def generate( self, width=10, height=10, gametype="Default", ntokens=8, nturns=10, scramble=False): """ Generate a new game and save it to the database. width/height - width & height of the generated grid. gametype - "Clear", "Solution", or "Default" ntokens - the number of different token types to use nturns - the number of turns to pre-play in a Default game, OR the number of turns to rewind in a Solution game """ self.width = width self.height = height self.grid = Grid( width, height ) self.tokens = tokens.selectRandomNTokens( ntokens, width, height ) self.nturns = nturns self.gamestate = "Playable" # "Playable" || "Win" || "Lose" self.mongo_id = 0 #The mongo_db id of this game record. self.gametype = gametype # an invisible currentToken isn't valid, but should be overwritten by the # self.selectValidToken() call. self.currentToken = tokens.InvisibleToken() self.failureCounter = 10 self.lastBomb = 0 #Too many bombs make the game unplayable. self.lastJoker = 0 #Too many jokers make the game confusing. self.scramble = scramble # Initialize Board if self.gametype == "Clear": self.setup_clear_game() elif self.gametype == "Solution": self.setup_solution_game() else: self.setup_default_game() self.selectValidToken()
def load( self ): print "Loading..." mongo_object = self.games_database().find_one({u'_id': ObjectId(self.mongo_id)} ) self.width = int(mongo_object[u'width']) self.height = int(mongo_object[u'height']) self.grid = Grid( self.width, self.height ) self.tokens = [ tokens.deserialize( token ) for token in mongo_object[u'tokens'] ] self.currentToken = tokens.deserialize( mongo_object[u'currentToken'] ) self.gametype = mongo_object[u'gametype'] self.gamestate = mongo_object[u'gamestate'] self.mongo_id = mongo_object[u'_id'] self.failureCounter = mongo_object[u'failureCounter'] self.lastBomb = mongo_object[u'lastBomb'] self.lastJoker = mongo_object[u'lastJoker'] self.scramble = mongo_object[u'scramble'] self.grid.unserialize( mongo_object[u'grid'] ) print "Load complete."
class Game( object ): """ The core game object. The game object must be generate()d or load()ed before any further operations are performed on it. """ def __init__(self): self.laziness = 60 #If we've already found 30 solutions, stop looking. self.minimumTimeBetweenBombs = 12 self.minimumTimeBetweenJokers = 10 self.scramble = False def generate( self, width=10, height=10, gametype="Default", ntokens=8, nturns=10, scramble=False): """ Generate a new game and save it to the database. width/height - width & height of the generated grid. gametype - "Clear", "Solution", or "Default" ntokens - the number of different token types to use nturns - the number of turns to pre-play in a Default game, OR the number of turns to rewind in a Solution game """ self.width = width self.height = height self.grid = Grid( width, height ) self.tokens = tokens.selectRandomNTokens( ntokens, width, height ) self.nturns = nturns self.gamestate = "Playable" # "Playable" || "Win" || "Lose" self.mongo_id = 0 #The mongo_db id of this game record. self.gametype = gametype # an invisible currentToken isn't valid, but should be overwritten by the # self.selectValidToken() call. self.currentToken = tokens.InvisibleToken() self.failureCounter = 10 self.lastBomb = 0 #Too many bombs make the game unplayable. self.lastJoker = 0 #Too many jokers make the game confusing. self.scramble = scramble # Initialize Board if self.gametype == "Clear": self.setup_clear_game() elif self.gametype == "Solution": self.setup_solution_game() else: self.setup_default_game() self.selectValidToken() def load( self ): print "Loading..." mongo_object = self.games_database().find_one({u'_id': ObjectId(self.mongo_id)} ) self.width = int(mongo_object[u'width']) self.height = int(mongo_object[u'height']) self.grid = Grid( self.width, self.height ) self.tokens = [ tokens.deserialize( token ) for token in mongo_object[u'tokens'] ] self.currentToken = tokens.deserialize( mongo_object[u'currentToken'] ) self.gametype = mongo_object[u'gametype'] self.gamestate = mongo_object[u'gamestate'] self.mongo_id = mongo_object[u'_id'] self.failureCounter = mongo_object[u'failureCounter'] self.lastBomb = mongo_object[u'lastBomb'] self.lastJoker = mongo_object[u'lastJoker'] self.scramble = mongo_object[u'scramble'] self.grid.unserialize( mongo_object[u'grid'] ) print "Load complete." def save( self): """ Save the entirety of the game state to mongodb. """ print "Saving..." document = {"width": self.width, "height": self.height, "gamestate": self.gamestate, "gametype": self.gametype, "tokens" : [ token.serialize() for token in self.tokens ], "currentToken": self.currentToken.serialize(), "grid": self.grid.serialize(), "failureCounter":self.failureCounter, "lastBomb":self.lastBomb, "lastJoker":self.lastJoker, "scramble":self.scramble} if self.mongo_id == 0: self.mongo_id = self.games_database().insert( document ) else: print "\t",self.games_database().update({u'_id':self.mongo_id}, document, safe=True ) print "Save complete." def saveFailure( self): """ Save just the updated failure counter. """ print "Saving failure counter..." document = { "$inc": { "failureCounter": -1} } print "\t",self.games_database().update({u'_id':self.mongo_id}, document, safe=True ) print "Save complete." def success( self ): self.failureCounter += 1 def failure( self ): self.failureCounter -= 1 if self.failureCounter <= 0: self.gamestate = "Lose" def games_database( self ): connection = Connection() db = connection.flup_database return db.games def setup_default_game( self ): """ In a Default game, we play n turns for the player. """ for i in range( 0, self.nturns ): self.autoplayOneTurn() def setup_clear_game( self ): """ In a Clear game, we play 0 turns for the player. """ pass def setup_solution_game( self ): """ In a Solution game, we solve the game, then rewind n turns. """ self.completelySolve() for i in range(0, self.nturns): self.grid.rewindLastFullMove() def selectValidToken( self ): """ Set a verifiably playable token to the current token. """ print "Planning Next Token..... " result = self.solveOneStep() if not result: print "Gamestate: Win" self.gamestate = "Win" return token, point = result print "Next Token: ", token print "Next Point: ", point self.currentToken = token def completelySolve( self ): """ Completely solve the game. (Currently brute-force and non-optimal) """ while self.autoplayOneTurn(): pass def autoplayOneTurn( self ): """ Completely play one turn for the player. """ token_point = self.solveOneStep() if not token_point: print "Solution complete. " return False token, point = token_point if self.grid.placeToken( token, point ): return True else: print "Somehow our valid placement is not valid - ", point print self.grid.error return self.autoplayOneTurn( ) def solveOneStep( self, temp_tokens = [] ): """ Return the solution to one step of the game, as a tuple (token, point). """ if temp_tokens == []: temp_tokens = copy.deepcopy( self.tokens ) print "\tSolving one step with tokens ", temp_tokens test_token = random.choice( temp_tokens ) print "\tAttempting", test_token.name() valid_placements = self.solveForToken( test_token ) print "\tValid Placements: ", valid_placements if len(valid_placements) == 0 and len(temp_tokens) <= 1: print "\tNo valid placements for ", test_token.name() return False if len(valid_placements) == 0: temp_tokens.remove( test_token ) return self.solveOneStep( temp_tokens ) return (test_token, random.choice(valid_placements) ) def solveForToken( self, token ): """ Returns all valid placements for the token. """ if token.name() == tokens.Bomb().name() : if self.lastBomb < self.minimumTimeBetweenBombs: return [] if token.name() == tokens.Joker().name() : if self.lastJoker < self.minimumTimeBetweenJokers: return [] valid_placements = [] for point in self.grid.points(): if token.isValid( self.grid, point) and not self.grid.isAnyTokenAtPoint( point ): valid_placements.append( point ) if len( valid_placements ) > self.laziness: break return valid_placements def obfuscateToken( self, token ): """ Obfuscate the token using the current set of obfuscation rules. """ for i in range( 0, len(self.tokens) ): if self.tokens[i].name() == token.name(): return obfuscator[i] def deobfuscateToken( self, fustulated_token ): """ Fix the token. """ for i in range( 0, len(obfuscator) - 1 ): if fustulated_token == obfuscator[i]: return self.tokens[i] def sequenceNumberOfLastMove( self ): return self.grid.moves[ len( self.grid.moves ) - 1 ][0] def sequenceCheck( self, sequenceNumber ): if sequenceNumber < self.sequenceNumberOfLastMove(): raise Exception( "Trying to play a move out of sequence.") def attemptMove( self, point, sequenceNumberOfLastMove ): self.sequenceCheck( sequenceNumberOfLastMove ) success = self.grid.placeToken( self.currentToken, point ) if success: self.setupNextTurn() self.success() return True else: self.failure() return False def hint( self, sequenceNumberOfLastMove ): self.sequenceCheck( sequenceNumberOfLastMove ) token_point = self.solveOneStep([self.currentToken]) if token_point: token, point = token_point else: self.gamestate = "Win" return False if self.grid.placeToken( token, point ): self.failure() self.setupNextTurn() return True else: return self.hint( sequenceNumberOfLastMove ) def setupNextTurn(self): if self.currentToken.name() == tokens.Bomb().name() : self.lastBomb = 0 else: self.lastBomb += 1 if self.currentToken.name() == tokens.Joker().name() : self.lastJoker = 0 else: self.lastJoker += 1 self.selectValidToken() return def __repr__(self): ret = "" ret += str(self.grid) + "\n" ret += "\n" ret += "Current Token: " + self.currentToken.name() + "\n" ret += "\n" ret += "Tokens in Play: \n" for token in self.tokens: ret += "\t" + token.name() + "\n" ret += "Game State: " + self.gamestate + "\n" return ret