Strona główna » Po Godzinach » Gry » Oryginalna Wieża Hanoi - kod źródłowy
 

Oryginalna Wieża Hanoi - kod źródłowy

· Gra · Kod źródłowy ·

Wstęp

Aplikacja Oryginalna Wieża Hanoi została napisana przy pomocy JavaScript, które zarządza wyświetlaną treścią zmieniając kod HTML oraz CSS. Użyte funkcje są zgodne z najnowszym standardem HTML5.

Umieszczenie na stronie

W celu umieszczenia na stronie gry wystarczy umieścić obiekt typu DIV, który będzie miał identyfikator _game.

  1. <div id="_game"></div>

Skrypt

Zmienne globalne

W celu poprawnego działania aplikacji potrzebnych jest kilka zmiennych globalnych, które mają za zadanie przechowywać informacje pomiędzy różnymi funkcjami. Ich znaczenie jest następujące:

  1. <script>
  2. var margin_rod = 20;
  3. var el_width = 200;
  4. var el_minwidth = 60;
  5. var n = 3;
  6. var paliki = [];
  7. var clicked = "";
  8. var lrod;

(2.) ustalenie marginesu pomiędzy kolejnymi palikami (łącznie z największym elementem). (3.) Maksymalna szerokość pojedynczego elementu. (4.) Najmniejsza szerokość elementu. Zapobiega to tworzeniu bardzo małych elementów. (5.) Domyślna ilość elementów na pierwszym paliku. (6.) Lista paliki będzie przechowywać jakie elementy są na którym paliku. Potrzebne są jeszcze zmienne, które przechowają (7.) kliknięty element oraz (8.) na którym paliku został kliknięty.

Rozpoczęcie gry

Zarówno uruchomienie nowej gry czy zrestartowanie obecnej polega na wywołaniu funkcji prepareGame() razem z argumentem, który będzie oznaczał ile krążków ma zostać położonych na pierwszy paliku.

  1. function prepareGame(new_n) {
  2.  var board = document.getElementById("_game");
  3.  board.innerHTML = "";
  4.  n = new_n;
  5.  paliki = [];
  6.  for(var i = 1; i <= 3; i++){
  7.   board.innerHTML += getRod(i);
  8.   paliki.push([]);
  9.  }
  10.  for(var i = n; i >= 1; i--){
  11.   board.innerHTML += getElement("el" + i, i, 360/n*i);
  12.   setElementPos(document.getElementById("el" + i), n - i, 1);
  13.   paliki[0].push("el" + i);
  14.  }
  15.  board.innerHTML += '<div id="_msg"></div>';
  16.  reportState("Oczekiwanie na pierwszy ruch");
  17. }

(2.) Znalezienie ekranu gry (3.) i jego wyczyszczenie. (4.) Zapamiętanie obecnej ilość krążków (do restartu gry). (5.) Wyczyść pozycję krążków. (6. - 9.) Utwórz trzy paliki. Następnie (10. - 14.) zaczynając od największego elementu: (11.) utwórz nowy obiekt, (12.) ustaw go i (13.) dodaj na koniec listy pierwszego palika. Elementy, które są na końcu danej listy palika są pierwszymi od góry. (15.) Utwórz obiekt pod komunikaty dla użytkownika i (16.) pokaż komunikat, że gra została przygotowana.

Do tworzenia palików służy funkcja getRod(). Tworzy ona n-ty palik, odpowiednio go ustawia na planszy i przypisuję funkcję putObject(), która odbiera zdarzenie odkładania elementu na wybrany palik.

  1. function getRod(n){
  2.  return '<div class="rod" id="rod'+n+'" style="left:'+((n - 0.5)*(margin_rod + el_width) - 20)+'px;bottom:0" onclick="putObject(this);"></div>';
  3. }

Podobną funkcją jest getElement(). Jej zadanie polega na utworzeniu elementu o określonej szerokości, ustaleniu identyfikatora, koloru oraz co ma się stać jak zostanie kliknięty. Funkcja nei ustala pozycji elementu na planszy, a jedynie jego cechy wyglądu i zdarzenia.

  1. function getElement(id,num,col){
  2.  return '<div id="'+id+'" class="el" style="background:hsl('+col+',80%,50%);width:'+(el_minwidth + num*(el_width-el_minwidth)/n)+'px" onclick="setObject(this);">'+num+'</div>';
  3. }

Do ustawiania elementu na stronie służy funkcja setElementPos(). Rozwiązanie to jest o tyle lepsze, że elementy są przestawiane w trakcie rozgrywki, a funkcja jest wykorzystana podczas tworzenia rozgrywki jak i jej samej.

  1. function setElementPos(obj, num, rod){
  2.  obj.style.left = ((rod - 0.5)*(margin_rod + el_width) - obj.style.width.replace("px", "")/2) + "px";
  3.  obj.style.bottom = (40*num) + "px";
  4. }

Ostatnia funkcja podczas przygotowania gry - reportState() wyświetla komunikaty dla gracza (o niepoprawnym ruchu czy, że gra została rozpoczęta.) Jest to zaledwie jedna linijka, która polega na znalezieniu odpowiedniego obiektu i zmianie jego zawartości:

  1. function reportState(msg){
  2.  document.getElementById("_msg").innerHTML = msg;
  3. }

