Commits

larry committed a6e06be

Big huge savestate rewrite. All but one of the __getstate__/__setstate__
calls are gone; we now rely on Python being smart for us.

Comments (0)

Files changed (1)

 
 savegame_revision = 1
 
+series = None
+game = None
+hand = None
+
 class IllegalMove(Exception):
 	def __init__(self, card, reason=None):
 		if isinstance(card, str):
 		raise IllegalMove(self, message)
 
 	def must_draw_first(self, player):
-		if not player.hand.deck:
+		if not hand.deck:
 			return
 		if len(player.cards) < 7:
 			self.illegal(" yet, must draw first")
 
 	def not_on_other(self, player, playee):
-		if playee not in (player, player.hand.discard):
+		if playee not in (player, hand.discard):
 			self.illegal(" on other players")
 
 	def not_on_self(self, player, playee):
 			self.illegal(" on yourself")
 
 	def on_discard(self, playee):
-		return playee == playee.hand.discard
+		return playee == hand.discard
 
 	def not_on_discard(self, playee):
 		if self.on_discard(playee):
 			return
 
 		mileage = playee.mileage()
-		limit = 1000 if playee.hand.extended else 700
+		limit = 1000 if hand.extended else 700
 		if ((mileage < limit) and ((mileage + self.distance) > limit)):
 			self.illegal(", it would take you over " + str(limit))
 
 		return playee.safeties
 
 	def is_coup_fouree(self, playee):
-		hand = playee.hand
 		if not hand.plays:
 			return False
 		last_play = hand.plays[-1]
 			self.must_draw_first(player)
 
 	def played(self, player, playee):
-		hand = player.hand
 		if self.is_coup_fouree(playee):
 			last_card = hand.plays[-1].card
 			pile = playee.speed_pile \
 		if (isinstance(top, Remedy)
 			and (top is not roll)
 			):
-			self.illegal(", can't play a hazard on a remedy (" + str(top) + ") (unless they've played the safety")
+			self.illegal(", can't play a hazard on a remedy (" + str(top) + ") (unless they've played the safety)")
 
 
 class Stop(Hazard):
 	return card
 
 
-def pickle_pile(pile):
-	return [card_to_string[c] for c in pile]
-
-def unpickle_pile(pickled_pile):
-	return [string_to_card[s] for s in pickled_pile]
+#def pickle_pile(pile):
+#	return [card_to_string[c] for c in pile]
+#
+#def unpickle_pile(pickled_pile):
+#	return [string_to_card[s] for s in pickled_pile]
 
 
 class PlayerBase:
 	def __init__(self):
-		self.unpickle(None, None)
 		self.total_score = 0
 
+	def game_end(self, winner):
+		pass
+
 	def __repr__(self):
 		return "".join(("<", self.__class__.__name__ ," ", self.name, ">"))
 
-	def __getstate__(self):
-		return {
-			"name" : self.name,
-			"total_score" : self.total_score,
-			}
-
-	def __setstate__(self, state):
-		self.name = state["name"]
-		self.total_score = state["total_score"]
-
-	def unpickle(self, game, hand):
-		self.game = game
-		self.hand = hand
-
-	def hand_start(self, hand):
-		self.hand = hand
+	def hand_start(self):
+		pass
+
+	def hand_end(self, winner):
+		pass
 
 	def is_legal(self, card, playee=None):
 		pass
 	def turn(self):
 		pass
 	
-	def game_end(self, winner):
-		pass
-
-	def hand_end(self, winner):
-		pass
-
-
-def pickle_player(player):
-	global series
-	if player is None:
-		return None
-	if series.game and series.game.hand and player == series.game.hand.discard:
-		return "discard"
-	return series.game.players.index(player)
-
-def unpickle_player(player):
-	global series
-	if player is None:
-		return None
-	if player == "discard":
-		assert series.game and series.game.hand and series.game.hand.discard
-		return series.game.hand.discard
-	if isinstance(player, int):
-		return series.game.players[player]
-	return player
+
 
 class Play:
 
 		self.player = player
 		self.playee = playee
 
