GameState loading/saving works

This commit is contained in:
Sebastian Lohff 2013-12-01 22:41:44 +01:00
parent 13690e493e
commit d26c7a3a88
4 changed files with 118 additions and 20 deletions

49
game.py
View File

@ -13,9 +13,11 @@ class SeopardyGame(QtGui.QWidget):
self.questions = questions
self.gamestate = gamestate
#self.players = [Player.gen_player(i, parent=self) for i in range(1, 4)]
self.players = []
for i in range(3):
self.add_player()
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
@ -23,7 +25,8 @@ class SeopardyGame(QtGui.QWidget):
self.showFullScreen()
# initiate starting the game!
QtCore.QCoreApplication.postEvent(self, GameStartEvent())
if self.gamestate.get_state() == "start":
QtCore.QCoreApplication.postEvent(self, GameStartEvent())
def add_player(self):
self.players.append(Player.gen_player(len(self.players)+1, self))
@ -40,22 +43,22 @@ class SeopardyGame(QtGui.QWidget):
# create board
#board = QtGui.QGridLayout(6, len(self.questions.get_sections()))
board = QtGui.QGridLayout()
board.setSizeConstraint(QtGui.QLayout.SetMaximumSize)
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; }")
board.addWidget(seclabel, 0, i)
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.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))
board.addWidget(b, j+1, i)
layout.addLayout(board)
self.board = board
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()
@ -81,6 +84,8 @@ class SeopardyGame(QtGui.QWidget):
x = PlayerStartWindow(self.players, self)
x.exec_()
self._inOtherWindow = False
self.gamestate.set_state("playing")
self.gamestate.save()
return True
else:
@ -136,6 +141,7 @@ class SeopardyGame(QtGui.QWidget):
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
@ -176,6 +182,23 @@ class SeopardyGame(QtGui.QWidget):
# 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
@ -199,8 +222,8 @@ class SeopardyGame(QtGui.QWidget):
btnstr = ""
btncolor = None
if not answers.is_answered():
btn.setText(str(answers.points()))
if answers is None or not answers.is_answered():
btn.setText(str(qno*100))
btn.setStyleSheet("QPushButton { font-size: 60px; }")
return

View File

@ -1,6 +1,8 @@
from __future__ import print_function
import datetime
import os
import yaml
from collections import defaultdict
class GameState(object):
@ -10,17 +12,30 @@ class GameState(object):
savedir: dir to save gamestate into, should be overwritable
board: dict of section with list of questions
"""
GAMESTATE = ["start", "playing", "end"]
def __init__(self, savedir):
self.savedir = savedir
self._board = defaultdict(lambda: [None]*5)
self._players = None
#self._board = defaultdict(lambda: [None]*5)
self._board = defaultdict(_mk_empty_board_column)
self._players = []
self._state = self.GAMESTATE[0]
if not os.path.exists(self.savedir):
os.mkdir(self.savedir)
elif not os.path.isdir(self.savedir):
raise ValueError("'%s' is not a directory but something else!" % self.savedir)
def set_state(self, state):
if state not in self.GAMESTATE:
raise ValueError("'%s' is not a valid gamestate, valid choices are %s" % (state, self.GAMESTATE))
self._state = state
def get_state(self):
return self._state
def set_answers(self, section, qnumber, answers):
self._board[section][qnumber-1] = answers
@ -28,14 +43,38 @@ class GameState(object):
return self._board[section][qnumber-1]
def set_players(self, players):
self.players = players
self._players = players
def get_players(self):
return self._players
def _make_structure(self):
return {
"state": self._state,
"players": self._players,
"board": self._board
}
def save(self):
pass
fname = datetime.datetime.now().strftime("seopardy.%Y-%m-%d-_%H:%M:%S.save")
fstream = open("%s/%s" % (self.savedir, fname), "w")
yaml.dump(self._make_structure(), fstream)
fstream.close()
@classmethod
def load(clazz, fpath):
pass
def load(clazz, sstream, savedir):
gs = clazz(savedir)
data = yaml.load(sstream)
gs._state = data["state"]
gs._players = data["players"]
gs._board = data["board"]
return gs
def _mk_empty_board_column():
""" We can't use a lambda here, as we want the default dict to be
easily serializeable by yaml. """
return [None]*5
class QuestionAnswers(object):
def __init__(self, section, qnumber, dj_points=None):

View File

@ -1,5 +1,6 @@
from __future__ import print_function
import yaml
from PySide import QtGui, QtCore
class Player(QtGui.QWidget):
@ -9,6 +10,7 @@ class Player(QtGui.QWidget):
("Baz", QtGui.QColor(0, 0, 255)),
("Blubb", QtGui.QColor(0, 255, 255)),
("Murr", QtGui.QColor(255, 0, 255)),
("Maunz", QtGui.QColor(255, 255, 0)),
]
def __init__(self, name, color, points=0, parent=None):
@ -46,6 +48,21 @@ class Player(QtGui.QWidget):
return clazz(*clazz.DEFAULT_PLAYERS[num-1], parent=parent)
@classmethod
def _yaml_representer(clazz, dumper, data):
#def __init__(self, name, color, points=0, parent=None):
return dumper.represent_mapping(u'!player', {
'name': data.name,
'points': data.points,
'color': data.color.name()
})
@classmethod
def _yaml_constructor(clazz, loader, node):
pdict = loader.construct_mapping(node)
pdict["color"] = QtGui.QColor(pdict["color"])
return Player(**pdict)
class ButtonEvent(QtCore.QEvent):
eventType = QtCore.QEvent.Type(QtCore.QEvent.registerEventType())
@ -60,3 +77,7 @@ class ButtonEvent(QtCore.QEvent):
return self.playerno
nobodyColor = QtGui.QColor(128, 128, 128)
# yaml dumpers/loaders
yaml.add_representer(Player, Player._yaml_representer)
yaml.add_constructor(u'!player', Player._yaml_constructor)

View File

@ -31,12 +31,27 @@ if __name__ == '__main__':
os.mkfifo(args.fifo)
except OSError as e:
print("Error: Could not create fifo: %s" % (str(e),), file=sys.stderr)
sys.exit(1)
questions = Questions(args.questions)
gamestate = GameState(args.savedir)
# start gui
app = QtGui.QApplication([])
# create or load gamestate
gamestate = None
if args.gamestate:
sstream = None
try:
sstream = open(args.gamestate, "r")
except IOError as e:
print("Error: Could not load gamestate: %s" % (str(e),), file=sys.stderr)
sys.exit(1)
gamestate = GameState.load(sstream, args.savedir)
else:
gamestate = GameState(args.savedir)
# create board
board = SeopardyGame(questions, gamestate)
board.show()
app.exec_()