2015-08-19 11:20:51 +02:00
|
|
|
# Licensed under GPLv3
|
|
|
|
# Written by Sebastian Lohff (seba@someserver.de)
|
|
|
|
# http://seba-geek.de/projects/seopardy/
|
|
|
|
|
2013-11-06 20:42:00 +01:00
|
|
|
from __future__ import print_function
|
|
|
|
|
|
|
|
from PySide import QtCore, QtGui
|
|
|
|
|
2013-11-25 12:06:07 +01:00
|
|
|
from player import Player, nobodyColor
|
2013-11-27 01:16:44 +01:00
|
|
|
from windows import QuestionWindow, EditAnswersWindow, PlayerStartWindow, VictoryWindow, DoubleJeopardyWindow
|
2013-11-18 17:47:03 +01:00
|
|
|
from gamestate import QuestionAnswers
|
2013-11-06 20:42:00 +01:00
|
|
|
|
|
|
|
class SeopardyGame(QtGui.QWidget):
|
2013-12-18 01:44:52 +01:00
|
|
|
def __init__(self, questions, gamestate, inputs, parent=None):
|
2013-11-06 20:42:00 +01:00
|
|
|
super(SeopardyGame, self).__init__(parent)
|
|
|
|
|
|
|
|
self.questions = questions
|
|
|
|
self.gamestate = gamestate
|
2013-12-18 01:44:52 +01:00
|
|
|
self.inputs = inputs
|
2013-11-22 00:01:09 +01:00
|
|
|
#self.players = [Player.gen_player(i, parent=self) for i in range(1, 4)]
|
2013-12-01 22:41:44 +01:00
|
|
|
self.players = self.gamestate.get_players()
|
|
|
|
if len(self.players) == 0:
|
|
|
|
for i in range(3):
|
|
|
|
self.add_player()
|
|
|
|
|
2013-11-27 01:16:44 +01:00
|
|
|
self.currentPlayer = None
|
2013-11-06 20:42:00 +01:00
|
|
|
|
2013-11-22 00:01:09 +01:00
|
|
|
self._inOtherWindow = False
|
2013-11-06 20:42:00 +01:00
|
|
|
self._createGui()
|
2015-01-06 20:06:33 +01:00
|
|
|
self.setWindowTitle("Seopardy - Board")
|
2013-11-06 20:42:00 +01:00
|
|
|
self.showFullScreen()
|
|
|
|
|
2013-11-22 00:01:09 +01:00
|
|
|
# initiate starting the game!
|
2013-12-01 22:41:44 +01:00
|
|
|
if self.gamestate.get_state() == "start":
|
|
|
|
QtCore.QCoreApplication.postEvent(self, GameStartEvent())
|
2013-11-22 00:01:09 +01:00
|
|
|
|
2013-12-07 20:44:17 +01:00
|
|
|
def add_player(self, addToGui=False):
|
2013-11-22 00:01:09 +01:00
|
|
|
self.players.append(Player.gen_player(len(self.players)+1, self))
|
|
|
|
|
2013-12-07 20:44:17 +01:00
|
|
|
if addToGui:
|
|
|
|
if len(self.players) > 1:
|
|
|
|
self.playerBar.addStretch()
|
|
|
|
self.playerBar.addWidget(self.players[-1])
|
|
|
|
|
2013-11-06 20:42:00 +01:00
|
|
|
def _createGui(self):
|
|
|
|
""" Create the board from questions. """
|
|
|
|
|
|
|
|
layout = QtGui.QVBoxLayout()
|
|
|
|
headerLayout = QtGui.QHBoxLayout()
|
2014-12-27 13:11:21 +01:00
|
|
|
self.header = QtGui.QLabel(self.questions.get_title())
|
2015-01-05 18:25:09 +01:00
|
|
|
self.header.setStyleSheet("QLabel { font-size: 20px; }")
|
2014-12-17 04:05:23 +01:00
|
|
|
headerLayout.addWidget(self.header)
|
2013-11-06 20:42:00 +01:00
|
|
|
headerLayout.setSizeConstraint(QtGui.QLayout.SetMinimumSize)
|
2014-12-17 04:05:23 +01:00
|
|
|
layout.addWidget(self.header, alignment=QtCore.Qt.AlignCenter)
|
2013-11-06 20:42:00 +01:00
|
|
|
|
|
|
|
# create board
|
|
|
|
#board = QtGui.QGridLayout(6, len(self.questions.get_sections()))
|
2013-12-01 22:41:44 +01:00
|
|
|
self.board = QtGui.QGridLayout()
|
|
|
|
self.board.setSizeConstraint(QtGui.QLayout.SetMaximumSize)
|
2013-11-06 20:42:00 +01:00
|
|
|
for i, sec in enumerate(self.questions.get_sections()):
|
|
|
|
seclabel = QtGui.QLabel(sec, alignment=QtCore.Qt.AlignCenter)
|
|
|
|
seclabel.setStyleSheet("QLabel { font-size: 30px; }")
|
2013-12-01 22:41:44 +01:00
|
|
|
self.board.addWidget(seclabel, 0, i)
|
2013-11-06 20:42:00 +01:00
|
|
|
for j in range(5):
|
|
|
|
b = QtGui.QPushButton(str((j+1)*100))
|
|
|
|
b.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
|
|
|
|
b.setAutoDefault(False)
|
2013-12-01 22:41:44 +01:00
|
|
|
#b.setStyleSheet("QPushButton { font-size: 60px; }")
|
2013-11-18 18:33:43 +01:00
|
|
|
b.installEventFilter(FocusKeyGrabber(i+1, j+1, self))
|
2013-11-11 00:52:37 +01:00
|
|
|
b.clicked.connect(lambda sec=sec, j=j: self.go_to_question(sec, j+1))
|
2013-12-01 22:41:44 +01:00
|
|
|
self.board.addWidget(b, j+1, i)
|
|
|
|
self._restyle_button(sec, j+1, self.gamestate.get_answers(sec, j+1))
|
|
|
|
layout.addLayout(self.board)
|
2013-11-06 20:42:00 +01:00
|
|
|
|
|
|
|
# create player bar
|
|
|
|
self.playerBar = QtGui.QHBoxLayout()
|
|
|
|
for i, player in enumerate(self.players):
|
|
|
|
self.playerBar.addWidget(player)
|
|
|
|
if i != len(self.players)-1:
|
|
|
|
self.playerBar.addStretch()
|
|
|
|
layout.addLayout(self.playerBar)
|
|
|
|
|
|
|
|
self.setLayout(layout)
|
|
|
|
|
2013-11-18 18:33:43 +01:00
|
|
|
def setFocusToQuestion(self, secno, number):
|
|
|
|
if secno < 1 or secno > len(self.questions.get_sections()) or number > 5 or number < 1:
|
|
|
|
return
|
|
|
|
|
|
|
|
self.board.itemAtPosition(number, secno-1).widget().setFocus()
|
2013-11-11 00:52:37 +01:00
|
|
|
|
2013-11-22 00:01:09 +01:00
|
|
|
def event(self, e):
|
|
|
|
if e.type() == GameStartEvent.eventType:
|
|
|
|
# start window
|
|
|
|
if not self._inOtherWindow:
|
|
|
|
self._inOtherWindow = True
|
|
|
|
x = PlayerStartWindow(self.players, self)
|
2013-12-19 18:42:08 +01:00
|
|
|
for inp in self.inputs:
|
|
|
|
inp.buttonEvent.connect(x.playerButtonPress)
|
|
|
|
x.buzzersOpen.connect(inp.buzzersOpen)
|
|
|
|
x.playerGotQuestion.connect(inp.playerGotQuestion)
|
2013-11-22 00:01:09 +01:00
|
|
|
x.exec_()
|
2013-12-19 18:42:08 +01:00
|
|
|
for inp in self.inputs:
|
|
|
|
inp.buttonEvent.disconnect(x.playerButtonPress)
|
|
|
|
x.buzzersOpen.disconnect(inp.buzzersOpen)
|
|
|
|
x.playerGotQuestion.disconnect(inp.playerGotQuestion)
|
2013-11-22 00:01:09 +01:00
|
|
|
self._inOtherWindow = False
|
2013-12-01 22:41:44 +01:00
|
|
|
self.gamestate.set_state("playing")
|
|
|
|
self.gamestate.save()
|
2013-11-22 00:01:09 +01:00
|
|
|
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
return super(SeopardyGame, self).event(e)
|
|
|
|
|
2013-12-07 21:09:17 +01:00
|
|
|
def closeEvent(self, event):
|
|
|
|
if not self._inOtherWindow:
|
|
|
|
event.accept()
|
|
|
|
else:
|
|
|
|
event.ignore()
|
|
|
|
|
2013-11-07 01:19:50 +01:00
|
|
|
def keyPressEvent(self, e):
|
|
|
|
if e.key() == QtCore.Qt.Key_Escape:
|
|
|
|
self.close()
|
2013-11-22 02:28:12 +01:00
|
|
|
elif e.key() == QtCore.Qt.Key_R:
|
|
|
|
x = PlayerStartWindow(self.players, self)
|
|
|
|
self._inOtherWindow = True
|
|
|
|
x.exec_()
|
|
|
|
self._inOtherWindow = False
|
2013-11-23 17:51:52 +01:00
|
|
|
elif e.key() == QtCore.Qt.Key_V:
|
|
|
|
self.show_victory_window()
|
2013-11-13 21:16:50 +01:00
|
|
|
elif e.key() == QtCore.Qt.Key_E:
|
|
|
|
if self._inOtherWindow:
|
|
|
|
return
|
2013-11-18 17:47:03 +01:00
|
|
|
|
|
|
|
# find current question
|
|
|
|
section = None
|
|
|
|
qno = None
|
|
|
|
found = False
|
|
|
|
for secno, section in enumerate(self.questions.get_sections(), 0):
|
|
|
|
for qno in range(1, 6):
|
|
|
|
btn = self.board.itemAtPosition(qno, secno).widget()
|
|
|
|
if btn == self.focusWidget():
|
|
|
|
found = True
|
|
|
|
break
|
|
|
|
if found:
|
|
|
|
break
|
|
|
|
|
|
|
|
if not found:
|
|
|
|
return
|
|
|
|
|
|
|
|
self.edit_question_answers(section, qno)
|
|
|
|
|
|
|
|
def edit_question_answers(self, section, number):
|
2013-11-13 21:16:50 +01:00
|
|
|
self._inOtherWindow = True
|
2013-11-18 17:47:03 +01:00
|
|
|
|
|
|
|
answers = self.gamestate.get_answers(section, number)
|
|
|
|
if answers is None:
|
|
|
|
answers = QuestionAnswers(section, number)
|
|
|
|
|
|
|
|
editAnswersWin = EditAnswersWindow(self.players, answers, self)
|
|
|
|
editAnswersWin.exec_()
|
2013-11-13 21:16:50 +01:00
|
|
|
self._inOtherWindow = False
|
2013-11-07 01:19:50 +01:00
|
|
|
|
2013-11-18 17:47:03 +01:00
|
|
|
oldAnswers = self.gamestate.get_answers(section, number)
|
|
|
|
newAnswers = editAnswersWin.get_new_answers()
|
|
|
|
if oldAnswers:
|
|
|
|
self._set_player_points(oldAnswers, rollback=True)
|
|
|
|
self._set_player_points(newAnswers)
|
|
|
|
self.gamestate.set_answers(section, number, newAnswers)
|
|
|
|
self._restyle_button(section, number, newAnswers)
|
2013-12-01 22:41:44 +01:00
|
|
|
self.gamestate.save()
|
2013-11-18 17:47:03 +01:00
|
|
|
|
2013-11-23 17:51:52 +01:00
|
|
|
def show_victory_window(self):
|
|
|
|
self._inOtherWindow = True
|
|
|
|
victoryWindow = VictoryWindow(self.players, self)
|
|
|
|
victoryWindow.exec_()
|
|
|
|
self._inOtherWindow = False
|
|
|
|
|
2013-11-11 00:52:37 +01:00
|
|
|
def go_to_question(self, section, number):
|
2013-11-13 21:16:50 +01:00
|
|
|
if self._inOtherWindow:
|
2013-11-11 00:52:37 +01:00
|
|
|
return
|
2013-11-13 21:16:50 +01:00
|
|
|
self._inOtherWindow = True
|
|
|
|
answers = self.gamestate.get_answers(section, number)
|
2013-11-25 19:26:57 +01:00
|
|
|
wasAnswered = (answers is not None and answers.is_answered())
|
2013-11-06 20:42:00 +01:00
|
|
|
|
2013-11-25 19:26:57 +01:00
|
|
|
question = self.questions.get_question(section, number)
|
2013-11-28 20:13:30 +01:00
|
|
|
dj = None
|
2013-11-27 01:16:44 +01:00
|
|
|
if not wasAnswered and question["Double-Jeopardy"]:
|
|
|
|
dwin = DoubleJeopardyWindow(self.players, number*100, self.currentPlayer, parent=self)
|
|
|
|
dwin.exec_()
|
2013-11-28 20:13:30 +01:00
|
|
|
dj = (dwin.get_player(), dwin.get_chosen_points())
|
2013-11-25 19:26:57 +01:00
|
|
|
|
2013-11-28 20:13:30 +01:00
|
|
|
qwin = QuestionWindow(self.players, section, number, question, answers, dj, self)
|
2013-12-18 01:44:52 +01:00
|
|
|
for inp in self.inputs:
|
2013-12-19 18:07:06 +01:00
|
|
|
inp.buttonEvent.connect(qwin.playerButtonPress)
|
2013-12-18 01:44:52 +01:00
|
|
|
qwin.buzzersOpen.connect(inp.buzzersOpen)
|
|
|
|
qwin.playerGotQuestion.connect(inp.playerGotQuestion)
|
2013-11-06 20:42:00 +01:00
|
|
|
qwin.showFullScreen()
|
|
|
|
qwin.exec_()
|
2013-12-18 01:44:52 +01:00
|
|
|
for inp in self.inputs:
|
2013-12-19 18:07:06 +01:00
|
|
|
inp.buttonEvent.disconnect(qwin.playerButtonPress)
|
2013-12-18 01:44:52 +01:00
|
|
|
qwin.buzzersOpen.disconnect(inp.buzzersOpen)
|
|
|
|
qwin.playerGotQuestion.disconnect(inp.playerGotQuestion)
|
2013-11-06 20:42:00 +01:00
|
|
|
|
2013-11-13 21:16:50 +01:00
|
|
|
self._inOtherWindow = False
|
2013-11-11 00:52:37 +01:00
|
|
|
|
|
|
|
# add points to players
|
2013-11-25 19:26:57 +01:00
|
|
|
if not wasAnswered:
|
|
|
|
answers = qwin.get_answers()
|
|
|
|
self.gamestate.set_answers(section, number, answers)
|
|
|
|
|
|
|
|
self._set_player_points(answers)
|
2013-11-11 00:52:37 +01:00
|
|
|
|
2013-11-27 01:16:44 +01:00
|
|
|
if answers.get_winner():
|
|
|
|
self.currentPlayer = answers.get_winner()
|
|
|
|
|
2013-11-11 00:52:37 +01:00
|
|
|
# restyle the button
|
|
|
|
self._restyle_button(section, number, answers)
|
|
|
|
|
2013-12-01 22:41:44 +01:00
|
|
|
# safe current gamestate
|
|
|
|
self.gamestate.save()
|
|
|
|
|
|
|
|
# check if we are done
|
|
|
|
foundUnanswered = False
|
|
|
|
for sec in self.questions.get_sections():
|
|
|
|
for j in range(5):
|
|
|
|
boardAnswers = self.gamestate.get_answers(sec, j+1)
|
|
|
|
if boardAnswers is None or not answers.is_answered():
|
|
|
|
foundUnanswered = True
|
|
|
|
if foundUnanswered:
|
|
|
|
break
|
|
|
|
|
|
|
|
if not foundUnanswered:
|
|
|
|
self.show_victory_window()
|
|
|
|
|
|
|
|
|
2013-11-13 21:16:50 +01:00
|
|
|
def _set_player_points(self, answers, rollback=False):
|
2013-11-28 20:13:30 +01:00
|
|
|
for i, (player, correct) in enumerate(answers.get_tries()):
|
2013-11-13 21:16:50 +01:00
|
|
|
prefix = 1
|
|
|
|
if rollback:
|
|
|
|
prefix *= -1
|
|
|
|
if not correct:
|
|
|
|
prefix *= -1
|
2013-11-28 20:13:30 +01:00
|
|
|
|
|
|
|
points = 0
|
|
|
|
if i == 0 and answers.get_dj_points() is not None:
|
|
|
|
points = answers.get_dj_points()
|
|
|
|
else:
|
|
|
|
points = answers.points()
|
|
|
|
|
|
|
|
player.add_points(prefix*points)
|
2013-11-11 00:52:37 +01:00
|
|
|
|
|
|
|
def _restyle_button(self, sec, qno, answers):
|
2013-11-18 17:47:03 +01:00
|
|
|
|
2013-11-11 00:52:37 +01:00
|
|
|
secno = self.questions.get_number_from_section(sec)
|
|
|
|
btn = self.board.itemAtPosition(qno, secno-1).widget()
|
|
|
|
btnstr = ""
|
|
|
|
btncolor = None
|
|
|
|
|
2013-12-01 22:41:44 +01:00
|
|
|
if answers is None or not answers.is_answered():
|
|
|
|
btn.setText(str(qno*100))
|
2013-11-18 17:47:03 +01:00
|
|
|
btn.setStyleSheet("QPushButton { font-size: 60px; }")
|
|
|
|
return
|
|
|
|
|
2013-11-11 00:52:37 +01:00
|
|
|
# restrict number of tries shown
|
|
|
|
numTries = 4 if answers.got_answered() else 3
|
|
|
|
tries = answers.get_tries()
|
|
|
|
if len(tries) > numTries:
|
|
|
|
btnstr = "...\n"
|
2013-11-28 20:47:24 +01:00
|
|
|
|
|
|
|
first = True
|
2013-11-11 00:52:37 +01:00
|
|
|
for player, correct in answers.get_tries()[-numTries:]:
|
|
|
|
if correct:
|
|
|
|
btncolor = player.color
|
|
|
|
prefix = "+"
|
|
|
|
else:
|
|
|
|
prefix = "-"
|
2013-11-28 20:47:24 +01:00
|
|
|
dj = " (D)" if first and answers.get_dj_points() is not None else ""
|
|
|
|
btnstr += "%s%s%s\n" % (prefix, player.name, dj)
|
|
|
|
first = False
|
2013-11-11 00:52:37 +01:00
|
|
|
|
|
|
|
if not answers.got_answered():
|
|
|
|
btnstr += "+nobody"
|
2013-11-25 12:06:07 +01:00
|
|
|
btncolor = nobodyColor
|
2013-11-11 00:52:37 +01:00
|
|
|
|
|
|
|
btn.setStyleSheet("QPushButton { background-color: %s; color: white; font-size: 20px; border: none; }" % (btncolor.name(),))
|
|
|
|
btn.setText(btnstr.strip())
|
2013-11-18 18:33:43 +01:00
|
|
|
|
|
|
|
class FocusKeyGrabber(QtCore.QObject):
|
|
|
|
def __init__(self, secno, number, parent, *args, **kwargs):
|
|
|
|
super(FocusKeyGrabber, self).__init__(parent, *args, **kwargs)
|
|
|
|
self._secno = secno
|
|
|
|
self._number = number
|
|
|
|
self._parent = parent
|
|
|
|
|
|
|
|
def eventFilter(self, obj, e):
|
|
|
|
if e.type() == QtCore.QEvent.KeyPress:
|
|
|
|
if e.key() == QtCore.Qt.Key.Key_Left:
|
|
|
|
self._parent.setFocusToQuestion(self._secno-1, self._number)
|
|
|
|
return True
|
|
|
|
elif e.key() == QtCore.Qt.Key.Key_Right:
|
|
|
|
self._parent.setFocusToQuestion(self._secno+1, self._number)
|
|
|
|
return True
|
|
|
|
elif e.key() == QtCore.Qt.Key.Key_Up:
|
|
|
|
self._parent.setFocusToQuestion(self._secno, self._number-1)
|
|
|
|
return True
|
|
|
|
elif e.key() == QtCore.Qt.Key.Key_Down:
|
|
|
|
self._parent.setFocusToQuestion(self._secno, self._number+1)
|
|
|
|
return True
|
|
|
|
return QtCore.QObject.eventFilter(self, obj, e)
|
2013-11-22 00:01:09 +01:00
|
|
|
|
|
|
|
class GameStartEvent(QtCore.QEvent):
|
|
|
|
eventType = QtCore.QEvent.Type(QtCore.QEvent.registerEventType())
|
|
|
|
def __init__(self):
|
|
|
|
super(GameStartEvent, self).__init__(self.eventType)
|