* Упражнение за структура от данни 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("Край");
}
}
След компилиране и изпълнение, играта би изглеждала по следния начин:


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