ITV0110 2. töö 2017: javascript ja css

Allikas: Lambda
IT

Mida tuleb teha

Sinu ülesandeks on kirjutada minesweeperi mängu brauseris töötav tugevalt lihtsustatud eriversioon, kasutades ainult html-i, css-i ja javascripti.

Loe kõigepealt läbi ülevaade wikipediast ja mängi katseks seda varianti ja seda varianti.

Valmis töö tuleb riputada üles ülikooli serverisse dijkstra sinu kataloogi prax2 alla. Ehk, arvestatakse ainult dijkstra-s olevaid töid.

Selles praksis teed arvuti vastu mängimise variandi, aga kolmandas praktikumis tuleb samale mängule lisada serveripoolset funktsionaalsust, näiteks tulemuste salvestamine ja vaatamine ja statistika, pooliku mängu salvestamine ja hilisem jätkamine ja samuti mäng kahe inimese vahel, mis toimub siis serverirakenduse vahendusel.

Detailid

Sa pead realiseerima minesweeperi täpselt alltoodud nõuete järgi: teistmoodi funktsionaalsusega lahendused ei sobi!

Tehnoloogilises mõttes (a la kas kasutada jQueryt, bootstrappi, reacti jne jne) piiranguid ei ole, kuid algajatele on soovitus kõiki lisatööriistu vältida: need on esialgu keerulised ja kulutavad aega,

Nõuded siis:

Sinu programm peab algul mängijale pakkuma

  • valikuna kolme variandi vahel laua suuruse: 6, 9 või 16 ruutu.
  • ja tekstiväljal sisestamiseks pommide arvu N.

Lisaks on näha nupp "Alusta". Lauda esialgu ei kuvata.

Peale "Alusta" nupule vajutamist kontrollitakse, kas valikud on tehtud. Kui ei, hoiatatakse. Kui jah, kuvatakse tühi laud.

Laud kuva valikute alla ja ära neid valikuid ära kustuta: las jäävad näha.

Laua disaini ära tee klassikalise pseudo-3d ja varjudega, vaid lihtsalt joontest ruudustikuna.

Lisaks laua kuvamisele arvuta välja pommide massiiv, paigutades N pommi juhuslikult laiali (selle kohta leiad all näitekoodi).

Kui kasutaja vajutab mõnele laua ruudule (avab ruudu) siis:

  • Kontrolli, kas tabati pommi, ja kui, siis näita kasutajale, et ta on kaotanud.
  • Kontrolli, kas kõik pommivabad ruudud on avatud, ja kui jah, siis näita kasutajale, et ta on võitnud.
  • Vastasel juhul (normaalolukord) tee järgmist:
    • märgi avatud ruut näiteks teise taustavärviga, rehkenda kokku avatud ruudu kõrvalruutudel olevate pommide arv ning kuva see avatud ruudu sisse. Kõrvalruutusid on ruudul kokku 8, kui ta pole just laua äärel. Kõrvalruutude leidmiseks leiad all näitekoodi.
    • kui avatud ruudu sisse kirjutati nullist suurem arv, on käik lõppenud ja oota uut käiku. Ainult avatud ruut sai sel juhul numbri.
    • kui avatud ruudu sisse kirjutati 0, siis rehkenda kokku naaberruutudel olevate pommide arvud ja kuva iga naaberrudu sisse. Iga naaberruut saab seega numbri, aga ta ei ole märgitud avatuks,

NB! Järgmised lihtsustused on rangelt nõutud, st nende tavafeatuuride tegemine on keelatud:

  • Minesweeperi tüüpilist funktsionaalsust - automaatset suure hulga ruutude avamist - ära tee.
  • Ruutude äramärkimist lipukesega ära tee.
  • Allesjäänud pommide arvu, tehtud käikude arvu, kulunud aega jms ära kuva.

Laua alla kuva seniste tulemuste loetelu: iga rida selles ütleb, kas kaotasid või võitsid ja mitu käiku kulus. Iga järgmine lõppenud mäng lisab sinna ühe rea.

Info paigutus ekraanil peab olema stabiilne, tekst/nupud ei tohi hüpata vahel ühte, vahel teise kohta. Leht peab olema selge, arusaadava ja kena disainiga, mõttetut/segast infot ja arusaamist raskendavaid kujunduselemente ära kasuta. Arvesta kindlasti selle juhendi soovitustega.

