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