Browse Source

GameState loading/saving works

Sebastian Lohff 6 years ago
parent
commit
d26c7a3a88
4 changed files with 118 additions and 20 deletions
  1. 36
    13
      game.py
  2. 45
    6
      gamestate.py
  3. 21
    0
      player.py
  4. 16
    1
      seopardy.py

+ 36
- 13
game.py View File

@@ -13,9 +13,11 @@ class SeopardyGame(QtGui.QWidget):
13 13
 		self.questions = questions
14 14
 		self.gamestate = gamestate
15 15
 		#self.players = [Player.gen_player(i, parent=self) for i in range(1, 4)]
16
-		self.players = []
17
-		for i in range(3):
18
-			self.add_player()
16
+		self.players = self.gamestate.get_players()
17
+		if len(self.players) == 0:
18
+			for i in range(3):
19
+				self.add_player()
20
+
19 21
 		self.currentPlayer = None
20 22
 
21 23
 		self._inOtherWindow = False
@@ -23,7 +25,8 @@ class SeopardyGame(QtGui.QWidget):
23 25
 		self.showFullScreen()
24 26
 
25 27
 		# initiate starting the game!
26
-		QtCore.QCoreApplication.postEvent(self, GameStartEvent())
28
+		if self.gamestate.get_state() == "start":
29
+			QtCore.QCoreApplication.postEvent(self, GameStartEvent())
27 30
 
28 31
 	def add_player(self):
29 32
 		self.players.append(Player.gen_player(len(self.players)+1, self))
@@ -40,22 +43,22 @@ class SeopardyGame(QtGui.QWidget):
40 43
 
41 44
 		# create board
42 45
 		#board = QtGui.QGridLayout(6, len(self.questions.get_sections()))
43
-		board = QtGui.QGridLayout()
44
-		board.setSizeConstraint(QtGui.QLayout.SetMaximumSize)
46
+		self.board = QtGui.QGridLayout()
47
+		self.board.setSizeConstraint(QtGui.QLayout.SetMaximumSize)
45 48
 		for i, sec in enumerate(self.questions.get_sections()):
46 49
 			seclabel = QtGui.QLabel(sec, alignment=QtCore.Qt.AlignCenter)
47 50
 			seclabel.setStyleSheet("QLabel { font-size: 30px; }")
48
-			board.addWidget(seclabel, 0, i)
51
+			self.board.addWidget(seclabel, 0, i)
49 52
 			for j in range(5):
50 53
 				b = QtGui.QPushButton(str((j+1)*100))
51 54
 				b.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
52 55
 				b.setAutoDefault(False)
53
-				b.setStyleSheet("QPushButton { font-size: 60px; }")
56
+				#b.setStyleSheet("QPushButton { font-size: 60px; }")
54 57
 				b.installEventFilter(FocusKeyGrabber(i+1, j+1, self))
55 58
 				b.clicked.connect(lambda sec=sec, j=j: self.go_to_question(sec, j+1))
56
-				board.addWidget(b, j+1, i)
57
-		layout.addLayout(board)
58
-		self.board = board
59
+				self.board.addWidget(b, j+1, i)
60
+				self._restyle_button(sec, j+1, self.gamestate.get_answers(sec, j+1))
61
+		layout.addLayout(self.board)
59 62
 
60 63
 		# create player bar
61 64
 		self.playerBar = QtGui.QHBoxLayout()
@@ -81,6 +84,8 @@ class SeopardyGame(QtGui.QWidget):
81 84
 				x = PlayerStartWindow(self.players, self)
82 85
 				x.exec_()
83 86
 				self._inOtherWindow = False
87
+				self.gamestate.set_state("playing")
88
+				self.gamestate.save()
84 89
 
85 90
 			return True
86 91
 		else:
@@ -136,6 +141,7 @@ class SeopardyGame(QtGui.QWidget):
136 141
 			self._set_player_points(newAnswers)
137 142
 			self.gamestate.set_answers(section, number, newAnswers)
138 143
 			self._restyle_button(section, number, newAnswers)
