C, PHP, VB, .NET

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


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

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

Ще демонстрирам работата със структура от данни стек (Stack) отново чрез пример с визуална програма. Това ще е опростен вариант на играта на карти, която е позната като „война“. Взима се стандартно тесте от 52 карти. Разбърква се добре и се раздава на две равни части. Когато играта започне, двамата играчи едновременно изтеглят и обръщат най-горната карта от своето тесте. Точка печели този, чиято карта е по-силна. Силата на картите не зависи от цветовете, а само от стойностите им, като във възходящ е следната: 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K, А. Ако се паднат две карти с равна сила, никой не печели точка. Изтеглените карти не се връщат обратно в играта, а се отстраняват. Играта завършва тогава, когато се изчерпят и двете тестета. Печели играчът, който е натрупал повече точки (възможен е и равен резултат).

За реализацията на проекта първоначално се нуждаем от картинки на самите карти. Трябват ви 52 файла с имена 0.png, 1.png, 2.png, …, 51.png и един файл с име back.png (гърба на картите). Създайте проект и направете следния дизайн:

Тук обектите по екрана имат следния смисъл:

  • leftCardPlayed е JLabel, който първоначално е с текст „лява карта“. Идеята е на негово място, след натискане на бутона „Война“, да се покаже обърната карта за левия играч;
  • rightCardPlayed е аналогичен обект за показване на обърната карта на десния играч;
  • leftDeck и rightDeck са двете картинки на гърбове на карти, които се виждат на екранната снимка;
  • message е JLabel с първоначален текст „Нека да играем на война“, който стои между leftCardPlayed и rightCardPlayed. В него след всяко изтегляне на нова карта ще казваме кой печели точка;
  • leftPlayerScore e нулата отляво на бутона, с която ще указваме текущия брой точки на левия играч;
  • rightPlayerScore e нулата отдясно на бутона, с която ще указваме текущия брой точки на левия играч;
  • dealButton е бутона за обръщане на карти;
  • dealsValue e броячът за оставащия брой тегления;
  • Останалите обекти са просто информатимни и не се променят.

Забележете, че всички картинки от архива cards.zip ги вмъкнахме в проекта в поддиректория images. Така те ще са директно достъпни програмно.

След като дизайнът е готов, следва да започнем да пишем програмния код. Задайте следните член променливи:

// Масив с всички карти във вид на числа
ArrayList<Integer> deck = new ArrayList<>(52);
// Стек за левите карти
Stack<Integer> leftCards = new Stack<>();
// Стек за десните карти
Stack<Integer> rightCards = new Stack<>();

Ще инициализираме тези член променливи още с отваряне на програмата, като за целта ще създадем събитие FormWindowOpened по следния начин:

private void formWindowOpened(java.awt.event.WindowEvent evt) { 
   // Добавя числата от 0 до 52 в общото тесте карти
   for(int i=0; i<52; i++){
      deck.add(i);
   }
   // Разбърква тестето с карти
   Collections.shuffle(deck);

   // Един по един добавя елементите от първата и втората
   // половина на тестето съответно в левия и десния стек
   for(int i=0; i<26; i++){
      leftCards.push(deck.get(i));
      rightCards.push(deck.get(i+26));
   }
   // Премахва текстовете за лява и дясна карта. Ще се заменят с картинки.
   leftCardPlayed.setText(" ");
   rightCardPlayed.setText(" ");
}

Следва кодът на бутона за започване на войната. В него направете следния код:

private void dealButtonActionPerformed(java.awt.event.ActionEvent evt) { 
   // Ако не са останали карти в лелия стек, това означава, че играта е приключила
   // Ще деактивираме бутона, ще премахнем картите и ще изпишем съобщение за край
   if(leftCards.size()==0){
      message.setText("Играта завърши");
      leftCardPlayed.setVisible(false);
      rightCardPlayed.setVisible(false);
      dealButton.setEnabled(false);
      return;
   }

   // Взимаме най-горните карти от двата стека
   Integer left = leftCards.pop();
   Integer right = rightCards.pop();

   // Сменяме иконката на текущо изиграната карта, за да я покажем.
   // Възползваме се от това, че името на файла съвпада със стойността на картата
   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(" Точка за левия ");
   }
   else if((left)%13 < (right)%13){
      rightPlayerScore.setText(""+(Integer.parseInt(rightPlayerScore.getText())+1));
      message.setText(" Точка за десния ");
   }
   else{
      message.setText(" Равно ");
   }

   // Намаляваме брояча за оставащи ходове
   dealsValue.setText(""+(Integer.parseInt(dealsValue.getText())-1));

   // Ако няма повече оставащи ходове, това значи, че сме обърнали всички карти в стековете.
   // Затова ги скриваме и променяме текста на бутона на „Край“
   if(leftCards.size()==0){
      leftDeck.setVisible(false);
      rightDeck.setVisible(false);
      dealButton.setText("Край");
   }
}

След компилиране и изпълнение, играта би изглеждала по следния начин:

 



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

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


*