Strona główna » Po Godzinach » Gry » Oczyść Planszę - Kod Źródłowy
 

Oczyść Planszę - Kod Źródłowy

· Gra · Kod Źródłowy ·

Cel

Poniżej znajdują się zagadnienia potrzebne do działania gry Oczyść Planszę. Kod źródłowy został on zapisany w JavaScript. Gra jest wyświetlana przy wkorzystaniu HTML, CSS oraz SVG. W ten sposób gra jest kompatybilna z każdym rozmiarem ekranu i można w nią grać na każdej platformie.

Zagadnienia

Generalnie sposób sterowania oraz sposób wyświetlania pozostaje dowolny i zależy jedynie od decyzji autora. W związku z tym przedstawie najważniejsze funkcje dzięki którym gra odpowiednio działa. Poniżej została przedstawiona ich lista:

  1. Losowanie Planszy
  2. Wybieranie obszaru i jego modyfikowanie
  3. Opadanie oraz przesuwanie odpowiednich pól
  4. Sprawdzanie warunków zwycięstwa

Implementacja

Losowanie Planszy

W celu wylosowania planszy ponumerujmy kolory, a następnie dla każdego pola wylosujmy pewien numer koloru. Zastosowany algorytm jest szybki i takie losowanie zazwyczaj sprawdza się, ale czasem może generować planszę, którą bardzo trudno oczyścić.

  1.   for(var y = 0; y < height; y++) {
  2.     var map_sub = [];
  3.     for(var x = 0; x < width; x++) {
  4.       map_sub.push(Math.floor(Math.random()*Gcolors));
  5.     }
  6.     map.push(map_sub);
  7.   }

Wybieranie obszaru i jego modyfikowanie

Po kliknięciu w wybrane pole użytkownikowi powinien podświetlić dany element i wszystkie elementy wokół o tym samym kolorze. Jednym z pomysłów na rozwiązanie tego problemu jest zastosowanie rekurencji.

Metoda polega na tym, aby po kliknięciu w wybrane pole funkcja oznaczyła to pole, a następnie dla sąsiednich polach wywołała to samo o ile są w tym samym kolorze co kliknięte pole. Dodatkowo należy pamiętać, że dane pole musi istnieć, więc trzeba sprawdzić czy nie będziemy chcieli zmodyfikować pola poza planszą. Oczywiście należy pamiętać, żeby podczas dalszych wywołań funkcji nie uwzględniać pól już oznaczonych.

  1. function fillBoard(x, y, col, check){
  2.   var a = 0;
  3.   var t = getElement(x, y).getAttribute("class");
  4.   if(t == col) {
  5.     a++;
  6.     getElement(x, y).setAttribute("class", "");
  7.     if(x > 0)
  8.       a += fillBoard(x - 1, y, col, check);
  9.     if(x + 1 < map[0].length)
  10.       a += fillBoard(x + 1, y, col, check);
  11.     if(y > 0)
  12.       a += fillBoard(x, y - 1, col, check);
  13.     if(y + 1 < map.length)
  14.       a += fillBoard(x, y + 1, col, check);
  15.     if(check) {
  16.       getElement(x, y).setAttribute("class", t);
  17.     }
  18.   }
  19.   return a;
  20. }

Tutaj funkcja fillBoard() przyjmuje cztery argumenty: x, y czyli współrzędne sprawdzanego pola czy jest do oznaczenia, col - kolor klikniętego pola oraz check - czy wprowadzone zmiany mają zostać wywołane. Jest to bardzo ważne z faktu, że funkcja może działać jako funkcja zliczająca, ponieważ uprości to proces sprawdzania czy istnieje ruch.

(2.) Deklarowana zmienna a będzie zliczać ile pól zostało zmodyfikowanych, a z kolei (3.) zmienna t przechowa informację o kolorze aktualnego pola na (x, y). (4.) Jeśli kolor się zgadza to (5.) aktualizujemy wartość zmienionych pól i (6.) zdejmujemy kolor z pola tj. odznaczamy pole. Następnie (7. - 14.) wywołujemy funkcję dla sąsiednich pól. Jeśli (15.) chcieliśmy tylko zliczać (16.) to należy przywrócić pierwotny kolor.