Kogu kood peab olema laetud dijkstra serverisse prax2 alamkataloogi. Pealeht olgu nimega index.html.

Kohustuslikud ja mittekohustuslikud osad ja punktiarvestus

Kokku võid saada 12 punkti, mis jagunevad selliselt:

Kui suudad kuvada laua ning käigud töötavad ok (naaberruutude arvud kuvatakse ok), saad praktikumi arvestatud ja kokku 6 punkti.

Kui sul on realiseeritud valikud (laua suurus ja pommide arv) ning suudad tuvastada ja kuvada võidu/kaotuse, saad lisaks 2 punkti.

Kui realiseerid tulemuste loetelu kuvamise, saad veel lisaks 2 punkti.

Kui mängu kujundus on kena ja arusaadav nii tava-arvutis kui mobiilis (ei ole vaja scrollida vasakule-paremale, elemendid ei ole väga väikesed jne), siis saad lisaks 2 punkti.


Mobiiliversioon ehk responsive design

Loe kõigepealt läbi see sissejuhatus, siis vaata w3schoolsi näiteid ja jätkuks võid lugeda veel media query kohta.

Kursuse põhilehel on samuti lisaks linke mõistlikele tutorialitele ja näidetele.

Koodist arusaamine ja plagiaadikontroll

Kogu esitatud kood peab jääma prax2 alamkataloogi alles kuni kursuse lõpuni.

Teiste inimeste - ka õppejõu - kirjutatud lahendusi aluseks võtta ei ole OK. Samas on nende lahendustega tutvumine igati soovitav (googelda minesweeper javascript).

Kui juhendaja tuvastab, et sinu koodil on väga suured sarnasused mõne teise koodiga, siis pead (parimal juhul) töö uuesti kirjutama. Järelkontrollid toimuvad ka pärast töö esitamist.

Peaasi: kõigist osadest oma koodis pead ise hästi aru saama ja suutma neid juhendajale selgitada, kui ta küsib. Ei ole OK võtta võrgust juppe, mille funktsioneerimisest sa aru ei saa (ehk, kui võtad mõne jupi, siis tee endale kõigepealt selgeks, mida see jupp täpselt teeb).

CSS-i ja javascripti teegid ja erivariandid javascriptist

Väliste teekide, ntx Jquery või Bootstrap kasutamine on ok, aga siis sa pead hästi aru saama, mida sinu tehtavad teegi-callid või stiilid teevad. Reaalselt on see praks piisavalt lihtne selleks, et teekide kasutamine vajalik ei oleks. Kui otsustad siiski teeki kasutada, siis väga soovitav on valida jquery kui suhteliselt lihtne ja domineerivalt populaarseim javascripti teek, kujunduse jaoks aga Bootstrap. React ja selletaolised suured teegid ja frameworkid on selle praksi jaoks täielik overkill.

Kogu javascript peab olema esitatud minimiseerimata ja nö normaalse taandega, et oleks kergesti loetav.

Ei ole OK kasutada süsteeme nagu typescript, mis kompileerivad sinu lähtekoodi javascriptiks: see muudaks juhendajate töö liiga raskeks. Peab olema võimalik otse koodi muuta ilma vajaduseta kasutada transpilereid nagu babel, pakkijaid nagu webpack jne.

Soovitusi htmli ja cssi osas

Hea mõte on algul jagada lehekülg mitmeks horisontaalseks reaks ja vertikaalseks kõrvuti tulbaks. Kõige lihtsam - ja selle rakenduse jaoks piisav - on seada ridadele ja tulpadele fikseeritud laiused ja kõrgused. NB! Selline fiks laiuste/kõrguste lähenemine ei ole enamiku harilike veebisaitide jaoks päris hea mõte, ja on hoopis halb mobiilile sobiva saidi tegemisel.

Siit ja siit leiad horisontaalse tsentreerimise õpetused (point: margin-left: auto; margin-right: auto;)

Vertikaalset tsentreerimist on raskem teha, aga siin on heaks abiks flexbox. Flexboxi kohta saad pikemalt lugeda näiteks siit.

Tulpade tegemine puhtalt div-dega ei ole ka päris triviaalne.


Soovitusi javascripti osas ja kasulikke näiteid

Kuidas käiku teha? Tee iga ruut kas tabeli elemendina või div-na (viimane on keerulisem) ja pane sinna nupule onclick atribuudina javascripti call, mis kutsub välja käigutegemise funktsiooni näiteks nii:

