Perhitungan Rasio Negara UEFA

gambar

Ada dua turnamen populer dalam sepakbola: Liga Champions dan Liga Eropa. Berdasarkan hasil mereka, yang disebut Rating Asosiasi Sepakbola dihitung. Berdasarkan peringkat ini, selanjutnya ditentukan berapa banyak tim dari masing-masing negara akan berpartisipasi dalam turnamen berikutnya.

Pada artikel ini, saya akan membuat aplikasi berdasarkan platform lsFusion terbuka dan gratis yang akan menghitung peringkat ini. Ini akan menyimpan semua datanya dalam PostgreSQL, menyediakan antarmuka web untuk mengubah dan menampilkannya dengan kemampuan penyaringan dan pengurutan, serta mengimpor hasil pertandingan menggunakan API khusus.

Semua kode untuk mengimplementasikan aplikasi ini akan terdiri dari sekitar 300 baris signifikan.

Logika domain


Pembuatan sistem informasi apa pun dimulai dengan tugas logika domain.
Pertama-tama, adalah logis untuk memilih direktori paling sederhana yang hanya memiliki kode dan nama:

  • Turnamen Liga Champions atau Liga Eropa.
  • Musim 2018-2019 / 2017-2018 dll.
  • Bulat . Final, Semifinal, Babak Grup, dll. Ini dapat dianggap sebagai komposisi untuk turnamen, tetapi dalam implementasi ini saya memilihnya sebagai entitas yang terpisah.
  • Negara Aplikasi ini digunakan sebagai Asosiasi Sepak Bola. Misalnya, klub Monako terletak di negara Monako, tetapi bermain di kejuaraan Prancis.
  • Klub Barcelona, ​​Real Madrid, Manchester United, dll.

Karena lsFusion menggunakan tipe logika yang sama untuk mendeklarasikannya, kami akan mendeklarasikan metacode (atau templat kode) yang akan menghasilkan logika yang sesuai:

Direktori Deklarasi Direktori
META defineMasterObject(object, caption, captions, nameLength)
CLASS ### object caption;