144
+			self.gamestate.save()
139 145
 
140 146
 	def show_victory_window(self):
141 147
 			self._inOtherWindow = True
@@ -176,6 +182,23 @@ class SeopardyGame(QtGui.QWidget):
176 182
 		# restyle the button
177 183
 		self._restyle_button(section, number, answers)
178 184
 
185
+		# safe current gamestate
186
+		self.gamestate.save()
187
+
188
+		# check if we are done
189
+		foundUnanswered = False
190
+		for sec in self.questions.get_sections():
191
+			for j in range(5):
192
+				boardAnswers = self.gamestate.get_answers(sec, j+1)
193
+				if boardAnswers is None or not answers.is_answered():
194
+					foundUnanswered = True
195
+			if foundUnanswered:
196
+				break
197
+
198
+		if not foundUnanswered:
199
+			self.show_victory_window()
200
+
201
+
179 202
 	def _set_player_points(self, answers, rollback=False):
180 203
 		for i, (player, correct) in enumerate(answers.get_tries()):
181 204
 			prefix = 1
@@ -199,8 +222,8 @@ class SeopardyGame(QtGui.QWidget):
199 222
 		btnstr = ""
200 223
 		btncolor = None
201 224
 
202
-		if not answers.is_answered():
203
-			btn.setText(str(answers.points()))
225
+		if answers is None or not answers.is_answered():
226
+			btn.setText(str(qno*100))
204 227
 			btn.setStyleSheet("QPushButton { font-size: 60px; }")
205 228
 			return
206 229
 

+ 45
- 6
gamestate.py View File

@@ -1,6 +1,8 @@
1 1
 from __future__ import print_function
2 2
 
3
+import datetime
3 4
 import os
5
+import yaml
4 6
 from collections import defaultdict
5 7
 
6 8
 class GameState(object):
@@ -10,17 +12,30 @@ class GameState(object):
10 12
 	savedir: dir to save gamestate into, should be overwritable
11 13
 	board: dict of section with list of questions