-	def __getstate__(self):
-		card = card_to_string[self.card]
-		player = pickle_player(self.player)
-		playee = pickle_player(self.playee)
-		r = {"card" : card, "player": player, "playee": playee}
-		return r
-
-	def __setstate__(self, state):
-		self.card = string_to_card[state["card"]]
-		self.player = state["player"]
-		self.playee = state["playee"]
-
-	def unpickle(self):
-		self.player = unpickle_player(self.player)
-		self.playee = unpickle_player(self.playee)
-
 
 
 class Discard(PlayerBase):
 
-	def hand_start(self, hand):
-		super().hand_start(hand)
+	name = "discard pile"
+
+	def __init__(self):
+		super().__init__()
+
+	def hand_start(self):
+		super().hand_start()
 		self.pile = []
 
-	def __init__(self):
-		self.name = "discard pile"
-
-	def __getstate__(self):
-		return {"pile" : pickle_pile(self.pile)}
-
-	def __setstate__(self, state):
-		self.pile = unpickle_pile(state["pile"])
-
 	def played(self, card, player):
 		self.pile.append(convert_card(card))
-		self.hand.plays.append(Play(card, player, self))
+		hand.plays.append(Play(card, player, self))
 
 
 class Player(PlayerBase):
 
-	def hand_start(self, hand):
-		super().hand_start(hand)
+	def hand_start(self):
+		super().hand_start()
 		self.cards = []
 		self.mileage_pile = []
 		self.battle_pile = []
 		self.safeties = []
 		self.coup_fourres = []
 
-	def __getstate__(self):
-		d = { "super" : super().__getstate__() }
-		for attr in "cards mileage_pile battle_pile speed_pile safeties coup_fourres".split():
-			d[attr] = pickle_pile(getattr(self, attr))
-		return d
-
-	def __setstate__(self, state):
-		super().__setstate__(state["super"])
-		for attr in "cards mileage_pile battle_pile speed_pile safeties coup_fourres".split():
-			setattr(self, attr, unpickle_pile(state[attr]))
-
 	def draw(self, card=None):
 		assert len(self.cards) <= 7
-		if not self.hand.deck:
+		if not hand.deck:
 			return None
 
 		if card is None:
-			card = self.hand.deck.pop()
+			card = hand.deck.pop()
 		else:
 			card = convert_card(card)
-			self.hand.deck.remove(card)
+			hand.deck.remove(card)
 		self.cards.append(card)
 		return card
 
 	def discard(self, card):
-		self.play(card, self.hand.discard)
+		self.play(card, hand.discard)
 
 	def is_legal(self, card, playee=None):
 		if playee is None:
 	# self is the playee
 	def played(self, card, player):
 		convert_card(card).played(player, self)
-		self.hand.plays.append(Play(card, player, self))
+		hand.plays.append(Play(card, player, self))
 
 	def won(self):
 		mileage = self.mileage()
 		return ((mileage == 1000)
-			or ((mileage == 700) and (not self.hand.extended)))
+			or ((mileage == 700) and (not hand.extended)))
 
 	def other(self):
-		return self.game.players[1 - int(self.game.players[1] == self)]
+		return game.players[1 - int(game.players[1] == self)]
 
 	def normalized_battle_top(self):
 		"""
 			score(400, "trip complete")
 			if total > 700:
 				score(200, "extension")
-			if not len(self.hand.deck):
+			if not len(hand.deck):
 				score(300, "delayed action")
 			if not self.two_hundreds():
 				score(300, "safe trip (no 200s)")
 	She extends if half the cards remain in the draw deck.
 	"""
 
+	name = "Rosey"
+
 	def __init__(self):
 		super().__init__()
-		self.name = "Rosey"
 
 	def turn(self):
 		self.draw()
 				self.play(card, playee)
 				print("    du-uh, played", card, "on", "herself" if playee == self else "you")
 				if self.won() and self.mileage() == 700:
