KEEP GOING
[python] (4) 블랙잭 GUI 게임 : 코드 개선 본문
project/project4: blackjack GUI programming
[python] (4) 블랙잭 GUI 게임 : 코드 개선
jmHan 2021. 12. 15. 14:06반응형
버튼 파일을 꾸미기 위한 stylesheet 파일이나 게임 결과 text를 담아두는 파일을 gameText.py로 따로 분리하였다.
그리고나서 메인 로직이 구현된 secondWindow.py의 코드를 개선해보았다.
추가적으로 내부 동작 알고리즘을 구현한 innerCode.py에 대한 unittest를 진행하였는데 unitTest.py에 기록해두었다.
1. button.py
from PyQt5.QtWidgets import *
class Button(QToolButton):
def __init__(self, text, callback):
super().__init__()
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
self.setText(text)
self.clicked.connect(callback)
def sizeHint(self):
size = super(Button, self).sizeHint()
size.setHeight(size.height() + 50)
size.setWidth(max(size.width(), size.height()))
return size
2. firstWindow.py
from PyQt5.QtGui import QIcon, QPixmap, QCursor
from PyQt5.QtWidgets import QLabel, QPushButton, QHBoxLayout, QGridLayout, QDesktopWidget
from musicPlayer import *
from PyQt5 import QtCore
from PyQt5.QtCore import Qt
from gameText import style_sheet
def styleButton(button):
button.setCursor(Qt.PointingHandCursor)
button.setStyleSheet(style_sheet[4])
class FirstWindow(QWidget):
switch_window = QtCore.pyqtSignal()
def __init__(self):
super().__init__()
self.setWindowTitle("BlackJack Game")
self.setWindowIcon(QIcon("./PNG-cards-1.3/blackjack.png"))
self.setGeometry(0, 0, 900, 600)
self.setStyleSheet('background-color: green')
self.music = MusicPlayer()
self.music.playAudioFile()
self.image = QPixmap("./PNG-cards-1.3/title.png")
self.label = QLabel()
self.label.setAlignment(Qt.AlignCenter)
self.label.setPixmap(self.image)
self.start_button = QPushButton("PLAY")
self.volumeUpButton = QPushButton("+")
self.volumeUpButton.clicked.connect(self.music.volumeUp)
self.volumeDownButton = QPushButton("-")
self.volumeDownButton.clicked.connect(self.music.volumeDown)
self.volumeMuteButton = QPushButton("Mute")
self.volumeMuteButton.clicked.connect(self.music.volumeMute)
styleButton(self.volumeUpButton)
styleButton(self.volumeDownButton)
styleButton(self.volumeMuteButton)
self.volume_layout = QHBoxLayout()
self.volume_layout.addWidget(self.volumeDownButton)
self.volume_layout.addWidget(self.volumeMuteButton)
self.volume_layout.addWidget(self.volumeUpButton)
self.start_button.setCursor(QCursor(Qt.PointingHandCursor))
self.start_button.setStyleSheet(style_sheet[5])
self.start_button.clicked.connect(self.secondWindowEmit)
self.grid = QGridLayout()
self.grid.addWidget(self.label, 1, 1)
self.grid.addWidget(self.start_button, 2, 1)
self.grid.addLayout(self.volume_layout, 3, 1)
self.setLayout(self.grid)
self.center()
self.show()
def center(self):
qr = self.frameGeometry()
cp = QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
def secondWindowEmit(self):
self.switch_window.emit()
3. gameText.py
fight_message = ["You lose!", "You win!", "Draw!", "Congratulations! \nBlack Jack!", "Burst!", "Draw"]
style_sheet = ["""QMessageBox
{
background-color: white;
font-family: 'Georgia';
}
""",
"""QLabel
{
font-size: 18px;
font-family: 'Georgia';
color: blue;
}
"""
, """QLabel
{
font-size: 18px;
font-family: 'Georgia';
color: blue;
}
""",
"""QToolButton{background-color: rgb(249, 228, 183);
color: black;
border-radius: 5px;
font-family: 'Georgia';
font-size: 20px;
}"""
"""QToolButton::hover
{
background-color: white;
}
""",
"""QPushButton{background-color: rgb(249, 228, 183);
color: black;
border-radius: 15px;
font-family: 'Georgia';
font-size: 25px;
padding: 5px 0;}"""
"""QPushButton::hover
{
background-color : white;
}
""",
"""QPushButton{background-color: rgb(249, 228, 183);
color: black;
border-radius: 25px;
font-family: 'Georgia';
font-size: 40px;
margin-bottom: 5px;
padding: 8px 0;}"""
"""QPushButton::hover
{
background-color : white;
}
"""
]
4. innerCode.py
import random
marks = ['spades', 'diamonds', 'hearts', 'clubs']
card_english = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']
# 파일 입출력
def load():
try:
f = open("money.dat", 'r')
return int(f.readline())
except FileNotFoundError:
f = open("money.dat", 'w')
f.write('100000')
return 100000
def write(money):
f = open("money.dat", 'w')
f.write(money)
f.close()
def set_money(now, betting, num):
# lose : 0
if num == 0 or num == 4:
write(str(now - betting))
return now - betting
# win : 1
elif num == 1:
write(str(now + betting))
return now + betting
# Black jack : 3
elif num == 3:
write(str(int(now + (1.5 * betting))))
return int(now + (betting * 1.5))
else:
return now
# 카드 두장(베팅 시 카드 지급)지급후에 카드뭉치에서 제거
def twocard(card):
cardList = []
for i in range(2):
cardList.append(card.pop(0))
return cardList
# 새로운 카드 받기
def cardappend(cardlist, card):
cardlist.append(card.pop(0))
# end 버튼 클릭 이벤트, Lose: 0 Win: 1 Draw 2
def fight(player_result, dealer_result):
if player_result > dealer_result or dealer_result > 21:
return 1
elif player_result < dealer_result or dealer_result == 21:
return 0
if player_result == dealer_result:
return 2
def burst(result):
if result > 21:
return 4
elif result == 21:
return 3
else:
return 5 # nothing
def set_card():
return random.sample(range(52), 17)
def count(card):
result = 0
cnt = 0
for data in card:
if data % 13 >= 10:
result += 10
else:
result += data % 13 + 1
# if data == A
if data % 13 == 0:
cnt += 1
for _ in range(cnt):
# A : 1 or 11
if result + 10 <= 21:
result += 10
else:
break
return result
def intToString_card(card):
card_list = []
for data in card:
card = str(marks[data//13]) + str(card_english[data % 13])
card_list.append(card)
return card_list
5. musicPlayer.py
from PyQt5.QtWidgets import QWidget
from PyQt5 import QtCore
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent
import os
class MusicPlayer(QWidget):
def __init__(self):
super().__init__()
self.player = QMediaPlayer()
def volumeUp(self):
current_volume = self.player.volume()
# print(currentVolume)
self.player.setVolume(current_volume + 10)
def volumeDown(self):
current_volume = self.player.volume()
# print(currentVolume)
self.player.setVolume(current_volume - 10)
def volumeMute(self):
self.player.setMuted(not self.player.isMuted())
def playAudioFile(self):
full_file_path = os.path.join(os.getcwd(), './sounds/bgm.mp3')
url = QtCore.QUrl.fromLocalFile(full_file_path)
content = QMediaContent(url)
self.player.setMedia(content)
self.player.play()
6. secondWindow.py
from PyQt5.QtWidgets import QWidget, QMessageBox, QVBoxLayout, QHBoxLayout, QLabel, QDesktopWidget
from PyQt5.QtGui import QIcon, QPixmap
from PyQt5.QtCore import Qt
from button import Button
from innerCode import *
from gameText import *
class SecondWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("BlackJack Game")
self.setWindowIcon(QIcon(f"./PNG-cards-1.3/blackjack.png"))
# setting the geometry of window
self.setGeometry(0, 0, 1200, 900)
self.setStyleSheet("background-color: green")
self.center()
self.q_msg_box = QMessageBox()
self.q_msg_box.setWindowTitle("Result")
self.q_msg_box.setWindowIcon(QIcon("./PNG-cards-1.3/blackjack.png"))
self.q_msg_box.setStyleSheet(style_sheet[0])
self.money = load()
self.betting_cost = 1000
# self.dealCount = 0
self.display = QLabel()
self.b_display = QLabel('bet: ' + str(self.betting_cost))
self.b_display.setStyleSheet(style_sheet[1])
self.m_display = QLabel('money: ' + str(self.money))
self.m_display.setStyleSheet(style_sheet[2])
display_vbox = QVBoxLayout()
display_vbox.addStretch(1)
display_vbox.addWidget(self.display)
display_vbox.addWidget(self.b_display)
display_vbox.addWidget(self.m_display)
betting_vbox = QVBoxLayout()
hbox = QHBoxLayout()
hbox.addLayout(betting_vbox)
self.components_btn = list() # deal, stay, append, reset, plus, minus
button_groups = [
{'buttons': ["+100", "-100"], 'layout': betting_vbox},
{'buttons': ["deal", "new card", "stay", "reset"], 'layout': hbox},
]
for label in button_groups:
i = 0
for btnText in label['buttons']:
self.components_btn.append(Button(btnText, self.button_clicked))
self.styleButton(self.components_btn[-1])
label['layout'].addWidget(self.components_btn[-1])
i += 1
vbox = QVBoxLayout()
vbox.addStretch(1)
vbox.addLayout(display_vbox)
vbox.addLayout(hbox)
self.setLayout(vbox)
self.cntLst = [0, 150, 300, 450, 600, 750]
self.dLabel = []
self.pLabel = []
for _ in range(len(self.cntLst)):
pl = QLabel(self)
dl = QLabel(self)
self.dLabel.append(dl)
self.pLabel.append(pl)
# 카드 배치, 베팅 초기화
self.clear()
# show all the widgets
self.show()
def loadCard(self, label, cardsuit, cnt, num):
self.pixmap = QPixmap(f"./PNG-cards-1.3/{cardsuit}").scaledToWidth(150)
label.setPixmap(self.pixmap)
label.move(cnt, num) # player 300, dealer 0
label.resize(self.pixmap.width(), self.pixmap.height())
# 프로그램 센터에 배치
def center(self):
qr = self.frameGeometry()
cp = QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
def clear(self):
for pl in self.pLabel:
idx = self.pLabel.index(pl)
if idx < 2:
self.loadCard(pl, 'background', self.cntLst[idx], 300)
else:
self.loadCard(pl, 'green', self.cntLst[idx], 300)
for dl in self.dLabel:
idx = self.dLabel.index(dl)
if idx < 2:
self.loadCard(dl, 'background', self.cntLst[idx], 0)
else:
self.loadCard(dl, 'green', self.cntLst[idx], 0)
self.betting_display('', 1000)
self.components_btn[3].setDisabled(True)
self.components_btn[4].setDisabled(True)
def styleButton(self, button):
button.setCursor(Qt.PointingHandCursor)
button.setStyleSheet(style_sheet[3])
def QMessageBoxExec(self, msg):
msg_box = self.q_msg_box
msg_box.setText(msg)
msg_box.exec()
self.components_btn[3].setDisabled(True)
self.components_btn[4].setDisabled(True)
self.components_btn[5].setDisabled(False)
self.display.setText('If you wanna restart, click reset button')
def button_clicked(self):
button = self.sender()
key = button.text()
if key == '+100':
self.betting_display("", self.betting_cost + 100)
elif key == '-100':
self.betting_display("", self.betting_cost - 100)
elif key == 'deal':
if self.betting_cost < 0:
self.betting_display("Bet on the positive value.", 1000)
elif self.betting_cost > 0:
if self.betting_cost < 1000:
self.betting_display("betting min is 1000", 1000)
elif self.betting_cost > self.money:
self.betting_display("You don't have much money", 1000)
else:
self.display.setText("let's start!")
self.components_btn[5].setDisabled(True)
self.components_disable(False)
self.card = set_card()
self.intPlayercards = twocard(self.card)
# print(self.intPlayercards)
# [34, 5]
self.intDealercards = twocard(self.card)
self.dealercards = intToString_card(self.intDealercards)
self.playercards = intToString_card(self.intPlayercards)
# print(self.intToString_card)
# ['hearts9', 'spades6']
self.loadCard(self.pLabel[0], self.playercards[0], self.cntLst[0], 300)
self.loadCard(self.pLabel[1], self.playercards[1], self.cntLst[1], 300)
self.loadCard(self.dLabel[0], self.dealercards[0], self.cntLst[0], 0)
# self.loadDealerCard(self.dLabel[1], self.dealercards[1], self.cntLst[1])
if count(self.intPlayercards) == 21:
self.money_display(fight_message[3], 3)
else:
self.display.setText("Please click betting number")
elif key == 'new card':
cardappend(self.intPlayercards, self.card)
# print(self.intPlayercards)
# [34, 5, 7]
self.playercards = intToString_card(self.intPlayercards)
for pl in self.pLabel:
idx = self.pLabel.index(pl)
if idx < len(self.intPlayercards):
self.loadCard(pl, self.playercards[idx], self.cntLst[idx], 300)
res = burst(count(self.intPlayercards))
if res != 5:
self.money_display(fight_message[res], res)
elif key == 'stay':
self.loadCard(self.dLabel[1], self.dealercards[1], self.cntLst[1], 0)
# 딜러 카드 합이 17이상이면 더이상 추가 카드를 받을 수 없음
while count(self.intDealercards) < 17:
cardappend(self.intDealercards, self.card)
self.dealercards = intToString_card(self.intDealercards)
for dl in self.dLabel:
idx = self.dLabel.index(dl)
if idx < len(self.intDealercards):
self.loadCard(dl, self.dealercards[idx], self.cntLst[idx], 0)
res = fight(count(self.intPlayercards), count(self.intDealercards))
self.money_display(fight_message[res], res)
elif key == 'reset':
self.components_disable(True)
self.clear()
self.display.setText('Play more? Click deal button')
def components_disable(self, check):
# deal, stay, append, reset, plus, minus
self.components_btn[3].setDisabled(check)
self.components_btn[4].setDisabled(check)
self.components_btn[0].setDisabled(not check)
self.components_btn[1].setDisabled(not check)
self.components_btn[2].setDisabled(not check)
def betting_display(self, message, cost):
self.display.setText(message)
self.betting_cost = cost
self.b_display.setText('bet: ' + str(self.betting_cost))
def money_display(self, message, num):
self.QMessageBoxExec(message)
self.money = set_money(self.money, self.betting_cost, num)
self.m_display.setText('money: ' + str(self.money))
7. unitTest.py
import unittest
from inner import *
class TestInner(unittest.TestCase):
def testShow_card(self):
card = [0]
self.assertEqual(show_card(card), '♠A, ')
def testCount(self):
card = [7, 42]
# ♠8 + ♣4
self.assertEqual(count(card), 12)
def testBlackJack(self):
card = [0, 50]
self.assertEqual(black(card), 'blackjack')
if __name__ == '__main__':
unittest.main()
#inner 현재 구gui호환이라 함수 이름이 다름
marks = ['♠', '◆', '♥', '♣']
card_english = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']
def show_card(card):
card_list = ''
for i in card:
card_list += marks[i // 13] + card_english[i % 13] + ", "
return card_list
def count(card):
result = 0
count_a = 0
for i in card:
if i % 13 >= 10:
result += 10
else:
result += i % 13 + 1
if i % 13 == 0:
count_a += 1
for i in range(count_a):
if result + 10 <= 21:
result += 10
else:
break
return result
#보드에 있던 조건을 함수로 구현
def black(player):
black = 0
for i in player:
if i % 13 == 0:
black += 1
elif i % 13 >= 10:
black += 2
else:
pass
if black == 3:
return 'blackjack'
8. mainGame.py
from firstWindow import FirstWindow
from secondWindow import SecondWindow
from PyQt5.QtWidgets import QApplication
import sys
class MyController:
def __init__(self):
self.first_window = FirstWindow()
self.window = SecondWindow()
self.window.close()
def show_window1(self):
self.first_window.switch_window.connect(self.show_window2)
self.first_window.show()
def show_window2(self):
self.first_window.close()
self.window.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
controller = MyController()
controller.show_window1()
sys.exit(app.exec_())
반응형
'project > project4: blackjack GUI programming' 카테고리의 다른 글
[python] (3) 블랙잭 GUI 게임 : GUI 구현 (1) | 2021.11.25 |
---|---|
[python] (2) 블랙잭 GUI 게임 : 내부 로직 구현 (0) | 2021.11.25 |
[python] (1) 블랙잭 GUI 게임 : 초안 (1) | 2021.11.25 |
Comments