Pomocí hlavolamu „Patnáctka“ vám vysvětlím, jak vyzrát v JavaScriptu na dvourozměrná pole. Současně si procvičíte přístup k vlastnostem formulářových prvků, konkrétně tlačítek. Věřím, že studium příkladu vás nejen poučí, ale i pobaví.

JavaScript zná pouze jednorozměrná pole. Vícerozměrná pole lze poměrně snadno nahradit poli polí, nebo využitím tzv. asociativních polí. Existuje ale ještě jednodušší způsob – pomocí převodní funkce indexů (řádkový index r a sloupcový index s nahradíte jediným indexem x). Předtím než začnete používat jednotlivé prvky pole, musíte pole vytvořit. K tomu se používá přiřazovací příkaz, ve kterém je na levé straně název pole a na pravé straně klíčové slovo new, následované konstruktorem (konstrukční funkcí) Array v jednom ze tří následujících tvarů:

a = new Array();
b = new Array(n);
c = new Array(x1, x2, x3, …);

Pokud uvnitř závorek není uveden žádný argument, pole je vytvořeno, ale nemá určenou délku (vlatnost length je rovna nule). Je-li uveden jeden argument, musí jít o číslo, které udává délku pole (vlastnost length je rovna tomuto číslu). V příkladu jsem použil číslo 36, protože potřebuji pole s 36 prvky (indexovanými 0 až 35). Třetí možný tvar konstruktoru má dva a více argumentů, oddělených vzájemně čárkami. Každý argument představuje hodnotu jednoho prvku pole a může být libovolného typu (číslo, řetězec apod.). Prvky jsou číslovány 0, 1, 2, … Vlastnost length je rovna počtu argumentů konstruktoru.

Matice patnáctky

V našem příkladu budete potřebovat matici 6 x 6 polí. Žlutá pole odpovídají skutečným polím hlavolamu, zatímco oranžová pole jsou tu jen proto, aby každé žluté pole mělo čtyři sousední pole (směrem nahorů, dolů, vlevo a vpravo). Tato vlastnost umožňuje použití jednoduché procedury, která pro každé vnitřní (žluté) pole zjistí, zda je možné na něm položeným kamenem pohnout (zda je některé sousední pole volné).

ř 0
s 0
ř 0
s 1
ř 0
s 2
ř 0
s 3
ř 0
s 4
ř 0
s 5
ř 1
s 0
ř 1
s 1
ř 1
s 2
ř 1
s 3
ř 1
s 4
ř 1
s 5
ř 2
s 0
ř 2
s 1
ř 2
s 2
ř 2
s 3
ř 2
s 4
ř 2
s 5
ř 3
s 0
ř 3
s 1
ř 3
s 2
ř 3
s 3
ř 3
s 4
ř 3
s 5
ř 4
s 0
ř 4
s 1
ř 4
s 2
ř 4
s 3
ř 4
s 4
ř 4
s 5
ř 5
s 0
ř 5
s 1
ř 5
s 2
ř 5
s 3
ř 5
s 4
ř 5
s 5

Bez problémů tedy připravíte jednoduchou funkci dvou proměnných r a s (řádek a sloupec), která převede označení pole tabulky pomocí řádku a sloupce (dvourozměrné pole, resp. matice) na označení pomocí jediného indexu (běžné jednorozměrné pole). Vzhledem k tomu, že tabulka má 6 sloupců (očíslovaných 1 až 5), násobíte číslo řádku šesti (počtem sloupců) a přičtete číslo řádku (opět číslovaných od nuly). Označíte-li index proměnnou x, je hledaná funkce: x = 6*r + s a výsledné očíslování polí tabulky:

012345
67891011
121314151617
181920212223
242526272829
303132333435

Stále ovšem potřebujete pouze žlutá pole, oranžová jsou tu tak trochu navíc a v programu jim vůbec nebudete přiřazovat hodnotu. To ovšem nevadí! Pole v JavaScriptu jsou totiž řídká (anglicky sparse). Hodnotu tedy mohou mít přiřazeny pouze některé prvky pole, zbývajícím prvkům se nealokuje (nepřiděluje) paměť a jejich hodnota není definována.

Pole formuláře