...
function move(x,y) {
 ...
}
...
<td id="s_3_4" class="gsquare" onclick="move(3,4)"></td>

Igal ruudul peaks olema id mille kaudu saad ruudu sisu muuta. Mõistlik on teha nii, et id leiad kergesti ruudu koordinaatidest.

Ruudul võiks olla class et kujundust kergesti muuta. Samas saab klassi/stiili anda ka nö üldisemalt tabeli td elementidele (või vastavalt div-dele).

Üks esimesi asju, mida su javascripti kood peaks tegema, on pommide paigutamine massiivi, näiteks nii: pommivaba element on 0 ja pommiga 1 ja inimese poolt klikatud (pommivaba) ruut on 2.

Tasub teada, et javascripti massiivid on erinevad java ja pythoni massiividest: nad on korraga nagu listid või javascripti objektid ehk võti-väärtus hashid, neis võivad olla augud ja neid võib suurendada käigu pealt, nö ette valmis tegemata. Mh on kõik array elemendid objekti positsiooni-nimel olevad väärtused, ehk arr.miski on sama, mis arr['miski']. Sul võib olla huvitav vaadata array meetodeid siit

Mitmemõõtmelise massiivi saad teha ja sinna väärtusi anda näiteks nii:

// first create a list of empty sublists
var board=[];
for (var i=0;i<10;i++) {
  board[i] = []; // insert an empty list to position i
}
...

// now insert new elements to sublists:
board[0][1]=0;
board[0][3]=1;
...

Siin on sulle abiks funktsioon, mis ehitab valmis laua massiivi ja paigutab sinna pommid (seda funktsiooni võid soovi korral otse oma praktikumi kopeerida):


// returns board as list of lists like [[0,1],[1,0]]
// size is the row/col length, bombs the number of bombs to insert
// NB! This algorithm may become slow if the nr of bombs is close to
// the board area (i.e. almost all the board covered with bombs)
//
// call it like this: var board=makeBoard(10,5);

function makeBoard(size,bombs) {
  var board=[]; 
  
  if (bombs>=size*size) throw "too many bombs for this size";
  
  // initialize board, filling with zeros
  for (var x=0; x<size; x++) {
    board[x]=[]; // insert empty subarray
    for (var y=0; y<size; y++) board[x][y]=0;
  }

  // now fill board with bombs in random positions
  var i=bombs;
  while (i>0) {
    // generate random x and y in range 0...size-1
    x=Math.floor(Math.random() * size);
    y=Math.floor(Math.random() * size);
    // put bomb on x,y unless there is a bomb already
    if (board[x][y]!=1) {
      board[x][y]=1;
      i--; // bomb successfully positioned, one less to go
      //console.log("positioned "+x+", "+y+" yet to go "+i);
    }
  }
  
  return board;
}

Samuti võib sulle abiks olla funktsioon, mis tagastab ruudu kõigi naabrite koordinaatide listi (ka seda funktsiooni võid soovi korral otse oma praktikumi kopeerida):


// returns a list of neighbour square coordinate pairs for a board 
// with a given size. Examples:
// neighbours(10,4,4) gives [[3,3],[3,4],[3,5],[4,3],[4,5],[5,3],[5,4],[5,5]]
// neighbours(10,0,0) gives [[0,1],[1,0],[1,1]]
// neighbours(10,9,9) gives [[8,8],[8,9],[9,8]]

function neighbours(size,x,y) {
  var list=[];
  for (var i=-1; i<=1; i++) {    
    for (var j=-1; j<=1; j++) {
      // square is not a neighbour of itself
      if (i==0 && j==0) continue;
      // check whether the the neighbour is inside board bounds
      if ((x+i)>=0 && (x+i)<size && (y+j)>=0 && (y+j)<size) {
        list.push([x+i,y+j]);  
      }
    }
  }
  return list;
}  

Tehnoloogianõuded

Kogu rakendus peab kasutama ainult html+css+javascripti ja olema üles laetud serverisse staatiliste lehtedena.

Ära kasuta lehe struktureerimiseks üksteise sees olevaid tabeleid, vaid div-e ja css-i.

Sisuliselt tabeli kujul oleva info (näiteks mängulaud ise) esitamine html tabelina on aga täiesti ok.