123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314 |
- # Licensed under GPLv3
- # Written by Sebastian Lohff (seba@someserver.de)
- # http://seba-geek.de/projects/seopardy/
-
- from __future__ import print_function
-
- from PySide import QtCore, QtGui
-
- from player import Player, nobodyColor
- from windows import QuestionWindow, EditAnswersWindow, PlayerStartWindow, VictoryWindow, DoubleJeopardyWindow
- from gamestate import QuestionAnswers
-
- class SeopardyGame(QtGui.QWidget):
- def __init__(self, questions, gamestate, inputs, parent=None):
- super(SeopardyGame, self).__init__(parent)
-
- self.questions = questions
- self.gamestate = gamestate
- self.inputs = inputs
- #self.players = [Player.gen_player(i, parent=self) for i in range(1, 4)]
- self.players = self.gamestate.get_players()
- if len(self.players) == 0:
- for i in range(3):
- self.add_player()
-
- self.currentPlayer = None
-
- self._inOtherWindow = False
- self._createGui()
- self.setWindowTitle("Seopardy - Board")
- self.showFullScreen()
-
- # initiate starting the game!
- if self.gamestate.get_state() == "start":
- QtCore.QCoreApplication.postEvent(self, GameStartEvent())
-
- def add_player(self, addToGui=False):
- self.players.append(Player.gen_player(len(self.players)+1, self))
-
- if addToGui:
- if len(self.players) > 1:
- self.playerBar.addStretch()
- self.playerBar.addWidget(self.players[-1])
-
- def _createGui(self):
- """ Create the board from questions. """
-
- layout = QtGui.QVBoxLayout()
- headerLayout = QtGui.QHBoxLayout()
- self.header = QtGui.QLabel(self.questions.get_title())
- self.header.setStyleSheet("QLabel { font-size: 20px; }")
- headerLayout.addWidget(self.header)
- headerLayout.setSizeConstraint(QtGui.QLayout.SetMinimumSize)
- layout.addWidget(self.header, alignment=QtCore.Qt.AlignCenter)
-
- # create board
- #board = QtGui.QGridLayout(6, len(self.questions.get_sections()))
- self.board = QtGui.QGridLayout()
- self.board.setSizeConstraint(QtGui.QLayout.SetMaximumSize)
- for i, sec in enumerate(self.questions.get_sections()):
- seclabel = QtGui.QLabel(sec, alignment=QtCore.Qt.AlignCenter)
- seclabel.setStyleSheet("QLabel { font-size: 30px; }")
- self.board.addWidget(seclabel, 0, i)
- for j in range(5):
- b = QtGui.QPushButton(str((j+1)*100))
- b.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
- b.setAutoDefault(False)
- #b.setStyleSheet("QPushButton { font-size: 60px; }")
- b.installEventFilter(FocusKeyGrabber(i+1, j+1, self))
- b.clicked.connect(lambda sec=sec, j=j: self.go_to_question(sec, j+1))
- self.board.addWidget(b, j+1, i)
- self._restyle_button(sec, j+1, self.gamestate.get_answers(sec, j+1))
- layout.addLayout(self.board)
-
- # 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)
-
- 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()
-
- def event(self, e):
- if e.type() == GameStartEvent.eventType:
- # start window
- if not self._inOtherWindow:
- self._inOtherWindow = True
- x = PlayerStartWindow(self.players, self)
- for inp in self.inputs:
- inp.buttonEvent.connect(x.playerButtonPress)
- x.buzzersOpen.connect(inp.buzzersOpen)
- x.playerGotQuestion.connect(inp.playerGotQuestion)
- x.exec_()
- for inp in self.inputs:
- inp.buttonEvent.disconnect(x.playerButtonPress)
- x.buzzersOpen.disconnect(inp.buzzersOpen)
- x.playerGotQuestion.disconnect(inp.playerGotQuestion)
- self._inOtherWindow = False
- self.gamestate.set_state("playing")
- self.gamestate.save()
-
- return True
- else:
- return super(SeopardyGame, self).event(e)
-
- def closeEvent(self, event):
- if not self._inOtherWindow:
- event.accept()
- else:
- event.ignore()
-
- def keyPressEvent(self, e):
- if e.key() == QtCore.Qt.Key_Escape:
- self.close()
- elif e.key() == QtCore.Qt.Key_R:
- x = PlayerStartWindow(self.players, self)
- self._inOtherWindow = True
- x.exec_()
- self._inOtherWindow = False
- elif e.key() == QtCore.Qt.Key_V:
- self.show_victory_window()
- elif e.key() == QtCore.Qt.Key_E:
- if self._inOtherWindow:
- return
-
- # 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):
- self._inOtherWindow = True
-
- answers = self.gamestate.get_answers(section, number)
- if answers is None:
- answers = QuestionAnswers(section, number)
-
- editAnswersWin = EditAnswersWindow(self.players, answers, self)
- editAnswersWin.exec_()
- self._inOtherWindow = False
-
- 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)
- self.gamestate.save()
-
- def show_victory_window(self):
- self._inOtherWindow = True
- victoryWindow = VictoryWindow(self.players, self)
- victoryWindow.exec_()
- self._inOtherWindow = False
-
- def go_to_question(self, section, number):
- if self._inOtherWindow:
- return
- self._inOtherWindow = True
- answers = self.gamestate.get_answers(section, number)
- wasAnswered = (answers is not None and answers.is_answered())
-
- question = self.questions.get_question(section, number)
- dj = None
- if not wasAnswered and question["Double-Jeopardy"]:
- dwin = DoubleJeopardyWindow(self.players, number*100, self.currentPlayer, parent=self)
- dwin.exec_()
- dj = (dwin.get_player(), dwin.get_chosen_points())
-
- qwin = QuestionWindow(self.players, section, number, question, answers, dj, self)
- for inp in self.inputs:
- inp.buttonEvent.connect(qwin.playerButtonPress)
- qwin.buzzersOpen.connect(inp.buzzersOpen)
- qwin.playerGotQuestion.connect(inp.playerGotQuestion)
- qwin.showFullScreen()
- qwin.exec_()
- for inp in self.inputs:
- inp.buttonEvent.disconnect(qwin.playerButtonPress)
- qwin.buzzersOpen.disconnect(inp.buzzersOpen)
- qwin.playerGotQuestion.disconnect(inp.playerGotQuestion)
-
- self._inOtherWindow = False
-
- # add points to players
- if not wasAnswered:
- answers = qwin.get_answers()
- self.gamestate.set_answers(section, number, answers)
-
- self._set_player_points(answers)
-
- if answers.get_winner():
- self.currentPlayer = answers.get_winner()
-
- # restyle the button
- self._restyle_button(section, number, answers)
-
- # 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()
-
-
- def _set_player_points(self, answers, rollback=False):
- for i, (player, correct) in enumerate(answers.get_tries()):
- prefix = 1
- if rollback:
- prefix *= -1
- if not correct:
- prefix *= -1
-
- 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)
-
- def _restyle_button(self, sec, qno, answers):
-
- secno = self.questions.get_number_from_section(sec)
- btn = self.board.itemAtPosition(qno, secno-1).widget()
- btnstr = ""
- btncolor = None
-
- if answers is None or not answers.is_answered():
- btn.setText(str(qno*100))
- btn.setStyleSheet("QPushButton { font-size: 60px; }")
- return
-
- # restrict number of tries shown
- numTries = 4 if answers.got_answered() else 3
- tries = answers.get_tries()
- if len(tries) > numTries:
- btnstr = "...\n"
-
- first = True
- for player, correct in answers.get_tries()[-numTries:]:
- if correct:
- btncolor = player.color
- prefix = "+"
- else:
- prefix = "-"
- dj = " (D)" if first and answers.get_dj_points() is not None else ""
- btnstr += "%s%s%s\n" % (prefix, player.name, dj)
- first = False
-
- if not answers.got_answered():
- btnstr += "+nobody"
- btncolor = nobodyColor
-
- btn.setStyleSheet("QPushButton { background-color: %s; color: white; font-size: 20px; border: none; }" % (btncolor.name(),))
- btn.setText(btnstr.strip())
-
- 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)
-
- class GameStartEvent(QtCore.QEvent):
- eventType = QtCore.QEvent.Type(QtCore.QEvent.registerEventType())
- def __init__(self):
- super(GameStartEvent, self).__init__(self.eventType)
|