-					extending = len(self.hand.deck) > (len(self.hand.original_deck) // 2)
+					extending = len(hand.deck) > (len(hand.original_deck) // 2)
 					if extending:
 						print()
 						print("    ------------------------")
 						print("    du-uh, extending to 1000")
 						print("    ------------------------")
 						print()
-						self.hand.extended = True
+						hand.extended = True
 					else:
 						print("    du-uh, not extending")
 				break
    	* smart about playing mileage >= 550
 	"""
 
-	def __init__(self):
-		super().__init__()
-		self.name = "Norman"
-		self.unpickle(None, None)
-
-	def unpickle(self, game, hand):
-		super().unpickle(game, hand)
-		def print_fn(*a):
-			print("    hmm,", *a)
-		self.print = print_fn
-		def debug_fn(*a):
-			print("        //", *a)
-		self.debug = debug_fn
-		def silent(*a):
-			pass
-		# self.debug = silent
-
-	def hand_start(self, hand):
-		super().hand_start(hand)
+	name = "Norman"
+
+	def print(self, *a):
+		print("    hmm,", *a)
+
+	def debug(self, *a):
+		print("        //", *a)
+
+
+	def hand_start(self):
+		super().hand_start()
 		self.safety_countdown = 0
 		self.play_safety = False
 		self.discardables = set()
 
-	def __getstate__(self):
-		d = {"super" : super().__getstate__()}
-		for attr in "safety_countdown play_safety discardables".split():
-			d[attr] = getattr(self, attr)
-		return d
-
-	def __setstate__(self, state):
-		super().__setstate__(state["super"])
-		for attr in "safety_countdown play_safety discardables".split():
-			setattr(self, attr, state[attr])
-
 	def check_for_coup_fouree(self, debug):
-		if not self.hand.plays:
+		if not hand.plays:
 			return False
 
-		play = self.hand.plays[-1]
+		play = hand.plays[-1]
 		if not ((play.playee == self)
 			and isinstance(play.card, Hazard)):
 			return False
 		other_safeties = self.other().safeties
 		extend_if = (
 			# we have half or more of the cards remining in the draw deck
-			(len(self.hand.deck) > (len(self.hand.original_deck) // 2))
+			(len(hand.deck) > (len(hand.original_deck) // 2))
 			# and they don't have right_of_way
 			and (right_of_way not in other_safeties)
 			# or 2 or more safeties
 				print("    hmm, extending to 1000")
 				print("    ----------------------")
 				print()
-				self.hand.extended = True
+				hand.extended = True
 				return True
 			else:
 				print("    hmm, not extending")
 			return None
 
 		mileage = self.mileage()
-		limit = 1000 if self.hand.extended else 700
+		limit = 1000 if hand.extended else 700
 
 		# if we're not near winning, play biggest card.
 		if mileage < (limit - 150):
 
 	def play(self, card, playee=None):
 		addendum = ""
-		if playee == self.hand.discard:
+		if playee == hand.discard:
 			verb = "discarding"
 		else:
 			verb = "playing"
 
 		all_my_safeties = set(self.safeties) | set((x for x in self.cards if isinstance(x, Safety)))
 
-		limit = 1000 if self.hand.extended else 700
+		limit = 1000 if hand.extended else 700
 		mileage_so_far = self.mileage()
 		maxed_out_200s = self.two_hundreds() == 2
 		debug("cards", " ".join([card.abbreviation for card in self.cards]))
 
 		if we_can_win:
 			# do we have the mileage card we'd need to play?
-			limit = 1000 if self.hand.extended else 700
+			limit = 1000 if hand.extended else 700
 			card_to_win = convert_card(limit - mileage_so_far)
 			we_can_win = card_to_win in mileage
 			debug("P0.c", card_to_win, we_can_win)
 		if we_can_win:
 			# would we want to extend?  and, if so, would we have
 			# to play safeties in order to win?
-			extending = (not self.hand.extended) and self._decide_to_extend()
+			extending = (not hand.extended) and self._decide_to_extend()
 			if (extending and safeties_needed_to_win):
 				# if so, hold off on winning unless the
 				# other player is in striking distance of winning.
 						next.add(drew)
 				safeties_to_play = next
 			debug("P0.g")
-			was_unextended = not self.hand.extended
+			was_unextended = not hand.extended
 			self.play(card_to_win)
-			assert self.won() or (was_unextended and self.hand.extended)
+			assert self.won() or (was_unextended and hand.extended)
 			return
 
 		################################################################
 			else:
 				self.safety_countdown = safety_countdown
 		else:
-			cards_remaining = len(self.hand.deck)
+			cards_remaining = len(hand.deck)
 			self.safety_countdown = random.randint(int(cards_remaining * 0.05), int(cards_remaining * 0.1))
 
 		###################################################
 			# then we have 4 or fewer cards in our hand,
 			# which means the deck is empty,
 			# which means I don't bother drawing.
-			assert not self.hand.deck
+			assert not hand.deck
 			for card in safeties:
 				debug("P9.a")
 				self.play(card)
 	and calculates odds.
 	"""
 
-	def __init__(self, game, name=None):
+	name = "Moriarty"
+
+	def __init__(self):
 		super().__init__()
-		self.name = "Moriarty"
 
 	def odds_that_opponent_has_card(self, card, on_next_turn=True):
 		# If there are D cards in the deck,
 
 		self.update_seen()
 
-		remaining = self.hand.total_cards[card] - self.hand.seen_cards[card]
+		remaining = hand.total_cards[card] - hand.seen_cards[card]
 		if not remaining:
 			return 0
 
-		hand_size = len(self.other().cards) + bool(self.hand.deck and on_next_turn)
-		all_cards = len(self.hand.deck) + hand_size + 1  # the + 1 fixes off-by-ones for range
+		hand_size = len(self.other().cards) + bool(hand.deck and on_next_turn)
+		all_cards = len(hand.deck) + hand_size + 1  # the + 1 fixes off-by-ones for range
 
 		# special case: if we only care about one card, the math is easy.
 		if remaining == 1:
 
 	tracked_hazards = (accident, flat_tire, out_of_gas, speed_limit)
 
-	def hand_start(self, hand):
-		super().hand_start(hand)
+	def hand_start(self):
+		super().hand_start()
 		self.scanned = 0
 
 		# maximum # of that card we should hold in our hand
 		self.maximums[right_of_way] = cards_total[speed_limit] + cards_total[stop]
 
 	def update_scan(self):
-		self.hand.update_scan()
+		hand.update_scan()
 		other = self.other
 		discard = hand.discard
-		for play in self.hand.plays[self.scanned:]:
+		for play in hand.plays[self.scanned:]:
 			if play.player is self:
 				continue
 			card = play.card
 						self.maximums[roll] -= 1
 				elif card is stop:
 					self.maximums[roll] -= 1
-		self.scanned = len(self.hand.plays)
+		self.scanned = len(hand.plays)
 
 
 	def manage_25_and_75(self, weights):
 				decrement = 1
 			self.maximums[card.remedy] -= decrement
 
-			outstanding_hazards = self.hand.total_cards[card.hazard] - self.hand.seen_cards[card.hazard]
+			outstanding_hazards = hand.total_cards[card.hazard] - hand.seen_cards[card.hazard]
 			self.maximums[roll] -= outstanding_hazards
 			if card is right_of_way:
-				outstanding_stops = self.hand.total_cards[stop] - self.hand.seen_cards[stop]
+				outstanding_stops = hand.total_cards[stop] - hand.seen_cards[stop]
 		elif card is stop:
 			self.maximums[roll] -= 1
 			self.maximums[right_of_way] -= 1
 	def turn(self):
 		self.update_scan()
 
-		seen = self.hand.cards_seen
-		total = self.hand.cards_total
+		seen = hand.cards_seen
+		total = hand.cards_total
 
 		# discard remedies and play safeties
 		# for hazards that have all been played
 	"""
 
 	def __init__(self, constructor, name=None):
-		self.name = name
 		self.constructor = constructor
+		self.name = name or constructor.name
 		self.total_score = 0
 		self.games_won = 0
 		self.hands_won = 0
 		self.highest_score = 0
 		self.shutouts = 0
 
-	attributes = "name total_score hands_won games_won highest_score shutouts".split()
-
-	def __getstate__(self):
-		d = { "constructor": self.constructor.__name__ }
-		for attr in self.attributes:
-			d[attr] = getattr(self, attr)
-		return d
-
-	def __setstate__(self, state):
-		for attr in self.attributes:
-			setattr(self, attr, state[attr])
-		self.constructor = {
-			"AverageComputerPlayer" : AverageComputerPlayer,
-			"DumbComputerPlayer" : DumbComputerPlayer,
-			"Player" : Player,
-			"StdioPlayer" : StdioPlayer,
-			}[state["constructor"]]
-
 
 savepath = os.path.expanduser("~/.mille.savegame")
 
 	"""
 
 	def __init__(self):
-		self.game = None
 		self.players = []
 		self.games_played = 0
 		self.hands_played = 0
 		global savegame_revision
 		d = {
 			"savegame_revision": savegame_revision,
-			"game" : pickle.dumps(self.game),
+			"random" : random.getstate(),
+			"game" : pickle.dumps(game),
+			"hand" : pickle.dumps(hand),
 			"players" : [pickle.dumps(p) for p in self.players],
 		}
 		for attr in self.attributes:
 		return d
 
 	def __setstate__(self, state):
+		global game
+		global hand
 		if savegame_revision != state["savegame_revision"]:
 			raise RuntimeError("can't load savegame, delete " + savepath + " to start a new game")
+		random.setstate(state["random"])
 		self.players = [pickle.loads(s) for s in state["players"]]
-		self.game = pickle.loads(state["game"])
+		game = pickle.loads(state["game"])
+		hand = pickle.loads(state["hand"])
 		for attr in self.attributes:
 			setattr(self, attr, state.get(attr))
 
-	def unpickle(self):
-		self.game.unpickle()
-
-	def add_player(self, s):
-		self.players.append(SeriesPlayer(s))
+	def add_player(self, constructor):
+		self.players.append(SeriesPlayer(constructor))
 
 	def save_game(self):
 		with open(savepath, "wb") as f:
 			pickle.dump(self, f)
 
 	def start_game(self):
-		if not self.game:
-			self.game = Game()
+		global game
+		if not game:
+			game = Game()
 			for p in self.players:
-				self.game.add_player(p.constructor())
-			self.game.start_hand()
-			self.unpickle()
+				o = p.constructor()
+				game.add_player(o)
+			game.start_hand()
 
 	def play(self):
+		global game
 
 		try:
 			while True:
 				if self.state == "game end":
-					winner = unpickle_player(self.winner)
-					assert self.game
-					for player in self.game.players:
+					# winner = unpickle_player(self.winner)
+					winner = self.winner
+					if winner is not None:
+						winner = game.players[winner]
+					assert game
+					for player in game.players:
 						player.game_end(winner)
 					self.state = None
 					self.winner = None
-					self.game = None
+					game = None
 					continue
 
 				self.start_game()
-				winner = self.game.play()
+				winner = game.play()
+				if winner is not None:
+					winner = game.players.index(winner)
 
 				self.state = "game end"
-				self.winner = pickle_player(winner)
+				# self.winner = pickle_player(winner)
+				self.winner = winner
 
 				series.games_played += 1
-				for p, game_player in zip(self.players, self.game.players):
+				for p, game_player in zip(self.players, game.players):
 					p.total_score += game_player.total_score
 					p.highest_score = max(p.highest_score, game_player.total_score)
 					if game_player == winner:
 class Game:
 	def __init__(self):
 		self.players = []
-		self.hand = None
 		self.round = 0
 		self.state = None
 		self.winner = None
 	def add_player(self, player):
 		self.players.append(player)
 
-	attributes = "over round state winner".split()
-
-	def __getstate__(self):
-		d = {
-			"random" : random.getstate(),
-			"players" : [pickle.dumps(p) for p in self.players],
-			"hand" : pickle.dumps(self.hand),
-			}
-		for attr in self.attributes:
-			d[attr] = getattr(self, attr)
-		return d
-
-	def __setstate__(self, state):
-		random.setstate(state["random"])
-		self.players = [pickle.loads(p) for p in state["players"]]
-		self.hand = pickle.loads(state["hand"])
-		if self.hand:
-			self.hand.game = self
-		for attr in self.attributes:
-			setattr(self, attr, state.get(attr))
-
-	def unpickle(self):
-		if self.hand:
-			self.hand.unpickle()
-		for p in self.players:
-			p.unpickle(self, self.hand)
-
 	def start_hand(self):
-		if not self.hand:
-			self.hand = Hand(self)
+		global hand
+		if not hand:
+			hand = Hand()
 
 	def play(self):
+		global hand
+
 		self.original_players = list(self.players)
 
 		while True:
 			if self.state == "hand end":
-				hand_winner = unpickle_player(self.winner)
+				# hand_winner = unpickle_player(self.winner)
+				hand_winner = self.winner
+				if hand_winner is not None:
+					hand_winner = game.players[hand_winner]
 
 				game_winner = None
 				if any((p for p in self.players if p.total_score >= 5000)):
 					player.hand_end(hand_winner)
 
 				self.round += 1
-				self.hand = None
+				hand = None
 
 				self.state = None
 				self.winner = None
 				continue
 
 			self.start_hand()
-			self.hand.play()
+			hand.play()
 
 			p1, p2 = self.players
 			if p1.mileage() in {700, 1000}:
 			else:
 				winner = None
 
-			self.winner = pickle_player(winner)
+			if winner:
+				winner = game.players.index(winner)
+
+			# self.winner = pickle_player(winner)
+			self.winner = winner
 			self.state = "hand end"
 			series.hands_played += 1
 
 
 class Hand:
 
-	def __init__(self, game):
-
-		self.game = game
+	def __init__(self):
 
 		self.discard = Discard()
 		self.extended = False
 		extend([roll] * 14)
 		append(right_of_way)
 
-		assert len(self.game.players) in {2, 3, 4, 6}
-		if len(self.game.players) < 4:
+		assert len(game.players) in {2, 3, 4, 6}
+		if len(game.players) < 4:
 			# remove one of each hazard
 			hazards = set()
 			new_deck = []
 
 		random.shuffle(self.deck)
 
-		for player in self.game.players:
-			player.hand_start(self)
+		for player in game.players:
+			player.hand_start()
 			player.cards = self.deck[0:6]
 			player.cards.sort(reverse=True)
 			del self.deck[0:6]
 
-		self.discard.hand_start(self)
+		self.discard.hand_start()
 
 		self.plays = []
 
 		self.cards_total = Counter(self.original_deck)
 
 		# alternate who starts first
-		players = self.game.players
-		self.current_player = players[self.game.round % len(players)]
-
-	def __getstate__(self):
-		self.update_seen()
-		if self.current_player:
-			current_player = self.game.players.index(self.current_player)
-		else:
-			current_player = None
-
-		return {
-			"current_player": current_player,
-			"discard" : pickle.dumps(self.discard),
-			"deck" : pickle_pile(self.deck),
-			"original_deck" : pickle_pile(self.original_deck),
-			"extended" : self.extended,
-			"cards_seen" : [(card_to_string[c], v) for c, v in self.cards_seen.items()],
-			"cards_total" : [(card_to_string[c], v) for c, v in self.cards_total.items()],
-			"plays" : [pickle.dumps(p) for p in self.plays],
-		}
-
-	def __setstate__(self, state):
-		self.current_player = state["current_player"]
-		self.discard = pickle.loads(state["discard"])
-		self.deck = unpickle_pile(state["deck"])
-		self.original_deck = unpickle_pile(state["original_deck"])
-		self.extended = state["extended"]
-		self.cards_seen = Counter(dict((string_to_card[s], v) for s, v in state["cards_seen"]))
-		self.cards_total = Counter(dict((string_to_card[s], v) for s, v in state["cards_total"]))
-		self.plays = [pickle.loads(s) for s in state["plays"]]
-		self.plays_scanned = len(self.plays)
-
-	def unpickle(self):
-		if isinstance(self.current_player, int):
-			self.current_player = self.game.players[self.current_player]
-		self.discard.unpickle(self.game, self)
-		for play in self.plays:
-			play.unpickle()
+		self.current_player = game.round % len(game.players)
 
 	def update_seen(self):
 		for play in self.plays[self.plays_scanned:]:
 		self.plays_scanned = len(self.plays)
 
 	def play(self):
-		p1, p2 = self.game.players
-
-		players = itertools.cycle(self.game.players)
+		p1, p2 = game.players
+
+		players = itertools.cycle(range(len(game.players)))
 
 		allow_seven = True
 		def check_cards(player, allow_seven=False):
 				assert len(player.cards) <= 6
 
 		winner = None
-		if not self.current_player:
-			self.current_player = next(players)
-		else:
-			assert self.current_player in self.game.players
-			while True:
-				p = next(players)
-				if p == self.current_player:
-					break
-
-		print("Game #" + str(series.games_played + 1) + ",", "Hand #" + str(self.game.round + 1) + ",", self.current_player.name, "plays next.")
+		assert self.current_player < len(game.players)
+		while True:
+			p = next(players)
+			if p == self.current_player:
+				break
+
+		print("Game #" + str(series.games_played + 1) + ",", "Hand #" + str(game.round + 1) + ",", game.players[self.current_player].name, "plays next.")
 
 		while True:
 			if not self.deck:
 				# are there any remaining plausible moves?
 				playable = None
-				for player in self.game.players:
+				for player in game.players:
 					if playable:
 						break
 					other = player.other()
 					# no more plays, stop
 					break
 
-			player = self.current_player
+			player = game.players[self.current_player]
 
 			if player.cards:
 				check_cards(player, allow_seven)
 			self.current_player = next(players)
 
 		if winner and (not winner.other().mileage()):
-			series.players[series.game.players.index(winner)].shutouts += 1
-
-		for p in self.game.players:
+			series.players[game.players.index(winner)].shutouts += 1
+
+		for p in game.players:
 			p.total_score += p.score().score
 
 	ScoresResult = namedtuple("ScoresResult", "winner lost_by_points")
 		all_totals = []
 		winner = None
 		divider = "--------------------------------"
-		for p in self.game.original_players:
+		for p in game.original_players:
 			score, comments = p.score(as_if_won)
 			comments = ["    " + x for x in comments]
 			comments.insert(0, divider)
 		series.add_player(Player)
 		series.add_player(Player)
 		series.start_game()
-		game = self.game = series.game
-		hand = self.hand = series.game.hand
+
 		self.p1, self.p2 = game.players
 		self.p1.name = "p1"
 		self.p2.name = "p2"
 		assert len(cards) in {6, 7}
 		cards = [convert_card(card) for card in cards]
 		for card in cards:
-			self.hand.deck.remove(card)
+			hand.deck.remove(card)
 		player.cards = list(cards)
 
 	def illegal(self, player, card, playee=None):
 		self.p2.draw_and_play(hazard, self.p1)
 
 		self.p1.play(safety)
-		self.assertEqual(len(self.hand.discard.pile), 1)
-		self.assertEqual(self.hand.discard.pile[0], hazard)
+		self.assertEqual(len(hand.discard.pile), 1)
+		self.assertEqual(hand.discard.pile[0], hazard)
 		self.assertIn(safety, self.p1.safeties)
 		self.assertIn(safety, self.p1.coup_fourres)
 
 """)
 
 def print_scores(as_if_won=False):
-	global series
-
-	if not (series.game and series.game.hand):
+	if not hand:
 		print("No current hand being played.")
 		return
 
-	game = series.game
-	game.hand.print_scores(as_if_won)
+	hand.print_scores(as_if_won)
 
 def played_so_far():
 	global series
 
-	if not (series.game and series.game.hand):
+	if not hand:
 		print("No current hand being played.")
 		return
 
-	game = series.game
-	game.hand.update_seen()
+	hand.update_seen()
 
 	print()
 
 		):
 		result = []
 		for card in line:
-			count = game.hand.cards_seen[card]
-			total = game.hand.cards_total[card]
+			count = hand.cards_seen[card]
+			total = hand.cards_total[card]
 			s = card.abbreviation.rjust(width) + " " + str(count).rjust(2)
 			if not isinstance(card, Safety):
 				s += "/" + str(total).ljust(2)
 			print("-" * len(s))
 			width = 10
 
-	game.hand.print_scores()
+	hand.print_scores()
 
 
 class StdioPlayer(Player):
+	
+	name = getpass.getuser()
 
 	def __init__(self, *a, **kw):
 		super().__init__(*a, **kw)
 		self.last_drawn = None
-		self.name = getpass.getuser()
 		self.state = None
 
-	def __getstate__(self):
-		return {
-			"super" : super().__getstate__(),
-			"last_drawn" : card_to_string.get(self.last_drawn),
-			"state" : self.state,
-		}
-
-	def __setstate__(self, state):
-		super().__setstate__(state["super"])
-		self.last_drawn = string_to_card.get(state["last_drawn"])
-		self.state = state["state"]
-
 	def getch(self, prompt, keys=None):
 		if keys:
 			keys += "!?sSt"
 		self.getch(prompt, " ")
 
 	def print_table(self):
-		if not (series.game and series.game.hand):
+		if not hand:
 			print("No hand currently being played.")
 			return
 
-		hand = self.hand
-		game = self.game
 		other = self.other()
 
-		if self.hand.plays and self.hand.plays[-1].playee is self.hand.discard:
+		if hand.plays and hand.plays[-1].playee is hand.discard:
 			discard_before = ">"
 			discard_after = "<"
 		else:
 			before_miles = " "
 			before_battle = between_piles = after_speed = "|"
 			highlights = set()
-			if self.hand.plays:
-				play = self.hand.plays[-1]
+			if hand.plays:
+				play = hand.plays[-1]
 				last_player = play.player
 				card = play.card
 				if play.playee == player:
 					elif isinstance(play.card, (Hazard, Remedy)):
 						before_battle = ">"
 						between_piles = "<"
-				for play in reversed(self.hand.plays):
+				for play in reversed(hand.plays):
 					if play.player != last_player:
 						break
 					if isinstance(play.card, Safety):
 		print(" ", ''.join(highlight_line))
 
 	def hand_end(self, winner):
-		series.game.hand.print_scores()
+		hand.print_scores()
 		text = []
 		add = text.append
 		if winner:
 			if lost_by_points:
 				add(" Which is weird, because " + winner.other().name + " got more points.")
 			if not winner.other().mileage():
-				add("And it's a shutout, #{} for {}!".format(series.players[series.game.players.index(winner)].shutouts, winner.name))
+				add("And it's a shutout, #{} for {}!".format(series.players[game.players.index(winner)].shutouts, winner.name))
 		else:
 			add("Nobody won the hand.")
 
 		text = "\n".join(text)
-		if series.game.over:
+		if game.over:
 			print(text)
 		else:
 			self.space_to_continue(text)
 But--in another, more accurate way--{winner.name} is the winner.
 			""".format(winner=winner)
 			add(screed)
-		for p, game_player in zip(series.players, series.game.players):
+		for p, game_player in zip(series.players, game.players):
 			add("{} lifetime games won: {} total score: {}".format(game_player.name, p.games_won, p.total_score))
 		self.space_to_continue("\n".join(text))
 
 	def turn(self):
-		hand = self.hand
 		other = self.other()
 
 		while True:
 		try:
 			with open(savepath, "rb") as f:
 				series = pickle.load(f)
-				series.unpickle()
+				# series.unpickle()
 		except EOFError:
 			print("Couldn't load savegame.  Starting new game.")
 			pass