12 14
 	"""
15
+	GAMESTATE = ["start", "playing", "end"]
16
+
13 17
 	def __init__(self, savedir):
14 18
 		self.savedir = savedir
15 19
 
16
-		self._board = defaultdict(lambda: [None]*5)
17
-		self._players = None
20
+		#self._board = defaultdict(lambda: [None]*5)
21
+		self._board = defaultdict(_mk_empty_board_column)
22
+		self._players = []
23
+		self._state = self.GAMESTATE[0]
18 24
 
19 25
 		if not os.path.exists(self.savedir):
20 26
 			os.mkdir(self.savedir)
21 27
 		elif not os.path.isdir(self.savedir):
22 28
 			raise ValueError("'%s' is not a directory but something else!" % self.savedir)
23 29
 
30
+
31
+	def set_state(self, state):
32
+		if state not in self.GAMESTATE:
33
+			raise ValueError("'%s' is not a valid gamestate, valid choices are %s" % (state, self.GAMESTATE))
34
+		self._state = state
35
+
36
+	def get_state(self):
37
+		return self._state
38
+
24 39
 	def set_answers(self, section, qnumber, answers):
25 40
 		self._board[section][qnumber-1] = answers
26 41
 
@@ -28,14 +43,38 @@ class GameState(object):
28 43
 		return self._board[section][qnumber-1]
29 44
 
30 45
 	def set_players(self, players):
31
-		self.players = players
46
+		self._players = players
47
+
48
+	def get_players(self):
49
+		return self._players
50
+
51
+	def _make_structure(self):
52
+		return {
53
+			"state": self._state,
54
+			"players": self._players,
55
+			"board": self._board
56
+		}
32 57
 
33 58
 	def save(self):
34
-		pass
59
+		fname = datetime.datetime.now().strftime("seopardy.%Y-%m-%d-_%H:%M:%S.save")
60
+		fstream = open("%s/%s" % (self.savedir, fname), "w")
61
+		yaml.dump(self._make_structure(), fstream)
62
+		fstream.close()
35 63
 
36 64
 	@classmethod
37
-	def load(clazz, fpath):
38
-		pass
65
+	def load(clazz, sstream, savedir):
66
+		gs = clazz(savedir)
67
+		data = yaml.load(sstream)
68
+		gs._state = data["state"]
69
+		gs._players = data["players"]
70
+		gs._board = data["board"]
71
+
72
+		return gs
73
+
74
+def _mk_empty_board_column():
75
+	""" We can't use a lambda here, as we want the default dict to be
76
+		easily serializeable by yaml. """
77
+	return [None]*5
39 78
 
40 79
 class QuestionAnswers(object):
41 80
 	def __init__(self, section, qnumber, dj_points=None):

+ 21
- 0
player.py View File

@@ -1,5 +1,6 @@
1 1
 from __future__ import print_function
2 2
 
3
+import yaml
3 4
 from PySide import QtGui, QtCore
4 5
 
5 6
 class Player(QtGui.QWidget):
@@ -9,6 +10,7 @@ class Player(QtGui.QWidget):
9 10
 		("Baz",   QtGui.QColor(0,     0, 255)),
10 11
 		("Blubb", QtGui.QColor(0,   255, 255)),
11 12
 		("Murr",  QtGui.QColor(255,   0, 255)),
13
+		("Maunz", QtGui.QColor(255, 255,   0)),
12 14
 	]
13 15
 
14 16
 	def __init__(self, name, color, points=0, parent=None):
@@ -46,6 +48,21 @@ class Player(QtGui.QWidget):
46 48
 
47 49
 		return clazz(*clazz.DEFAULT_PLAYERS[num-1], parent=parent)
48 50
 
51
+	@classmethod
52
+	def _yaml_representer(clazz, dumper, data):
53
+		#def __init__(self, name, color, points=0, parent=None):
54
+		return dumper.represent_mapping(u'!player', {
55
+							'name': data.name,
56
+							'points': data.points,
57
+							'color': data.color.name()
58
+						})
59
+
60
+	@classmethod
61
+	def _yaml_constructor(clazz, loader, node):
62
+		pdict = loader.construct_mapping(node)
63
+		pdict["color"] = QtGui.QColor(pdict["color"])
64
+		return Player(**pdict)
65
+
49 66
 
50 67
 class ButtonEvent(QtCore.QEvent):
51 68
 	eventType = QtCore.QEvent.Type(QtCore.QEvent.registerEventType())
@@ -60,3 +77,7 @@ class ButtonEvent(QtCore.QEvent):
60 77
 		return self.playerno
61 78
 
62 79
 nobodyColor = QtGui.QColor(128, 128, 128)
80
+
81
+# yaml dumpers/loaders
82
+yaml.add_representer(Player, Player._yaml_representer)
83
+yaml.add_constructor(u'!player', Player._yaml_constructor)

+ 16
- 1
seopardy.py View File

@@ -31,12 +31,27 @@ if __name__ == '__main__':
31 31
 		os.mkfifo(args.fifo)
32 32
 	except OSError as e:
33 33
 		print("Error: Could not create fifo: %s" % (str(e),), file=sys.stderr)
34
+		sys.exit(1)
34 35
 
35 36
 	questions = Questions(args.questions)
36
-	gamestate = GameState(args.savedir)
37 37
 
38 38
 	# start gui
39 39
 	app = QtGui.QApplication([])
40
+
41
+	# create or load gamestate
42
+	gamestate = None
43
+	if args.gamestate:
44
+		sstream = None
45
+		try:
46
+			sstream = open(args.gamestate, "r")
47
+		except IOError as e:
48
+			print("Error: Could not load gamestate: %s" % (str(e),), file=sys.stderr)
49
+			sys.exit(1)
50
+		gamestate = GameState.load(sstream, args.savedir)
51
+	else:
52
+		gamestate = GameState(args.savedir)
53
+
54
+	# create board
40 55
 	board = SeopardyGame(questions, gamestate)
41 56
 	board.show()
42 57
 	app.exec_()

Loading…
Cancel
Save