Opadanie oraz przesuwanie odpowiednich pól

Po zmodyfikowaniu wybranego obszaru trzeba przejść teraz do porządkowania planszy. Wszystkie klocki w każdej kolumnie nie powinny mieć między sobą żadnego pustego pola, a każda pusta kolumna powinna zostać usunięta.

  1. if(fillBoard(x, y, t, true) > 1) {
  2.   var p = fillBoard(x, y, t, false);
  3.   points += (p - 1)*(p - 1);
  4. }
  5. var xs = 0;
  6. for(var x = 0; x < width; x++) {
  7.   var ys = 0;
  8.   for(var y = 0; y < height; y++) {
  9.     var t = getElement(x, y).getAttribute("class");
  10.     if(t != ""){
  11.       getElement(xs, ys).setAttribute("class", t);
  12.       ys++;
  13.     }
  14.   }
  15.   if(ys != 0) {
  16.     xs++;
  17.   }
  18.   for(; ys < height; ys++) {
  19.     getElement(x, ys).setAttribute("class", "");
  20.   }
  21. }
  22. for(; xs < width; xs++) {
  23.   for(var y = 0; y < height; y++) {
  24.     getElement(xs, y).setAttribute("class", "");
  25.   }
  26. }

Po upewnieniu się, że kliknięte pole nie jest puste oraz odczytaniu jego współrzędnych można (1.) spróbować usunąć obszar. Jeśli zwrócona wartość jest większa od 1 to znaczy, że jest to obszar conajmniej dwuelementowy. Następnie (2.) wynik funkcji zapisujemy do zmiennej p i zaznaczamy, że tym razem chcemy go defintywnie usunąć i (3.) dodajemy odpowiednią ilość punktów. Potem rozpoczynamy przesuwanie klocków. Ze względu na fakt, że numer kolumny do której mają być przeniosione dane nie jest równy numeru iteracji to deklarujemy zmienne (6.) xs oraz (8.) ys, które kolejno będą wskazywać numer kolumny zapisu oraz pola w kolumnie.

(7.) Dla każdej kolumny wpierw (9. - 16.) usuń przerwy pomiędzy elementami w kolumnie. Następnie (17.) sprawdź czy został w danej kolumnie zapisany chociaż jeden element. Jeśli tak to (18.) zwiększ indeks zapisu kolumny. Na koniec iteracji (20. - 22.) wszystkie pola powyżej ys zajętych pól w kolumnie ustaw na puste. Podobnie przeprowadź działanie z kolumnami po przejściu przez wszystkie kolumny. (24. - 28.) Wszystkie niezapisane kolumny wypełnij pustymi polami.

Sprawdzanie warunków zwycięstwa

W celu sprawdzenia czy są jeszcze dostępne ruchy wystarczy znaleźć pole, które nie jest puste i który znajduje się w obszarze o rozmiarze większym niż jedno pole.

  1. function anyMove(x, y, col) {
  2.   for(var y = 0; y < height; y++) {
  3.     for(var x = 0; x < width; x++) {
  4.       var t = getElement(x, y).getAttribute("class");
  5.       if(t != "" && fillBoard(x, y, t, true) > 1) {
  6.         return true;
  7.       }
  8.     }
  9.   }
  10.   return false;
  11. }

Wtedy posiadając tak napisaną funkcję można przejść do wypisywania odpowiednich komunikatów. Warto zauważyć, że gra jest ukończona jak nie ma ruchów, ale pole w lewym, dolnym rogu jest puste.

  1. if(anyMove(x, y, t)) {
  2.   reportStatus("Ruch " + move + ", zdobytych punktów: " + points);
  3. } else {
  4.   if(getElement(0, 0).getAttribute("class") == "") {
  5.     reportStatus("Gra ukończona! Wykonanych ruchów " + move + ", zdobytych punktów: " + points);
  6.   } else {
  7.     reportStatus("Porażka!");
  8.   }
  9. }