V JavaScriptu se na straně klienta (tedy prohlížeče webových stránek) vyskytuje ještě jeden druh polí, který se nevytváří pomocí konstruktoru Array. Jsou to pole vázaná na prvky právě zobrazovaného HTML dokumentu (např. obrázky, hypertextové odkazy, formuláře a formulářové prvky).

K poli formulářů se přistupuje jako k vlastnosti aktuálního dokumentu (objektu „document“). Očíslování (indexace) začíná opět od nuly. Pokud je tedy formulář v HTML dokumentu jen jeden (a to je poměrně častý případ), budu na něj odkazovat jako na document.forms[0]. V rámci každého formuláře jsou formulářové prvky přístupné jako prvky pole „elements“ a jsou očíslovány od nuly. Přistupujete k nim jako k vlastnostem objektu, tedy prostřednictvím operátoru „tečka“: apod. Přes operátor „tečka“ můžete přistupovat i k vlastnostem konkrétního formulářového prvku. V příkladu využívám vlastnost value, která se u tlačítka projeví jako jeho popis. Šestnácti tlačítkům se přidělí čísla (jako popisy tlačítek) pomocí následující procedury:

function zobraz()
{
    for (i = 1; i <= 4; i++)
       { for (j = 1; j <= 4; j++)
          { document.forms[0].elements[4*(i-1) + j-1].value = a[6*i + j]; }}
}

Nastavení výchozích hodnot

Procedurou nazývám funkci JavaScriptu, která nevrací žádnou hodnotu (neobsahuje příkaz return). JavaScript totiž neodlišuje syntaxí funkci od procedury a obě uvádí klíčovým slovem function. Další procedura nastaví výchozí hodnoty tlačítek, které pro zpestření tvoří tzv. magický čtverec. To znamená, že součty čísel ve všech řadách, ve všech sloupcích a v obou úhlopříčkách jsou stejné. Všimněte si, že hodnoty jsou přiřazeny pouze 16 z celkově 36 prvků pole. Umožňují to řídká pole, o kterých jsem se už zmínil. Procedura „nastav“ na svém konci volá proceduru „zobraz“, aby se nastavení prvků pole viditelně projevilo.

function nastav()
{
    a[7] = ‚   12    ‚;    a[8] = ‚    1    ‚;    a[9] = ‚   10   ‚;    a[10] = ‚    7    ‚;
    a[13] = ‚    2    ‚;    a[14] = ‚   15    ‚;    a[15] = ‚    4    ‚;    a[16] = ‚    9    ‚;
    a[19] = ‚    5    ‚;    a[20] = ‚    8    ‚;    a[21] = ‚    3    ‚;    a[22] = ‚   14   ‚;
    a[25] = ‚   11   ‚;    a[26] = ‚    6    ‚;    a[27] = ‚   13   ‚;    a[28] = “;
    zobraz();
}

Když nastavíte počáteční hodnoty políček hlavolamu, můžete se pustit do jeho řešení. Opět připomínám, že hodnoty prvků pole pro některé hodnoty indexu nemají definovanou hodnotu. Přesto se na ně můžete odvolávat v proceduře, která se „rozhlédne“ čtyřmi směry okolo konkrétního tlačítka a pokud je některé políčko hlavolamu volné (má hodnotu prázdného řetězce), vymění si s ním místo. Pokud žádné sousední pole není volné, upozorní program řešitele hlášením alert.

function tah(r, s)       // r = řádek (1 až 4), s = sloupec (1 až 4)
{
    nelze = true;       // nelze-li provést tah, vypíše hlášení „alert“
    x = 6*r + s;
    if (a[x-1] == “) { a[x-1]=a[x]; a[x]=“; nelze=false; };      // pohled doleva
    if (a[x+1] == “) { a[x+1]=a[x]; a[x]=“; nelze=false; };      // pohled doprava
    if (a[x-6] == “) { a[x-6]=a[x]; a[x]=“; nelze=false; };      // pohled nahoru
    if (a[x+6] == “) { a[x+6]=a[x]; a[x]=“; nelze=false; };      // pohled dolů
    if (nelze) {alert(‚Tímto dílkem nelze táhnout! \nŽádné sousední pole není volné.‘); };
    zobraz();
}

