Online piškvorky v PHP s MySQL 2.

28. května 2003

V druhom pokračovaní online piškvoriek si prezrieme funkcie, ktoré sme si predstavili v predchádzajúcom článku – funkciu na spracovanie vstupov, funkciu na zobrazenie hracieho poľa a funkciu na zistenie víťaza hry. Nájdete tu aj zdrojové kódy skriptu.

function Action(&$row, &$s, &$master, &$slave)

V úvode funkcie si pretransformujeme pole $_GET na premenné a prekonvertujeme $pid na číselnú hodnotu:

if (isset($_GET)){
reset ($_GET);
while (list ($key, $val) = each ($_GET))
        $$key = $val;
}
$pid *= 1;

Ďalej sa pustíme do postupného spracovania týchto premenných. Každá podmienka bude ukončená príkazom return True alebo False, podľa toho, či budeme zobrazovať sekciu hry, alebo nie, preto je dôležité zachovať poradie jednotlivých podmienok vo funkcii Action tak, ako si teraz ukážeme. Najskôr vytvorenie novej hry:

if ($m==“create“){
    // osetri maximalny pocet hier
    $p = mysql_fetch_array ( mysql_query („SELECT count(*) FROM piskvorky“) );
    if ($p[0] >= MAXGAME){
        $s .= „Prekročený maximálny počet vytvorených hier. Počkajte prosím, kým sa niektorá z hier ukončí.“;
        return False;
        }
    // zaloz novu hru (zaznam),
    // do db zapisujem: cas vytvorenia, master session, znacku „*“ pre prave vytvorenu hru
    mysql_query („INSERT INTO piskvorky (begin, master_sess, last) VALUES (UNIX_TIMESTAMP(NOW()), ‚“.session_id ().“‚, ‚*‘)“);
    // zisti „pid“ tejto hry
    // mysql_insert_id vrati ID (AUTO_INCREMENT stlpec) posledneho INSERT prikazu
    $row->pid = mysql_insert_id ();
    $master = True;
    // zobraz sekciu hry
    return True;
    } // vytvorenie hry

Hra bude vytvorená len ak nebol prekročený počet MAXGAME – počet záznamov v tabuľke „piskvorky“. Inak zobrazíme správu o tom, že hra nebola vytvorená a vyskočíme z funkcie s návratovou hodnotou False. Metaelement v tomto prípade zabezpečí návrat na úvodnú stránku. Nastavenie premennej $master na True je potrebný z dôvodu volania funkcie pre zobrazenie hry, aby sa zobrazovali obrázky pre hráča MASTER. Funkciu opustíme príkazom return s hodnotou True, čo znamená, že sa bude zobrazovať sekcia hry. V prípade, že sa nevytvára nová hra, ale premenná pid (ID hry) nie je definovaná zobrazíme úvodnú obrazovku:

if (!$pid){
    $s .= „ONLINE PIŠKVORKY“;
    // vymaz stare hry
    mysql_query („DELETE FROM piskvorky WHERE begin < (UNIX_TIMESTAMP(NOW())-„.TIMEOUT.“)“);
    // vypis vytvorenych hier
    $s .= „Vytvorené hry:<br/>“;
    // najnovsie hry navrchu
    $result = mysql_query („SELECT * FROM piskvorky WHERE last=’*‘ ORDER BY begin DESC“);
    while ($row = mysql_fetch_object ($result)) {
        // nacitaj odkaz z chatu
        $row->chat = substr ($row->chat, 0, strpos ($row->chat, „<br/>“));
        // odkaz na hru
        $s .= „<a href=’index.php?pid=$row->pid&amp;m=connect’>Hraj hru č. $row->pid založenú „.date(„j.n.Y G:i:s“, row->begin).“</a>“;
        // zobraz k odkazu spravu z chatu (napr. nejaka vyzva pre pripajajucich sa…)
        if ($row->chat)
            $s .= “ – <span class=’info’>$row->chat</span>“;
        $s .= „<br/>“;
        }
    // vypis aktivnych hier (obsadene hry)
    $s .= „<hr/>Aktívne hry:<br/>“;
    $result = mysql_query („SELECT * FROM piskvorky WHERE last!=’*‘ ORDER BY begin DESC“);
    while ($row = mysql_fetch_object ($result)) {
        $s .= „Hra č. $row->pid založená „.date(„j.n.Y G:i:s“, $row->begin).“ je aktívna.<br/>“;
        }
    // odkaz pre vytvorenie hry
    $s .= „<hr/><a href=’index.php?m=create’>Vytvor hru</a>“;
    // nezobraz sekciu hry
    return False;
    } // uvodna obrazovka