Rozgrywka

Po kliknięciu dowolnego elementu wywoływana jest funkcja setObject():

  1. function setObject(el) {
  2.  if(clicked!="")
  3.   clicked.className = clicked.className.replace("el elc", "el");
  4.  if(el){
  5.   for(var i = 0; i < 3; i++){
  6.    reportState("Element podniesiony");
  7.    if(el.id == paliki[i][paliki[i].length - 1]){
  8.     clicked = el;
  9.     lrod = i;
  10.     el.className = el.className.replace("el", "el elc");
  11.     return;
  12.    }
  13.   }
  14.   reportState("Element nie może zostać podniesiony");
  15.  }
  16.  clicked = "";
  17. }

(2.) Jeśli jest jakiś kliknięty obiekt to (3.) go odznacz. (4.) Jeśli kliknięty jest rzeczywiście obiektem to (5.) zacznij szukać palika na którym jest on element na wierzchu. (6.) Zgłoś status o poniesieniu elementu. (7.) Jeśli i-ty palik ma kliknięty element el na wierzchu to: (8.) zapamiętaj go (9.) oraz palik na którym się znajduje. (10.) Dodaj klasę do obiektu, aby użytkownik zobaczył, że kliknął element. (11.) Zakończ wywoływanie funkcji. (12.) Jednak jeśli funkcja nie zostanie przerwana to: (14.) zgłoś, że element nie może być podniesiony i (16.) przed zakończeniem funkcji ustal, że żaden element nie jest kliknięty.

Po podniesieniu elementu gracz klika na wybrany palik. Do obsługi tego zdarzenie służy funkcja putObject():

  1. function putObject(obj) {
  2.  var rod = obj.id.replace("rod", "");
  3.  if(clicked != "" && (lastElement(rod - 1) == undefined || lastElement(rod - 1).replace("e1_","").replace("e2_","") >= clicked.id.replace("e1_","").replace("e2_",""))){
  4.   reportState("Element przełożony");
  5.   paliki[rod - 1].push(paliki[lrod].pop());
  6.   setElementPos(clicked, paliki[rod - 1].length - 1, rod);
  7.   setObject("");
  8.   if(checkWin()){
  9.    reportState('Zagadka rozwiązana, <a href="javascript:void()" class="cU" onclick="prepareGame(n);">zrestartuj grę</a>');
  10.   }
  11.  }
  12. }

(2.) Pobierz numer palika na podstawie jego identyfikatora. (3.) Jeśli jest kliknięty element i ostatni element listy palika nie jest pusty, element istnieje oraz jest mniejszy od elementu już położonego to: (4.) zgłoś status, że element został przełożony, (5.) zdejmij ostatni element z palika elementu i dodaj go na wybrany palik. (6.) ustal nową pozycję elementu, (7.) odznacz element (8.) i sprawdź warunek wygranej. Jeśli ruch doprowadził do zwycięstwa to (9.) pokaż komunikat o wygranej.

Warunek zwycięstwa jest sprawdzany przy pomocy funkcji checkWin(). Sprawdza ona czy każdy kolejny element na liście środkowego palika ma coraz mniejsze numery elementów:

  1. function checkWin(){
  2.  for(var i = n; i >= 1; i--){
  3.   if(paliki[1][n - i] != "el" + i)
  4.    return false;
  5.  }
  6.  return true;
  7. }

Niewymieniona jeszcze funkcja lastELement() ułatwia wybranie ostatniego elementu z dowolnego palika:

  1. function lastElement(rod) {
  2.  return paliki[rod][paliki[rod].length - 1];
  3. }

Rozpoczęcie gry

Grę można rozpocząć przy pomocy funkcji prepareGame(). Na przykład w celu zrestartowania gry / uruchomienia z domyślną konfiguracją należy wpisać:

  1. prepareGame(n);

Styl rozgrywki

Elementy gry są częściowo ustalana poprzez kod CSS. Styl ekranu gry:

  1. #_game {
  2.  width: 700px;
  3.  height: 400px;
  4.  background: #82b1ff;
  5.  overflow: hidden;
  6.  position: relative;
  7.  margin: 0 auto;
  8. }

Styl pola komunikatów:

  1. #_msg {
  2.  width: 700px;
  3.  top: 0;
  4.  padding: 4px;
  5.  background: #cfd8dc;
  6. }

Styl palika:

  1. .rod {
  2.  width: 40px;
  3.  background: #7F3300;
  4.  border: 1px solid gray;
  5.  position: absolute;
  6.  height: 300px;
  7.  border-radius: 6px;
  8. }

Styl elementu:

  1. .el {
  2.  position: absolute;
  3.  height: 40px;
  4.  border: 1px solid gray;
  5.  border-radius: 6px;
  6.  line-height: 40px;
  7.  font-size: 30px;
  8.  font-weight: 700;
  9.  text-align: center;
  10.  text-shadow: 1px 1px 2px white;
  11. }

Styl wybranego elementu:

  1. .elc {
  2.  opacity: 0.5;
  3. }