C, PHP, VB, .NET

Дневникът на Филип Петров


* Упражнение за структура от данни Queue

Публикувано на 16 май 2023 в раздел УКИ.

Ще надградим проекта, в който се упражняваше структурата от данни стек, като реализираме по-разширен вариант на играта Война. При нея вместо картите да се премахват от тестетата на играчите, всяка спечелена ръка се връща най-отдолу в тестето на този, който е спечелил. Засега за опростяване на играта ще се отклоним от пълния ѝ вариант, като при равенство (когато получим карти с една и съща стойност) ще приемем, че битката печели чрез цвета във възходящ ред: спатия, каро, купа, пика (в истинската игра не е така). Ще печели играчът, който прибере всички карти. Ще използваме оригиналният дизайн със съвсем леки модификации - dealsValue вече ще започва да брои от 0 и ще се увеличава нагоре, като този брояч вече ще има смисъл на „колко на брой хода са направени от началото на играта“.

Първото нещо, което ще направим, е да променим типа на член-променливите. Двете купчини с карти на играчите ще станат съответно от тип структура от данни Queue по следния начин:

Queue<Integer> leftCards = new LinkedList<>();
Queue<Integer> rightCards = new LinkedList<>();

Промяната в метода на инициализиращото събитие ще е минимална:

private void formWindowOpened(java.awt.event.WindowEvent evt) { 
   for(int i=0; i<52; i++){
      deck.add(i);
   }
   Collections.shuffle(deck);

   for(int i=0; i<26; i++){
      leftCards.add(deck.get(i));
      rightCards.add(deck.get(i+26));
   }

   leftCardPlayed.setText(" ");
   rightCardPlayed.setText(" ");
}

Модификацията за кода на метода на бутона е следната:

private void dealButtonActionPerformed(java.awt.event.ActionEvent evt) { 
   // Краят на играта вече настъпва когато едно от двете тестета свърши
   if(leftCards.size()==0 || rightCards.size()==0){
      message.setText("Играта завърши");
      leftCardPlayed.setVisible(false);
      rightCardPlayed.setVisible(false);
      dealButton.setEnabled(false);
      return;
   }
   Integer left = leftCards.poll();
   Integer right = rightCards.poll();
   leftCardPlayed.setIcon(new ImageIcon(getClass().getResource("/CardsWarGame/images/"+left+".png")));
   rightCardPlayed.setIcon(new ImageIcon(getClass().getResource("/CardsWarGame/images/"+right+".png")));

   if((left)%13 > (right)%13){
      leftPlayerScore.setText(""+(Integer.parseInt(leftPlayerScore.getText())+1));
      message.setText(" Точка за левия ");
      // Връщаме картите в началото на левия списък
      leftCards.add(left);
      leftCards.add(right);
   }
   else if((left)%13 < (right)%13){
     rightPlayerScore.setText(""+(Integer.parseInt(rightPlayerScore.getText())+1));
     message.setText(" Точка за десния ");
     // Връщаме картите в началото на десния списък
     rightCards.add(right);
     rightCards.add(left);
   }
   else{
      // При равенство проверяваме кой е по-силния цвят - той ще спечели ръката
      // Възползваме се, че при именоването на файловете са подредени по големина на цветовете
      if(left > right){
         leftPlayerScore.setText(""+(Integer.parseInt(leftPlayerScore.getText())+1));
         message.setText(" Точка за левия ");
         leftCards.add(left);
         leftCards.add(right);
      }
      else{
         rightPlayerScore.setText(""+(Integer.parseInt(rightPlayerScore.getText())+1));
         message.setText(" Точка за десния ");
         rightCards.add(right);
         rightCards.add(left);
      }
   }
   dealsValue.setText(""+(Integer.parseInt(dealsValue.getText())+1));
   // При край на играта вече скриваме гърба на картите само на загубилия
   if(leftCards.size()==0){
      leftDeck.setVisible(false);
      dealButton.setText("Край");
   }
   if(rightCards.size()==0){
      rightDeck.setVisible(false);
      dealButton.setText("Край");
   }
}

Ще забележите, че при този вариант играта става много по-продължителна. Може да се наложи да извършвате над 200 хода и дори много повече, преди да се стигне до изчерпване на една от двете конкурентни опашки. Обърнете също внимание, че играта приключва точно тогава, когато единият играч е натрупал точно 26 точки повече от другия.

Нека се възползваме от това и да променим броячите така, че да отразяват текущия броя карти в тестето на съответния играч. Началната стойност на тези броячи трябва да е 26. След това вместо да ги увеличаваме с единица, просто в края на всеки ход ще ги променяме с текст, който отразява текущия брой елементи в опашката. Промените ще са следните:

private void dealButtonActionPerformed(java.awt.event.ActionEvent evt) { 
   if(leftCards.size()==0 || rightCards.size()==0){
      message.setText("Играта завърши");
      leftCardPlayed.setVisible(false);
      rightCardPlayed.setVisible(false);
      dealButton.setEnabled(false);
      return;
   }
   Integer left = leftCards.poll();
   Integer right = rightCards.poll();
   leftCardPlayed.setIcon(new ImageIcon(getClass().getResource("/CardsWarGame/images/"+left+".png")));
   rightCardPlayed.setIcon(new ImageIcon(getClass().getResource("/CardsWarGame/images/"+right+".png")));
   if((left)%13 > (right)%13){
      //leftPlayerScore.setText(""+(Integer.parseInt(leftPlayerScore.getText())+1));
      message.setText(" Точка за левия ");
      leftCards.add(left);
      leftCards.add(right);
   }
   else if((left)%13 < (right)%13){
      //rightPlayerScore.setText(""+(Integer.parseInt(rightPlayerScore.getText())+1));
      message.setText(" Точка за десния ");
      rightCards.add(right);
      rightCards.add(left);
   }
   else{
      if(left > right){
         //leftPlayerScore.setText(""+(Integer.parseInt(leftPlayerScore.getText())+1));
         message.setText(" Точка за левия ");
         leftCards.add(left);
         leftCards.add(right);
      }
      else{
         //rightPlayerScore.setText(""+(Integer.parseInt(rightPlayerScore.getText())+1));
         message.setText(" Точка за десния ");
         rightCards.add(right);
         rightCards.add(left);
      }
   }
   dealsValue.setText(""+(Integer.parseInt(dealsValue.getText())+1));
   leftPlayerScore.setText(""+leftCards.size());
   rightPlayerScore.setText(""+rightCards.size());
   // При край на играта вече скриваме гърба на картите само на загубилия
   if(leftCards.size()==0){
      leftDeck.setVisible(false);
      dealButton.setText("Край");
   }
   if(rightCards.size()==0){
      rightDeck.setVisible(false);
      dealButton.setText("Край");
   }
}

Задача за упражнение: За пълната версия на играта Война ще е нужно кода да се модифицира така, че при равенство картите да се запазят на масата и да се изтеглят нови. Това може да се реализира като текущите карти на масата се натрупват в стек. Би било добро упражнение за комбинация между двете разгледани структури. Реализацията обаче няма да е толкова проста, особено ако се вземе решение да се отчете и малко вероятната, но все пак възможна „патова“ игра (поредица от 26 равни и няма нито един победител).

 



Добави коментар

Адресът на електронната поща няма да се публикува


*