Ve vlastním HTML kódu nemusíte tlačítka pojmenovávat (atribut NAME), ani určovat jejich popisky (atribut VALUE). Popisky zajistí procedura nastav(), kterou vložíte do HTML značky <BODY> jako hodnotu atributu – událostní procedury onLoad. U každého tlačítka <INPUT TYPE=“BUTTON“> však musíte vložit událostní ovladač onClick (kliknutí myší na tlačítko) a jako jeho hodnotu volání procedury tah(r, s), kde r je číslo řádku a s číslo sloupce, ve kterém je příslušné tlačítko. Formulář v HTML části stránky bude vypadat následovně (několik řádků je pro lepší čitelnost HTML kódu vynecháno):

<FORM>
    <TABLE BORDER=7 CELLSPACING=0 CELLPADDING=3 ALIGN=“CENTER“ BGCOLOR=“yellow“>
       <TR ALIGN=“Center“>
          <TD>  <BR><INPUT TYPE=“BUTTON“ onClick=“tah(1, 1);“>
          <TD>  <BR><INPUT TYPE=“BUTTON“ onClick=“tah(1, 2);“>
          <TD>  <BR><INPUT TYPE=“BUTTON“ onClick=“tah(1, 3);“>
          <TD>  <BR><INPUT TYPE=“BUTTON“ onClick=“tah(1, 4);“>
       <TR ALIGN=“Center“>
          <TD>  <BR><INPUT TYPE=“BUTTON“ onClick=“tah(2, 1);“>
          <TD>  <BR><INPUT TYPE=“BUTTON“ onClick=“tah(2, 2);“>
          …
          <TD>  <BR><INPUT TYPE=“BUTTON“ onClick=“tah(4, 4);“>
    </TABLE><BR><BR>
    <TABLE ALIGN=“CENTER“ BORDER=0>
       <TR> <TD> <INPUT TYPE=“BUTTON“ VALUE=“ Obnovit “ onClick=“nastav();“>
       <TD> <INPUT TYPE=“BUTTON“ VALUE=“14 <–> 15″ onClick=“vymen();“>
    </TABLE>
    <BR><BR><BR>
</FORM>

A na závěr nezbývá než ukázat hotový hlavolam „15“ a popřát vám příjemnou zábavu při jeho řešení, programování, či studiu zdrojového kódu a případném vylepšování základního schématu. Všimněte si tlačítka 14 <–>15, které je nutné pro úplné dořešení hlavolamu. Vašim cílem je pochopitelně seřadit čísla v přirozeném pořadí od 1 do 15. Proč by se vám to bez uvedeného tlačítka nepodařilo, je na delší povídání o tzv. lichých a sudých permutacích. Na to, jako toto tlačítko naoprogramovat zkuste přijít sami, nebo si počkejte na příště.

3 Příspěvků v diskuzi

  1. Dobrý den,

    zarazila mě věta „Všimněte si tlačítka 14 15, které je nutné pro úplné dořešení hlavolamu“. Kdysi jsem totiž přesně tuto hru měl doma v reálné podobě s destičkami a žádné tlačítko na výměnu čísel u něj nebylo a vždy šlo dořešit ať už uspořádání po řádcích, sloupcích či do kruhu. Ano, stalo se mi že jsem skončil tak, kdy bych vážně to přehození potřeboval, to se pak musí rozhodit pár již poskládaných čísel, ale vždy to dořešit lze.
    Jinak děkuji za pěkný článek, dal mi podnět k tomu, abych si sám napsal tuhle hru v javascriptu. Použil jsem ale 16 prvků pole a nepracoval jsem s formulářem, tudíž i obsah funkcí byl řešený odlišně, v podstatě je ale princip stejný.
    Prosím o osvětlení co jsou sudé a liché permutace a proč by se to nedalo bez toho tlačítka vyřešit.

  2. Hned po zaslání komentáře jsem si všiml data vytvoření článku – 30. 12. 2001, tudíž jsem zvědavý jestli mi vůbec někdo odpoví :-D.

  3. no já jsem na tenhle článek narazil když jsem hledal deklaraci dvourozměrného pole v javascriptu pomocí googlu a docela mi to pomohlo.

    V podstatě v dnešní době s využitím html5 a css3 se dají i programovat jednoduché hry v javascriptu :D

Odpovědět