id '' = DATA INTEGER ( ### object);
object ( INTEGER id) = GROUP AGGR ### object o BY id(o); //

name '' = DATA ISTRING ( ### object) CHARWIDTH nameLength;
object ( ISTRING name) = GROUP AGGR ### object o BY name(o); //

FORM object caption
OBJECTS o = ### object PANEL
PROPERTIES (o) id, name

EDIT ### object OBJECT o
;

FORM object ## s captions
OBJECTS o = ### object
PROPERTIES (o) READONLY id, name
PROPERTIES (o) NEWSESSION NEW , EDIT , DELETE
;

FORM dialog ### object ## s captions
OBJECTS o = ### object
PROPERTIES (o) READONLY id, name

LIST ### object OBJECT o
;

NAVIGATOR {
NEW object ## s;
}
END


Dia akan mengumumkan:

  • Kelas dengan nama yang diberikan
  • Properti dengan kode dan nama untuk kelas baru
  • Tiga bentuk: mengedit objek, formulir dengan daftar semua objek, yang kemudian ditambahkan ke navigator, dialog untuk memilih objek ini. Sebagai dialog, Anda bisa menggunakan formulir kedua, tetapi kemudian pengguna akan memiliki kesempatan untuk mengubah objek saat memilih, yang dapat menyebabkan kesalahan pada bagian pengguna.

Empat parameter dilewatkan ke metacode:

  • Identifier (objek) . Dengan nama ini, kelas dan formulir akan dibuat. Konstruk ### digunakan untuk membuat huruf pertama dari pengenal ditulis dalam kode yang dihasilkan.
  • Nama dalam bentuk tunggal . Digunakan untuk judul kelas dan formulir.
  • Namanya dalam bentuk jamak . Digunakan untuk kotak kombo dan dialog.
  • Panjang Nama . Dalam nama-nama objek yang berbeda, panjang yang berbeda diharapkan, yang penting ketika membangun antarmuka.

Menggunakan metacode yang dibuat, tambahkan lima entitas yang dijelaskan di atas:
@defineMasterObject (tournament, '' , '' , 20 );
@defineMasterObject (season, '' , '' , 5 );
@defineMasterObject (round, '' , '' , 15 );
@defineMasterObject (country, '' , '' , 10 );
@defineMasterObject (team, '' , '' , 20 );


Kode yang dihasilkan, misalnya, untuk turnamen akan terlihat seperti ini:
CLASS Tournament '' ;

id '' = DATA INTEGER (Tournament);
tournament ( INTEGER id) = GROUP AGGR Tournament o BY id(o);

name '' = DATA ISTRING (Tournament) CHARWIDTH 20 ;
tournament ( ISTRING name) = GROUP AGGR Tournament o BY name(o);

FORM tournament ''
OBJECTS o = Tournament PANEL
PROPERTIES (o) id, name

EDIT Tournament OBJECT o
;

FORM tournaments ''
OBJECTS o = Tournament
PROPERTIES (o) READONLY id, name
PROPERTIES (o) NEWSESSION NEW , EDIT , DELETE
;

FORM dialogTournaments ''
OBJECTS o = Tournament
PROPERTIES (o) READONLY id, name

LIST Tournament OBJECT o
;

NAVIGATOR {
NEW tournaments;
}

Tambahkan tautan ke negara ke logika klub yang dibuat. Untuk melakukan ini, pertama-tama buat properti yang sesuai, yang kemudian menempatkannya pada bentuk pengeditan dan melihat klub:
country = DATA Country (Team);
nameCountry '' (Team t) = name(country(t));

EXTEND FORM team PROPERTIES (o) nameCountry;
EXTEND FORM teams PROPERTIES (o) READONLY nameCountry;

Kami menempatkan semua logika yang dibuat dalam modul Master terpisah (file Master.lsf).

Sekarang buat Liga entitas. Dia akan menentukan turnamen musim tertentu. Misalnya, Liga Champions 2017-18 atau Liga Eropa 2018-19. Liga tidak akan memiliki nama, tetapi hanya tautan ke turnamen dan musim. Oleh karena itu, kami tidak akan menggunakan metacode sebelumnya, tetapi kami akan melakukan logika yang sama dan memasukkannya ke modul Liga baru:
MODULE League;

REQUIRE Master;

CLASS League '' ;

id '' = DATA INTEGER (League);
league ( INTEGER id) = GROUP AGGR League o BY id(o);

tournament = DATA Tournament (League);
nameTournament '' (League l)= name(tournament(l));

season = DATA Season(League);
nameSeason '' (League l)= name(season(l));

FORM league ''
OBJECTS o = League PANEL
PROPERTIES (o) id, nameTournament, nameSeason

EDIT League OBJECT o
;

FORM leagues ''
OBJECTS o = League
PROPERTIES (o) READONLY id, nameTournament, nameSeason
PROPERTIES (o) NEWSESSION NEW , EDIT , DELETE
;

FORM dialogLeagues ''
OBJECTS o = League
PROPERTIES (o) READONLY id, nameTournament, nameSeason

LIST League OBJECT o
;

NAVIGATOR {
NEW leagues;
}

Dan akhirnya, tambahkan logika pertandingan. Untuk melakukan ini, buat Pertandingan kelas, yang akan merujuk ke liga dan babak. Baginya, klub-klub yang berpartisipasi di dalamnya, dan hasilnya juga akan ditanyakan. Kami menempatkan semua ini dalam modul Match yang terpisah:
MODULE Match;

REQUIRE League;

CLASS Match '' ;

id '' = DATA INTEGER (Match);
match ( INTEGER id) = GROUP AGGR Match o BY id(o);

dateTime '' = DATA DATETIME (Match);

league = DATA League (Match);

tournament (Match m) = tournament(league(m));
nameTournament '' (Match m) = name(tournament(m));

season(Match m) = season(league(m));
nameSeason '' (Match m) = name(season(m));

round = DATA Round (Match);
nameRound '' (Match m) = name(round(m));

homeTeam = DATA Team (Match);
nameHomeTeam '' (Match m) = name(homeTeam(m));

awayTeam = DATA Team (Match);
nameAwayTeam '' (Match m) = name(awayTeam(m));

goalsHome ' ()' = DATA INTEGER (Match);
goalsAway ' ()' = DATA INTEGER (Match);

FORM match ''
OBJECTS o = Match PANEL
PROPERTIES (o) id, dateTime, nameTournament, nameSeason, nameRound,
nameHomeTeam, goalsHome, goalsAway, nameAwayTeam

EDIT Match OBJECT o
;

FORM matches ''
OBJECTS o = Match
PROPERTIES (o) READONLY id, dateTime, nameTournament, nameSeason, nameRound,
nameHomeTeam, goalsHome, goalsAway, nameAwayTeam
PROPERTIES (o) NEWSESSION NEW , EDIT , DELETE

LIST Match OBJECT o
;

NAVIGATOR {
NEW matches;
}


Impor data


Sayangnya, saya berhasil menemukan hanya satu API publik dan gratis yang mendukung semua Eurocups. Ini adalah API Sepak Bola . Namun, ada masalah:

  • Tidak ada hasil hingga 2016.
  • Tidak ada kualifikasi untuk Liga Europa hingga 2018.
  • Ada kesalahan tertentu dalam data. Misalnya, Irtysh Pavlodar ditugaskan ke Rusia, meskipun klub ini mewakili Kazakhstan. Juga, Europa Fc karena alasan tertentu merujuk ke Spanyol, bukan Gibraltar.


Kesalahan data dapat diperbaiki secara manual menggunakan formulir yang dibuat sebelumnya. Namun, karena perhitungan koefisien total didasarkan pada lima tahun terakhir, sayangnya, itu tidak akan berfungsi untuk menghitung koefisien total dari data Football API. Jika seseorang di komentar menyarankan di mana mendapatkan data yang diperlukan dalam format apa pun dari tahun-tahun sebelumnya, saya akan sangat berterima kasih. Tetapi, karena ada data lengkap untuk 2018, akan mungkin untuk memverifikasi kebenaran perhitungan untuk setidaknya tahun ini.

API yang kami butuhkan diimplementasikan dalam bentuk permintaan HTTP, di mana parameter dikirimkan melalui url, dan kunci akses khusus ditunjukkan di header. Nyatakan logika yang sesuai:
host = 'api-football-v1.p.rapidapi.com' ;
key ' API Football' = DATA STRING () CHARWIDTH 50 ;

url = 'https://' + host() + '/v2' ;

headers( TEXT name) = CASE
WHEN name = 'x-rapidapi-host' THEN host()
WHEN name = 'x-rapidapi-key' THEN key();

Semua tindakan impor data akan ditempatkan pada formulir liga yang dibuat sebelumnya. Di sana kita akan menempatkan kunci akses di bilah alat tabel dengan daftar liga:
EXTEND FORM leagues
PROPERTIES () key DRAW o TOOLBAR
;


Pertama, kami menerapkan daftar liga. Untuk ini, API Sepakbola memiliki url khusus: / liga. Permintaan GET untuk itu mengembalikan JSON dari formulir:

Jawabannya
 { "api":{ "results":2, "leagues":[ { "league_id":1, "name":"2018 Russia World Cup", "country":"World", "country_code":null, "season":2018, "season_start":"2018-06-14", "season_end":"2018-07-15", "logo":"https://www.api-football.com/public/leagues/1.png", "flag":null, "standings":0, "is_current":1 }, { "league_id":2, "name":"Premier League", "country":"England", "country_code":"GB", "season":2018, "season_start":"2018-08-10", "season_end":"2019-05-12", "logo":"https://www.api-football.com/public/leagues/2.png", "flag":"https://www.api-football.com/public/flags/gb.svg", "standings":1, "is_current":1 } ] } } 


Untuk menghasilkan permintaan GET dan mencatat badan respons, konstruksi berikut digunakan:
LOCAL result = FILE ();
EXTERNAL HTTP GET url() + '/leagues' HEADERS headers TO result;

Itu menulis hasilnya ke properti hasil lokal tanpa parameter tipe FILE.

Untuk mem-parsing file dalam format JSON, formulir dibuat yang strukturnya sesuai dengan struktur JSON. Anda dapat membuatnya di IDE menggunakan item menu:

gambar

Untuk JSON di atas, formulir akan terlihat seperti ini (dengan hanya memperhitungkan nilai-nilai yang akan diimpor):
GROUP api;

tournamentName = DATA LOCAL STRING ( INTEGER );
seasonName = DATA LOCAL STRING ( INTEGER );
leagueId = DATA LOCAL INTEGER ( INTEGER );

FORM importLeagues
OBJECTS leagues = INTEGER IN api
PROPERTIES (leagues) name = tournamentName, season = seasonName, league_id = leagueId
;

Untuk langsung mengimpor dari properti hasil JSON dalam format formulir importLeagues, gunakan perintah berikut:
IMPORT importLeagues JSON FROM result();

Setelah dieksekusi, nilai-nilai yang sesuai dari file JSON akan ditempatkan di turnamenName , musimName dan properti ligaId :

gambar

Artinya, nilai untuk turnamenName (0) akan menjadi "Piala Dunia", dan di turnamenName (1) itu akan menjadi "Liga Premier".

Sayangnya, API Football tidak memiliki entitas turnamen sama sekali. Satu-satunya cara untuk menghubungkan semua liga adalah memiliki nama yang cocok dengan liga-liga turnamen yang sama dari musim yang berbeda. Untuk melakukan ini, dalam impor, pertama-tama kita mengelompokkan semua nama liga yang diimpor dan, jika tidak dalam database, membuat turnamen baru:
FOR [ GROUP SUM 1 BY tournamentName( INTEGER i)]( STRING tn) AND NOT tournament(tn) DO NEW t = Tournament {
name(t) <- tn;
}

Juga tidak ada kode untuk musim, jadi ketika mengimpor liga, mereka dibuat dengan cara yang sama. Setelah objek yang hilang dibuat, liga diimpor secara langsung. Turnamen dan musim dicari berdasarkan nama menggunakan properti yang dibangun sebelumnya melalui GROUP AGGR :
FOR leagueId( INTEGER i) AND NOT league(leagueId(i)) DO NEW l = League {
id(l) <- leagueId(i);
tournament(l) <- tournament(tournamentName(i));
season(l) <- season(seasonName(i));
}

Secara default, data akan dimuat, tetapi hanya akan disimpan ke database ketika pengguna mengklik tombol Simpan di formulir. Jika perlu, Anda dapat menambahkan perintah BERLAKU di akhir tindakan sehingga segera disimpan ke database tanpa pratinjau.

Dan akhirnya, tambahkan aksi impor ke formulir daftar liga:
EXTEND FORM leagues
PROPERTIES () importLeagues DRAW o TOOLBAR
;

Demikian pula, kami mengimpor klub dan pertandingan. Namun, karena API menyediakan kemampuan untuk mengimpornya hanya untuk liga tertentu, tindakan tersebut harus menggunakan liga sebagai input:

Impor klub dan pertandingan
//
teamId = DATA LOCAL INTEGER ( INTEGER );
teamName = DATA LOCAL STRING ( INTEGER );
countryName = DATA LOCAL STRING ( INTEGER );

FORM importTeams
OBJECTS teams = INTEGER IN api
PROPERTIES (teams) team_id = teamId, name = teamName, country = countryName
;

importTeams ' ' (League l) {
LOCAL result = FILE ();
EXTERNAL HTTP GET url() + '/teams/league/' + id(l) HEADERS headers TO result;

IMPORT importTeams JSON FROM result();
FOR [ GROUP SUM 1 BY countryName( INTEGER i)]( STRING cn) AND NOT country(cn) DO NEW c = Country {
name(c) <- cn;
}

FOR teamId( INTEGER i) AND NOT team(teamId(i)) DO NEW t = Team {
id(t) <- teamId(i);
name(t) <- teamName(i);
country(t) <- country(countryName(i));
}
}

//

matchId = DATA LOCAL INTEGER ( INTEGER );
dateTime = DATA LOCAL STRING ( INTEGER );
roundName = DATA LOCAL STRING ( INTEGER );

GROUP homeTeam;
homeTeamId = DATA LOCAL INTEGER ( INTEGER );

GROUP awayTeam;
awayTeamId = DATA LOCAL INTEGER ( INTEGER );

goalsHome = DATA LOCAL INTEGER ( INTEGER );
goalsAway = DATA LOCAL INTEGER ( INTEGER );

FORM importMatches
OBJECTS fixtures = INTEGER IN api
PROPERTIES (fixtures) fixture_id = matchId, league_id = leagueId, event_date = dateTime, round = roundName,
homeTeamId IN homeTeam EXTID 'team_id' ,
awayTeamId IN awayTeam EXTID 'team_id' ,
goalsHomeTeam = goalsHome, goalsAwayTeam = goalsAway
;

importMatches ' ' (League l) {
LOCAL result = FILE ();
EXTERNAL HTTP GET url() + '/fixtures/league/' + id(l) HEADERS headers TO result;

IMPORT importMatches JSON FROM result();
FOR [ GROUP SUM 1 BY awayTeamId( INTEGER i)]( INTEGER id) AND NOT team(id) DO {
MESSAGE ' ' + id;
RETURN ;
}

FOR [ GROUP SUM 1 BY awayTeamId( INTEGER i)]( INTEGER id) AND NOT team(id) DO {
MESSAGE ' ' + id;
RETURN ;
}

FOR [ GROUP SUM 1 BY roundName( INTEGER i)]( STRING rn) AND NOT round(rn) DO NEW r = Round {
name(r) <- rn;
}

FOR matchId( INTEGER i) AND NOT match(matchId(i)) DO NEW m = Match {
id(m) <- matchId(i);
dateTime(m) <- toDateTimeFormat(left(dateTime(i), 19 ), 'yyyy-MM-ddThh24:mi:ss' );
league(m) <- league(leagueId(i));
round(m) <- round(roundName(i));
homeTeam(m) <- team(homeTeamId(i));
awayTeam(m) <- team(awayTeamId(i));
goalsHome(m) <- goalsHome(i);
goalsAway(m) <- goalsAway(i);
}
}

Ada kekhasan untuk pertandingan: kode tim masuk ke dalam tag homeTeam dan awayTeam tambahan. Grup yang sesuai dibuat untuk mereka dengan analogi dengan api. Selain itu, di dalamnya mereka memiliki tag team_id yang sama. Karena properti dengan nama yang sama tidak dapat ditambahkan ke formulir, kata kunci EXTID khusus digunakan , yang menentukan nama tag di JSON yang diimpor.

Agar semua impor berada pada formulir yang sama, dan karena mereka terkait dengan liga, kami membawanya semuanya ke bentuk yang sama. Selain itu, kami menambahkan tim dan pertandingan ke formulir agar dapat melihat apa yang diimpor sebelum menyimpan:
EXTEND FORM leagues
OBJECTS t = Team
PROPERTIES (t) READONLY id, name

PROPERTIES importTeams(o) DRAW t TOOLBAR

OBJECTS m = Match
PROPERTIES (m) READONLY id, dateTime, nameRound, nameHomeTeam, goalsHome, goalsAway, nameAwayTeam
FILTERS league(m) = o

PROPERTIES importMatches(o) DRAW m TOOLBAR
;

DESIGN leagues {
OBJECTS {
NEW leagueDetails {
fill = 2 ;
type = SPLITH ;
MOVE BOX (t);
MOVE BOX (m);
}
}
}


Bentuk yang dihasilkan akan terlihat seperti ini:
gambar

Semua impor akan dimasukkan ke dalam modul APIFootball terpisah.

Perhitungan koefisien


Kami melanjutkan langsung ke perhitungan koefisien negara UEFA. Adalah logis untuk meletakkan semua kode dalam modul UEFA yang dipasang khusus untuk ini.

Pertama, perlu diingat bahwa API Sepak Bola menyediakan antarmuka untuk mengimpor semua pertandingan, dan bukan hanya Eurocups. Oleh karena itu, kami memisahkan pertandingan Eurocup sesuai dengan nama turnamen (lebih tepat memiliki properti utama terpisah untuk ini, tetapi penerapan properti selalu dapat diubah tanpa mengubah sisa logika):
isCL (Tournament t) = name(t) = 'Champions League' ;
isEL (Tournament t) = name(t) = 'Europa League' ;

isUL (Tournament t) = isCL(t) OR isEL(t);
isUL (Match m) = isUL(tournament(m));

Pertama, mari kita hitung poin yang diterima setiap klub dalam satu musim untuk hasil pertandingan tertentu.
Selama periode ini, setiap tim menerima:
2 poin jika menang;
1 poin untuk dasi.
Sejak 1999, poin-poin ini dibagi menjadi dua jika diperoleh di babak kualifikasi, yaitu:
1 poin jika menang;
0,5 poin untuk seri.


Buat properti tambahan yang menentukan hubungan antara pertandingan dan klub:
played (Team t, Match m) = homeTeam(m) = t OR awayTeam(m) = t;
won (Team t, Match m) = (homeTeam(m) = t AND goalsHome(m) > goalsAway(m)) OR (awayTeam(m) = t AND goalsHome(m) < goalsAway(m));
draw (Team t, Match m) = played(t, m) AND goalsHome(m) = goalsAway(m);

Untuk menentukan berapa banyak poin yang dicetak di setiap pertandingan, kami menambahkan properti utama dari tipe numerik untuk putaran, yang secara default akan sama dengan satu:
dataMatchCoeff = DATA NUMERIC [ 10 , 1 ] (Round);
matchCoeff ' ' (Round r) = OVERRIDE dataMatchCoeff(r), 1.0 ;

Lalu kami menghitung poin untuk kemenangan dan hasil imbang dan menambahkan bersama-sama:
wonPoints ' ' (Season s, Team t) =
GROUP SUM 2 * matchCoeff(round(Match m)) IF won(t, m) AND season(m) = s AND isUL(m);
drawPoints ' ' (Season s, Team t) =
GROUP SUM 1 * matchCoeff(round(Match m)) IF draw(t, m) AND season(m) = s AND isUL(m);
matchPoints ' ' (Season s, Team t) = wonPoints(s, t) (+) drawPoints(s, t) MATERIALIZED ;

Poin untuk pertandingan ditandai sebagai MATERIALISASI sehingga disimpan dalam tabel, dan tidak dihitung setiap waktu.

Sekarang Anda perlu menghitung poin bonus:
Selain itu, poin bonus diberikan:
1 poin diberikan jika tim mencapai perempat final, semifinal dan final di piala Eropa;
4 poin untuk mencapai babak penyisihan grup Liga Champions (hingga 1996 - 2 poin, dari 1997 hingga 2003 - 1 poin, dari 2004 hingga 2008 - 3 poin);
5 poin dalam hal tim berangkat ke 1/8 final Liga Champions (sebelum 2008 - 1 poin).
Hanya pertandingan yang dimainkan yang diperhitungkan (kerugian teknis tidak diperhitungkan). Pertandingan yang berakhir dengan serangkaian adu penalti, ketika menghitung koefisien dianggap sesuai dengan hasil, yang ditetapkan oleh hasil pertandingan dalam waktu reguler dan tambahan.

Dalam implementasi ini, kami menganggap bahwa klub pergi ke putaran turnamen jika ia bermain setidaknya satu pertandingan di dalamnya. Untuk melakukan ini, kami menghitung berapa banyak pertandingan yang dimainkan klub di musim, turnamen, babak tertentu:
played '' (Season s, Tournament t, Round r, Team tm) =
GROUP SUM 1 IF played(tm, Match m) AND round(m) = r AND tournament(m) = t AND season(m) = s;


Sekarang Anda perlu menentukan berapa banyak poin untuk mencetak bagian dalam babak tertentu. Karena itu tergantung pada turnamen (misalnya, bagian di Liga Champions given diberikan 5 poin, tetapi tidak ada di Liga Eropa). Untuk melakukan ini, kami memperkenalkan properti utama:
bonusPoints ' ' = DATA NUMERIC [ 10 , 1 ] (Tournament, Round);

Sekarang mari kita menghitung poin bonus dan jumlah total poin untuk klub untuk musim ini:
bonusPoints ' ' (Season s, Team tm) = GROUP SUM bonusPoints(Tournament t, Round r) IF played(s, t, r, tm) MATERIALIZED ;

points '' (Season s, Team tm) = matchPoints(s, tm) (+) bonusPoints(s, tm);

Akhirnya, kita langsung menuju koefisien negara.
Untuk menghitung peringkat asosiasi, semua poin yang dicetak oleh klub yang berpartisipasi di Liga Champions dan Liga Eropa ditambahkan, dan hasilnya dibagi dengan jumlah klub dari asosiasi ini [2] [3].

Mari kita hitung jumlah klub untuk setiap asosiasi yang berpartisipasi dalam kompetisi Eropa:
matchesUL ' ' (Season s, Team t) = GROUP SUM 1 IF played(t, Match m) AND season(m) = s AND isUL(m);
teams '' (Season s, Country c) = GROUP SUM 1 IF matchesUL(s, Team t) AND country(t) = c;

Sekarang kami mempertimbangkan jumlah total poin asosiasi untuk musim ini dan dibagi dengan jumlah klub:
totalPoints ' ()' (Season s, Country c) = GROUP SUM points(s, Team t) IF country(t) = c;
points '' (Season s, Country c) = trunc( NUMERIC [ 13 , 4 ](totalPoints(s, c)) / teams(s, c), 3 );


Peringkat suatu negara adalah jumlah dari koefisien negara untuk 5 tahun sebelumnya.


Untuk melakukan ini, kami menomori semua musim mulai dari yang terakhir dengan kode internal (kami menganggap bahwa yang terakhir ditambahkan kemudian dan memiliki kode yang lebih besar):
index '' (Season s) = PARTITION SUM 1 IF s IS Season ORDER DESC s;

Jika perlu, Anda bisa memasukkan bidang atau nomor terpisah dengan nama.
Tetap hanya untuk menghitung peringkat akhir untuk negara:
rating '' (Country c) = GROUP SUM points(Season s, c) IF index(s) <= 5 ;

Di atas, kami mengumumkan peluang untuk turnamen dan putaran. Tambahkan mereka ke formulir pengeditan turnamen, sambil memfilter hanya putaran yang ada di turnamen ini:
matches (Tournament t, Round r) = GROUP SUM 1 IF tournament(Match m) = t AND round(m) = r;

EXTEND FORM tournament
OBJECTS r = Round
PROPERTIES name(r) READONLY , matchCoeff(r), bonusPoints(o, r)
FILTERS matches(o, r)
;


Pengaturan Odds, misalnya, untuk Liga Champions yang perlu Anda atur seperti ini:
gambar

Mari kita menggambar formulir yang akan menampilkan peringkat, di mana tim akan ditampilkan untuk setiap negara, dan untuk setiap tim pertandingannya:
FORM countryCoefficientUEFA ' UEFA'
OBJECTS s = Season
FILTERS index(s) <= 5

OBJECTS c = Country
PROPERTIES (c) READONLY name, rating
PROPERTIES (s, c) COLUMNS (s) points HEADER ' : ' + name(s), teams HEADER ' : ' + name(s)

OBJECTS t = Team
PROPERTIES (t) READONLY nameCountry, name
PROPERTIES (s,t) COLUMNS (s) HEADER name(s) points BACKGROUND matchesUL(s, t)
FILTERGROUP country
FILTER ' ' country(t) = c DEFAULT

OBJECTS m = Match
PROPERTIES (m) READONLY dateTime, nameTournament, nameSeason, nameRound,
nameHomeTeam,
goalsHome BACKGROUND goalsHome(m) > goalsAway(m),
goalsAway BACKGROUND goalsHome(m) < goalsAway(m),
nameAwayTeam
FILTERS played(t, m)
ORDER dateTime(m) DESC
;

DESIGN countryCoefficientUEFA {
OBJECTS {
NEW countryDetails {
type = SPLITH ;
fill = 0.5 ;
MOVE BOX (t);
MOVE BOX (m);
}
}

}

NAVIGATOR {
NEW countryCoefficientUEFA;
}

Bentuk yang dihasilkan akan terlihat seperti ini:
gambar
Warna di tabel klub menunjukkan ketika ia mengambil bagian dalam musim, dan dalam tabel pertandingan - siapa yang menang.
Gambar tersebut menunjukkan bahwa peringkat untuk tahun 2018 dihitung persis sama dengan di Wikipedia. Untuk tahun-tahun sebelumnya, seperti yang disebutkan di atas, API Sepak Bola tidak memberikan semua informasi.

Ringkasan



Kami membangun aplikasi kecil yang sepenuhnya dijelaskan oleh kode di atas dan menyimpan datanya di PostgreSQL, menyediakan antarmuka web untuk melihat dan mengedit data. Pada saat yang sama, ini akan bekerja secara efektif pada volume besar, karena semua formulir hanya membaca jendela yang terlihat. Juga di luar kotak adalah filter, pengurutan, pengunggahan ke Excel, dan banyak lagi.

Perlu dicatat betapa mudahnya menggunakan platform tugas menghitung koefisien diuraikan menjadi properti individu. Ketika dijalankan, semua logika ini akan diterjemahkan ke dalam query SQL, dan semua perhitungan akan dilakukan secara langsung pada server database menggunakan semua optimasi DBMS.

Contoh cara kerja aplikasi dengan data yang dimuat ke dalamnya dapat ditemukan di: https://demo.lsfusion.org/euroleague . Login tamu tanpa kata sandi. Pengguna dalam mode hanya baca.

Mereka yang ingin dapat mengatur sendiri semuanya secara lokal dan, misalnya, membuat model koefisien dengan memasukkan hasil pertandingan yang akan datang. Semua modul aplikasi yang dijelaskan di atas di-host di github . Setelah instalasi otomatis, Anda hanya perlu memunculkan file-file ini di folder yang sesuai dari instruksi dan restart server.

Untuk mengunduh data dari Football API, Anda harus mendaftar dan mendapatkan kunci API. Itu membutuhkan kartu, tetapi jika Anda membuat tidak lebih dari 50 permintaan per hari, maka tidak ada yang akan dikurangkan darinya.

Selain itu, Anda dapat menjalankan aplikasi ini secara online di bagian yang sesuai di situs. Pada tab Platform, pilih contoh Perhitungan Peluang UEFA dan klik Mainkan.

Ngomong-ngomong, jika seseorang perlu menerapkan beberapa sistem sederhana yang Excel tidak lagi cocok, maka tulis di komentar. Untuk mempelajari kemampuan platform, kami akan mencoba mengimplementasikannya dan menulis artikel terkait.

Source: https://habr.com/ru/post/id467279/


All Articles