Dnes dokončíme projekt, jehož obsahem bylo vytvořit uživatelsky přívětivou čtečku sportovních výsledků pro příkazový řádek.
6.6.2008 07:00 | Jiří Václavík | přečteno 14718×
Dnes máme za úkol dokončit práce na projektu. Chybí nám napsat poslední věc a tou je online přenos.
Načrtněme si opět předběžný postup.
Pojďme se do toho pustit. Bude třeba napsat tuto podmínku, kterou jsme nechali minule neimplementovanou.
if($online){
#implementace online přenosu
}
Předně musíme ze všech zápasů vybrat pouze jediný. K tomu si napíšeme zvlášť podprogram.
@vyhovujici = vyber_zapas(@vyhovujici);
To je v podstatě opakované volání metody najdi_zapas_podle_kriterii, která na základě kritérií postupně zužuje výběr. Jakmile klesne na jediný zápas, můžeme výběr ukončit a postupovat dále.
sub vyber_zapas {
my @vyhovujici = @_;
while(scalar @vyhovujici > 1){
print "Byly nalezeny zapasy (".scalar @vyhovujici."):\n";
tiskni_vyhovujici(@vyhovujici);
print "Musite zadat zpresnujici kriterium: ";
my $kriteria;
chomp($kriteria = <STDIN>);
my @kriteria = split(" ", $kriteria);
@vsechna_kriteria = (@vsechna_kriteria, @kriteria);
@vyhovujici = $live->najdi_zapas_podle_kriterii(\@vyhovujici, \@kriteria);
}
return @vyhovujici;
}
Je ovšem možné, že doplňující kritérium vyloučí všechny zápasy. V takovém případě musíme program ukončit, protože nemáme jak pokračovat. Jinou možností by bylo nebrat poslední kritérium v úvahu.
die "Zadny vyhovujici zapas\n" if scalar @vyhovujici == 0;
Nyní zjistíme ligu a číslo zápasu, které je třeba předat metodě prenos. Ale je třeba si dát pozor na tuto věc: Číslo zápasu a liga (parametry odkaz_idzapasu a odkaz_liga v hashi s informacemi o zápase) nemusí být vůbec dostupné - resp. nejsou dostupné, pokud zatím v zápase nedošlo ke sledované události. Nastává zde tedy problém. Jak můžeme získat data, když nevíme odkud? Tuto otázku nemá smysl řešit - tato data nezískáme, protože neexistují.
Vyřešíme to trochu jinak a to tak, že si počkáme, až budou dostupná. To znamená průběžně kontrolovat, zda nenastala událost a neobjevil se nám odkaz na seznam událostí. Jakmile událost nastane, získáme odkaz a budeme ji moci zobrazit. Bude to sice o něco náročnější na programování, ale v zásadě tím nic neztrácíme.
Periodicky tak budeme stahovat informace o zápasech. Vždy v nich najdeme ten náš zápas, který sledujeme. Ten nyní může být ve čtyřech stavech.
Je-li zápas před výkopem, budeme v intervalech zjišťovat, zda to stále platí, dokud se nezačne hrát. Když se začne hrát, nejsou zpravidla dostupné žádné události. Proto budeme v intervalech tisknout pouze probíhající minutu. Jakmile ale dojde k události, vyskočíme z cyklu, protože v tomto okamžiku budeme schopni stáhnout podrobnosti k zápasu - již známe odkaz (prvky odkaz_idzapasu a odkaz_liga). Pokud zápas skončil, ukončíme cyklus také. Pokud tyto požadavky zahrneme do další části programu, získáme toto.
Nejprve tedy zkusíme, zda již jsou detaily dostupné.
my $vyhovujici_liga = $vyhovujici[0]{"odkaz_liga"};
my $vyhovujici_idzapasu = $vyhovujici[0]{"odkaz_idzapasu"};
my $probihajici_minuta;
Pokud ne, budeme si na ně muset počkat. Periodicky budeme kontrolovat, zda již jsou dostupné.
while(!$vyhovujici_idzapasu){
@vyhovujici = $live->ziskej_zapasy_dane_ligy();
@vyhovujici = $live->najdi_zapas_podle_kriterii(\@vyhovujici, \@vsechna_kriteria);
$probihajici_minuta = $vyhovujici[0]{"minuta"}, "\n";
last if($vyhovujici[0]{"hraje_se"} == Livescore::UKONCEN);
if($vyhovujici[0]{"odkaz_idzapasu"}){
$vyhovujici_idzapasu = $vyhovujici[0]{"odkaz_idzapasu"};
$vyhovujici_liga = $vyhovujici[0]{"liga"};
}
if($vyhovujici[0]{"hraje_se"} == Livescore::PROBIHA){
print "Probiha $probihajici_minuta' \r";
}elsif($vyhovujici[0]{"hraje_se"} == Livescore::PRED_VYKOPEM){
print "Zapas zatim nezacal\r";
}
sleep $refresh;
}
K tomu, aby se nám neuchovávala data ve výstupním bufferu zatímco je v činnosti funkce sleep je třeba připsat na začátek skriptu tyto dva řádky. Vyprazdňování bufferu musí být automatické.
use IO::Handle;
STDOUT->autoflush(1);
Pokud skončil předchozí cyklus, znamená to, že buď zápas skončil nebo probíhá a jsou dostupné události. V obou případech vytiskneme dostupné události. Jestliže zápas probíhá, budeme navíc tisknout přibyvší události dokud zápas také neskončí.
do {
my @udalosti = $live->prenos($vyhovujici_liga, $vyhovujici_idzapasu);
$probihajici_minuta = shift @udalosti;
$hraje_se = shift @udalosti;
#vytiskneme nové události
print "Probiha $probihajici_minuta'\r";
sleep $refresh if $hraje_se == Livescore::PROBIHA;
}while($hraje_se == Livescore::PROBIHA);
Nyní projdeme všechny události a ty, které jsou nové zobrazíme. ID starých událostí budeme kopírovat do pole @zobrazene_udalosti, abychom měli přehled o tom, co již bylo zobrazeno.
for (@{$udalosti[0]}){
next if in_array($_->{"id_udalosti"}, \@zobrazene_udalosti);
#zobrazíme událost a zapíšeme do @zobrazene_udalosti
}
Nyní zbývají poslední dva kroky. Zvolíme vhodnou formu zobrazení a opět pomocí funkce colored vytiskneme. Máme 3 druhy události - gól, žlutá karta a červená karta. Na základě prvku udalost můžeme u všech událostí rozhodnout, o který případ jde. Poté aktualizujeme pole @zobrazene_udalosti.
if ($_->{"udalost"} eq "yellow"){
print colored(sprintf("%2s' %-20s (%s)\a\n", $_->{"minuta"},
$_->{"hrac"}, $_->{"tym"}), "bold yellow");
}elsif ($_->{"udalost"} eq "red" or $5 eq "yellow-red"){
print colored(sprintf("%2s' %-20s (%s)\a\n", $_->{"minuta"},
$_->{"hrac"}, $_->{"tym"}), "bold red");
}elsif ($_->{"udalost"} eq "goal"){
print colored(sprintf("%2s' ", $_->{"minuta"}), "bold white");
print colored(sprintf("%d:%d ", $_->{"skore1"}, $_->{"skore2"}),
"bold yellow");
print colored(sprintf("%-20s (%s)\a\n", $_->{"hrac"}, $_->{"tym"}),
"bold white");
}
push @zobrazene_udalosti, $_->{"id_udalosti"};
}
Za cyklus do-while se program dostane pouze v jediném případě - pokud skončil zápas. Tuto informaci tedy vytiskneme a na závěr zopakujeme aktualizovaný výsledek.
print "Zapas skoncil\n";
$live->ziskej_zapasy_dane_ligy;
tiskni_vyhovujici($live->najdi_zapas_podle_kriterii(\@vyhovujici, \@vsechna_kriteria));
exit;
Nyní jsme hotovi. Všechny požadavky ze zadání projektu jsme úspěšně dokončili. Kompletní program si můžete stáhnout (Livescore.pm, live) a vyzkoušet.
Výsledek zápasu *** Výsledek interaktivně vybraného zápasu *** Aktualizovaný probíhající online přenos
Samozřejmě by nyní tento program mohl být rozšířen o nové funkce. Například souběžné online přenosy více zápasů najednou, lepší členění pomocí přepínače -l a s tím související vylepšení cachování nebo přepis do Curses, Qt či jiného pokročilejšího uživatelského rozhraní.
Nicméně náš původní cíl je nyní splněn a proto tato šestidílná série, jejíž cílem bylo předvést některé techniky probrané v seriálu i z trochu jiného pohledu, dneškem končí.