O čo sa stará úvodná stránka:

  • vymazanie starých hier
  • odkaz (href='index.php?pid=$row->pid&amp;m=connect) na vytvorené hry (last='*') plus prvý odkaz z MAXMSG správ – napr. nejaká výzva pre pripájajúcich sa
  • zobrazenie aktívnych hier (last!='*')
  • odkaz na vytvorenie novej hry (href='index.php?m=create')

Ak pid nebude prázdne, načítame z tabuľky tento záznam. Ak záznam neexistuje, hra bola vymazaná a zobrazíme o tom správu:

// nacitaj zaznam o hre
$result = mysql_query („SELECT * FROM piskvorky WHERE pid=’$pid'“);
// hra bola vymazana
if (!mysql_num_rows ($result)){
    $s .= „Hra bola vymazaná<br/><a href=’index.php’>Hraj znova !</a><br/>“;
    // nezobraz sekciu hry
    return False;
    }
// hra existuje
$row = mysql_fetch_object ($result);

Odteraz máme vo vlastnostiach objektu $row k dispozícii hodnoty položiek hry $pid. Nasledujúca časť kódu zabezpečí pripojenie hráča na už vytvorenú hru a ošetruje pripojenie viacerých hráčov na tú istú hru. Takýto prípad môže nastať ak by v približne rovnakom čase klikli viacerí SLAVE hráči na odkaz vytvorenej hry, ktorý by sa nestihol refreshnut a zaradiť medzi aktívne hry (teda, že by to už nebol odkaz). Hráč bude ku hre pripojený vtedy, ak bude prázdna položka slave_sess, kam zapíšeme session ID SLAVE hráča:

// niekto sa pripaja na hru
if($m==“connect“){
    // vytvor SLAVE hraca
    if (!$row->slave_sess){
        mysql_query („UPDATE piskvorky SET slave_sess='“.session_id ().“‚, last=’m‘ WHERE pid=’$pid'“);
        // zobraz sekciu hry
        return True;
        }
    // SLAVE hrac uz existuje
    else {
        $s .=“Ľutujem, niekto sa na hru pripojil skôr.<br/>“;
        // nezobraz sekciu hry
        return False;
        }
    } // $m=connect

Dostávame sa k časti funkcie Action, v ktorej už máme istotu, že pripojený ku hre je niekto z aktívnych hráčov (SLAVE, alebo MASTER). Určíme si kto je kto:

// som MASTER ?
$master = ($row->master_sess == session_id ());
// som SLAVE ?
$slave = ($row->slave_sess == session_id ());
// formatuj suradnice, ak existuju
$coo = ($x!=““ && $y!=““) ? sprintf (FORMAT, $x, $y) : False;

Tiež naplníme $coo formátovanou hodnotou súradníc, ak boli nejaké zadané (pri kliknutí na nejakú bunku hracieho poľa). Môže sa však stať, že niekto by do URL zadal ručne hodnotu existujúcej hry, čo musíme ošetriť, ak nechceme mať v hre divákov (naviac by to spôsobovalo chyby pri vyhodnocovaní víťaza):

// ani MASTER ani SLAVE
if(!$master && !$slave){
    $s .= „Nepovolený vstup do hry č. $row->pid !“;
    return False;
    }

Zápis posledných MAXMSG správičiek z chatu do databázy urobíme v týchto krokoch:

// chat
if($txt){ // zadana sprava
    // osetrenie vstupu a pridanie novej spravy (s IP adresou hraca)
    $row->chat .= „[„.$REMOTE_ADDR.“] – „.stripslashes( strtr ( sprintf („%.80s“,$txt), „<>&“,“***“) );
    // uloz spravy ako prvky pola
    $row->chat = explode („<br/>“, $row->chat);
    // vyber len poslednych MAXMSG sprav
    // zaporna hodnota parametra „offset“ pre array_slice vybere pocet „offset“ prvkov od konca pola
    $row->chat = array_slice ($row->chat, -MAXMSG);
    // zlep prvky pola
    $row->chat = implode („<br/>“, $row->chat);
    // a uloz ich do db
    mysql_query („UPDATE piskvorky SET chat=’$row->chat<br/>‘ WHERE pid=’$pid'“);
    // zobraz sekciu hry
    return True;
    }

V prvej časti článku sme si povedali, že hru budeme označovať na vymazanie, ak sa hráčovi zobrazí vyhodnotenie. Teraz môžeme skontrolovať túto položku a hru vymazať:

// zmaze ukoncenu hru (znacka „d“)
if($row->last == „d“){
    mysql_query („DELETE FROM piskvorky WHERE last=’d‘ AND pid=’$pid'“);
    // zobraz sekciu hry
    return True;
    }

Nakoniec nám ostáva zapísať súradnice bunky príslušného hráča, najskôr MASTER:

if ($master && $coo){
    // naposledy tahal (alebo vytvoril hru) MASTER – na rade je druhy hrac
    if($row->last==“m“ || $row->last==“*“){
        $s .= „Na rade je druhý hráč SLAVE<br/>“;
        // zobraz sekciu hry
        return True;
        }
    // kontrola buniek
    if ( strstr($row->slave, $coo) ){
        $s .= „Obsadené políčko hráčom SLAVE<br/>“;
        // zobraz sekciu hry
        return True;
        }
    // zapis MASTER suradnice do db
    $row->master .= $coo;
    mysql_query („UPDATE piskvorky SET master=’$row->master‘, last=’m‘ WHERE pid=’$pid'“);
    // zobraz sekciu hry
    return True;
    } // $master && $coo

Podmienka if ($master && $coo) bude pravdivá, len ak je hráč MASTER a máme nastavené súradnice – inak povedané, hráč MASTER klikol na bunku hracieho poľa. Ďalšími podmienkami ošetríme udalosti:

  • na ťahu je druhý hráč (zistíme podľa položky last – „*“ určuje práve vytvorenú hru, teda prvý na ťahu bude vždy hráč, ktorý sa na hru pripája = SLAVE)
  • políčka obsadené druhým hráčom (prehľadanie súradníc protihráča SLAVE)

Ak nebudú tieto podmienky pravdivé zapíšeme súradnice do databázy a položku last nastavíme na „m“ – posledný na ťahu bol MASTER. Rovnaký postup použijeme aj pre hráča SLAVE, okrem kontroly last="*", pretože tento hráč má právo ťahať prvý.

if ($slave && $coo){
    // naposledy tahal SLAVE – na rade je druhy hrac
    if ($row->last==“s“){
        $s .=“Na rade je druhý hráč MASTER<br/>“;
        // zobraz sekciu hry
        return True;
        }
    // kontrola buniek
    if ( strstr($row->master, $coo) ){
        $s .=“Obsadené políčko hráčom MASTER<br/>“;
        // zobraz sekciu hry
        return True;
        }
    // zapis SLAVE suradnice do db
    $row->slave .= $coo;
    mysql_query („UPDATE piskvorky SET slave=’$row->slave‘, last=’s‘ WHERE pid=’$pid'“);
    // zobraz sekciu hry
    return True;
    } // $slave && $coo

Dostávame sa k ukončeniu funkcie Action. Ak nenastala ani jedna zo spomínaných podmienok, znamená to, že je potrebný len refresh stránky, respektíve refresh sekcie hry, pretože si môžeme byť istý, že hráč je MASTER, alebo SLAVE, teda už sa nachádzame v sekcii hry. Ukončenie funkcie Action:

// zobraz sekciu hry – iba refresh – ziadna udalost
return True;

function Area (&$s, $row, $master, $slave)

Area napĺňa premennú $s HTML kódom, ktorý zabezpečí zobrazenie hracieho poľa. Dáta pre hracie pole si uložíme do dvojrozmerného poľa $matrix:

// dvojrozmerne pole $matrix naplnime hodnotami: „x“=SLAVE bunka, „o“=MASTER bunka, „*“=prazdna bunka
for ($y=0 ; $y<AREA; $y++){
    for($x=0 ; $x<AREA; $x++){
        $coo = sprintf (FORMAT, $x, $y);
        if ( strstr($row->master, $coo) )
            $matrix[$y][$x] = „x“;
        else if ( strstr($row->slave, $coo) )
            $matrix[$y][$x] = „o“;
        else
            $matrix[$y][$x] = „*“;
        }
    }

V ďalšom kroku zavoláme funkciu WinTest s parametrom $matrix (predaným odkazom), ktorá vyhodnotí víťaza hry a vráti 0 (ak nie je víťaz), 1 (ak je víťaz MASTER), 2 (víťaz je SLAVE) alebo 3 (ak nastala remíza – obsadené všetky bunky, ale niet víťaza). Na základe tejto návratovej hodnoty zobrazíme odpovedajúcim hráčom výsledok hry:

// funkcia na zistenie vitaza: 0=neni, 1=MASTER, 2=SLAVE, 3=remiza
// taktiez oznaci vitazny tah

$win = WinTest ($matrix);
// zobraz info o vitazstve, prehre..
if (($win == 1 && $master) || ($win == 2 && $slave))
    $s .= „<b>Gratulujem, si víťaz !</b><br/>“;
else if (($win == 1 && $slave) || ($win == 2 && $master))
    $s .= „<b>Ľutujem, prehral si !</b><br/>“;
else if ($win == 3)
    $s .= „<b>Remíza.</b><br/>“;

Hracie pole bude vytvorené elementom table a bunky tabuľky budú reprezentovať bunky hracieho poľa. Kliknúť na bunku sa bude dať len vtedy, ak hra ešte neskončila ($win==0) a bunka je prázdna ($matrix[$y][$x] == "*"). Tam, kde sa bude dať kliknúť, budeme zobrazovať odkaz s pid hry a súradnicami bunky (href='index.php?pid=$row->pid&amp;x=$x&amp;y=$y'). Odkaz je obohatený o udalosti onmouseover a onmouseout, pomocou ktorých zobrazujeme na prázdnych bunkách pri prechode kurzora príslušné obrázky. Ďalej v cykle cez príkaz „switch“ priradíme bunkám obrázky:

// generuje hracie pole
$s .= „<table cellspacing=’0′ cellpadding=’1′ border=’0’>“;
for ($y=0 ; $y<AREA ; $y++){
    $s .= „<tr>“;
    for($x=0 ; $x<AREA ; $x++){
        // odkaz pridavaj len ak sa este hra
        if ( !$win && $matrix[$y][$x] == „*“){
          $over = $master ? „x3.gif“ : „o3.gif“;
          $a_start = „<a href=’index.php?pid=$row->pid&amp;x=$x&amp;y=$y‘
            onmouseover = ‚document.images.x$x“.“y$y.src=\“$over\“‚
            onmouseout = ‚document.images.x$x“.“y$y.src=\“blank.gif\“‚>“;
          $a_end = „</a>“;
          }
        else {
            $a_start = $a_end = „“;
            }
        // podla znacky zobraz obrazok
        switch ($matrix[$y][$x]){
            case „x“:
                $src = „x.gif“;
                break;
            case „[x]“:
                $src = „x2.gif“;
                break;
            case „o“:
                $src = „o.gif“;
                break;
            case „[o]“:
                $src = „o2.gif“;
                break;
            default:
                $src = „blank“;
                break;
            }
        $s .= „<td width=’39‘ height=’39’>$a_start<img src=’$src‘ width=’39‘ height=’39‘ border=’0′ name=’x$x“.“y$y‘ />$a_end</td>“;
        }
    $s .= „</tr>“;
    }
$s .= „</table>“;

Na záver zobrazíme správy chatu a, ak sa ešte hrá, aj formulár na vpisovanie správ s focusom na tento prvok:

// chat text
$s .= „<hr/>$row->chat“;
// ak sa este hrá zobraz formular na chat a nasmeruj nan kurzor
if ( !$win ){
    $s .= „<form action=’index.php‘ method=’get‘ name=’f’><input type=’hidden‘ name=’pid‘ value=’$row->pid‘ /><input type=’text‘ name=’txt‘ size=’40‘ />&nbsp;<input type=’submit‘ value=’Odošli správičku‘ /></form>“;
    $s .= „<script type=’text/javascript’>document.f.txt.focus ()</script>“;
    }
return $win;

function WinTest (&$matrix)

Funkcia WinTest kontroluje dvojrozmerné pole $matrix a vráti víťaza – 0 (neni), 1 (MASTER), 2 (SLAVE) alebo 3 (remíza). Naviac nám toto pole doplní ($matrix je volaný odkazom) o víťazný ťah tak, že hodnoty víťazných prvkov uzavrie do hranatých zátvoriek. Takto budeme pri vykresľovaní vedieť, do ktorých buniek vkladať obrázok pre víťazný ťah. Víťazný ťah kontrolujeme vo štyroch smeroch – horizontálny, vertikálny a dve diagonály. Kontrola každého smeru je urobená cez cykly, ukážeme si len horizontálny smer:

for ($y=0 ; $y<AREA; $y++){
    $win[0]=$win[1]=0;
    for($x=0 ; $x<AREA ; $x++){
        if ($matrix[$y][$x] == „x“){
            $win[0]++;
            $win[1]=0;
            }
        else if ($matrix[$y][$x] == „o“){
            $win[1]++;
            $win[0]=0;
            }
        else
            $win[0]=$win[1]=0;
        if ($win[0] == WINNER){
            for($x=0 ; $x<AREA; $x++)
                $matrix[$y][$x] = ($matrix[$y][$x]==“x“) ? „[x]“ : $matrix[$y][$x];
            return 1;
            }
        if ($win[1] == WINNER){
            for($x=0 ; $x<AREA; $x++)
                $matrix[$y][$x] = ($matrix[$y][$x]==“o“) ? „[o]“ : $matrix[$y][$x];
            return 2;
            }
        }
    }

Premenná $win[0] určuje počet buniek hráča MASTER idúcich za sebou, $win[1] to isté pre hráča SLAVE. Ak bude tento počet zhodný s počtom WINNER, označíme víťazný ťah (hranaté zátvorky) a príkazom return vrátime hodnotu pre daného víťaza. Ak viete o lepšom algoritme na kontrolu víťazného ťahu, neváhajte mi napísať.

Dúfam, že skript sa vám páčil. Samotná hra nie je asi veľmi zábavná, ale ako ukážka vytvorenia online hry v PHP to myslím postačí, naviac zopakujem, že sme použili len jednu databázovú tabuľku a session využívame len na identifikáciu užívateľa. Opäť uvádzam odkaz na ukážku (AREA=5, WINNER=4) a dnes aj na samotný skript.

Starší komentáře ke článku

Pokud máte zájem o starší komentáře k tomuto článku, naleznete je zde.

Štítky: Články

Mohlo by vás také zajímat

Nejnovější

1 komentář

  1. MEN-X

    Říj 13, 2009 v 22:36

    Složitěji by to snad ani nešlo. Sry tohle neni tutorial, ale návod jak co nejvíce skrátit kód..

    Odpovědět

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *