def simulateGame(game_state, row, card, bAppend, op_deck=None): ''' takes in game state and chosen row to place given card in if bAppend == True else if bAppend is false skip appending any specific card. randomly simulates rest of game and returns score ''' gs_copy = copy.deepcopy(game_state) # deepcopy copies all elements including nested ones if bAppend == True: gs_copy = simulate_append_card(gs_copy, row, card, True) # append card to appropriate position in game state prune_deck_of_cards(gs_copy) #print gs_copy if op_deck is None: global deck # get available cards for placement tdeck = deck[:] random.shuffle(tdeck) else: # use a specific passed deck (e.g. for consistent unit testing) tdeck = op_deck[:] # populate empty slots in game board with random cards for i in range(1,14): if gs_copy['properties2']['cards']['items']['position'+str(i)] == None: gs_copy['properties2']['cards']['items']['position'+str(i)] = tdeck.pop(0) if gs_copy['properties1']['cards']['items']['position'+str(i)] == None: gs_copy['properties1']['cards']['items']['position'+str(i)] = tdeck.pop(0) current_milli_time = lambda: int(round(time.time() * 1000)) stime2 = current_milli_time() scores = helpers.scoring_helper(gs_copy) # score game board global loop_elapsed loop_elapsed += (current_milli_time() - stime2) p2score = (helpers.scores_arr_to_int(scores)) * -1 # function returns p1's score. Get the inverse of this for AI's EV global counthands counthands += 1 if scores[3][1] == False or scores[3][0] == False: # only printing valid results (fouled simulated hands from both players omitted) if p2score > 0: global scoringhands scoringhands += 1 elif p2score == 0: global zeroscorehands zeroscorehands += 1 else: global losinghands losinghands += 1 else: global nullscoringhands nullscoringhands += 1 return p2score
def test_scores_arr_to_int5(self): # test validation in scores_arr_to_int print "\nTest #14 scores_arr_to_int - validation #3" test_scores = [[1, 0, 0], [1, 0, 0], [1, 0, "uh oh!"], [False, False]] result = helpers.scores_arr_to_int(test_scores) self.assertEqual(None, result) print "Passed!"
def test_scores_arr_to_int4(self): # test validation in scores_arr_to_int print "\nTest #13 scores_arr_to_int - validation #2" test_scores = ["invalid list length"] result = helpers.scores_arr_to_int(test_scores) self.assertEqual(None, result) print "Passed!"
def test_scores_arr_to_int3(self): # test validation in scores_arr_to_int print "\nTest #12 scores_arr_to_int - validation #1" test_scores = "invalid type1" result = helpers.scores_arr_to_int(test_scores) self.assertEqual(None, result) print "Passed!"
def test_scores_arr_to_int6(self): # test validation in scores_arr_to_int print "\nTest #15 scores_arr_to_int - validation #4" test_scores = [[1, 0, 0], [1, 0, 0], [1, 0, 0], [False, "look im not a boolean!"]] result = helpers.scores_arr_to_int(test_scores) self.assertEqual(None, result) print "Passed!"
def test_scores_arr_to_int2(self): # test that function correctly converts scores array to int (p1's score) print "\nTest #11 scores_arr_to_int #2" test_scores = [[2, 0, 5], [2, 0, 3], [2, 0, 6], [False, False]] result = helpers.scores_arr_to_int(test_scores) self.assertEqual(type(1), type(result)) self.assertEqual(-20, result) print "Passed!"
def test_scores_arr_to_int1(self): # test that function correctly converts scores array to int (p1's score) print "\nTest #10 scores_arr_to_int #1" test_scores = [[1, 3, 0], [1, 0, 0], [2, 0, 0], [False, False]] result = helpers.scores_arr_to_int(test_scores) self.assertEqual(type(1), type(result)) self.assertEqual(4, result) print "Passed!"
def handle_game_logic(game_state, game_id): ''' Take in game state from frontend and game id as inputs - use game id to get record from database Compare game state passed to game state from db - validate legitimacy Based off who went first and cards placed so far determine next action e.g. deal cards, AI, score board Update game state changes and store in database, call AI helper functions to determine optimal play Return appropriate response to server e.g. updated game state, cards to be placed, scores array ''' current_milli_time = lambda: int(round(time.time() * 1000)) # retrieve database for this game games = db_backend.get_database_collection() state = games.find_one({'_id': ObjectId(game_id)}) # find if player acted first this round and how many cards have been placed in order to work out current game position count = 0 playerFirst = state["playerFirst"] for i in range(0, 13): for j in range(0, 2): if game_state['properties' + str(j + 1)]['cards']['items']['position' + str(i + 1)] is not None: count += 1 print "\nCurrent game state:\n", game_state, "\nCards placed:", count if playerFirst: # Special case for player's first turn if count == 0: cdeck = deck.Deck() # creates deck cards = cdeck.deal_n(5) state['deck'] = {} # initialise deck dic within game state state['deck']['cards'] = cdeck.cards state['deck']['current-position'] = cdeck.current_position state['first5cards'] = cards # update game state in database update = games.update({'_id': ObjectId(game_id)}, {'$set': state}) return json.dumps(cards) # Special case for AI's first turn elif count == 5: # remove first 5 cards entry from db now that these have been placed on the board del state['first5cards'] # recreate deck from deck info in database cdeck = deck.Deck(state['deck']['cards'], state['deck']['current-position']) # validate game state state = validate_and_update_state(cdeck, count, game_state, state) if state == 0: return 0 # raise cherrypy 500 error # calculate AI's first 5 card placements cards = cdeck.deal_n(5) OFCP_AI.loop_elapsed = 0 stime = current_milli_time() iterations_timer = 4000 # Sets time in ms to spend simulating games. # As iterations increases diverges to optimal solution cardPlacementsAI = OFCP_AI.chooseMove(game_state, cards, iterations_timer) print "\nTime taken calculating 5 placements:", current_milli_time( ) - stime, "ms" print "Total time spent scoring hands: ", OFCP_AI.loop_elapsed, "ms" state = zip_placements_cards(cardPlacementsAI, cards, state) if state == 1: # Error with AI placement return 1 # deal player's next card card = cdeck.deal_one() # update game state with deck info state['deck']['cards'] = cdeck.cards state['deck']['current-position'] = cdeck.current_position # records game state in database + remove first5cards key state['cardtoplace'] = card update = games.update({'_id': ObjectId(game_id)}, { '$set': state, '$unset': { 'first5cards': 1 } }) del state['deck'] # don't return deck info to frontend del state['_id'] # state.pop('_id', None) return json.dumps(state) # general case for every other round after initial 5 placements by player and AI elif count < 26: cdeck = deck.Deck(state['deck']['cards'], state['deck']['current-position']) # validate game state state = validate_and_update_state(cdeck, count, game_state, state) if state == 0: return 0 # raise cherrypy 500 error # AI's next move card = str(cdeck.deal_one()) OFCP_AI.loop_elapsed = 0 stime = current_milli_time() iterations_timer = 3000 AI_placement = OFCP_AI.chooseMove(game_state, card, iterations_timer) print "\nTime taken calculating 1 placement:", current_milli_time( ) - stime, "ms" print "Total time spent scoring hands: ", OFCP_AI.loop_elapsed, "ms" state = zip_placements_cards([AI_placement], [card], state) if state == 1: # Error with AI placement return 1 # deal player's next card card = cdeck.deal_one() # update game state with deck info state['deck']['cards'] = cdeck.cards state['deck']['current-position'] = cdeck.current_position # records game state in database state['cardtoplace'] = card update = games.update({'_id': ObjectId(game_id)}, {'$set': state}) # print "\nStored game state in database:", state del state['deck'] # don't return deck info to frontend del state['_id'] # print "\nReturning state to player:", state return json.dumps(state) else: # game over - validate and score game board cdeck = deck.Deck(state['deck']['cards'], state['deck']['current-position']) # validate game state state = validate_and_update_state(cdeck, count, game_state, state) if state == 0: return 0 # raise cherrypy 500 error # update game state with deck info state['deck']['cards'] = cdeck.cards state['deck']['current-position'] = cdeck.current_position # score game board scores_array = helpers.scoring_helper(game_state) # store p1's score in database state['score'] += helpers.scores_arr_to_int(scores_array) print "\nState score recorded as:", state['score'], "!\n" scores_array.append([state['score']]) print "scores_array was", scores_array # records game state in database del state['cardtoplace'] update = games.update({'_id': ObjectId(game_id)}, {'$set': state}) OFCP_AI.reset() # reset AI variables/ states # scores_array format [ [winnerid, winners_bottom_royalty, losers_bottom_royalty], # [winnerid, winners_middle_royalty, losers_middle_royalty] , # [winnerid, winners_top_royalty, losers_top_royalty] ], # [p1foulbool, p2foulbool], # [p1_existing_score] print '\n Scores -->', scores_array, '\n' return json.dumps(scores_array) else: if count == 0: # AI acts first, but return player's first 5 cards first while AI calculates if 'first5cards' not in state: cdeck = deck.Deck() # creates deck cards_5_player = cdeck.deal_n(5) # player's first 5 cards state['deck'] = {} # initialise deck dic within game state state['deck']['cards'] = cdeck.cards state['deck']['current-position'] = cdeck.current_position # validate game state state = validate_and_update_state(cdeck, count, game_state, state) if state == 0: return 0 # raise cherrypy 500 error state['first5cards'] = cards_5_player # update game state in database update = games.update({'_id': ObjectId(game_id)}, {'$set': state}) return json.dumps(cards_5_player) else: cdeck = deck.Deck(state['deck']['cards'], state['deck']['current-position']) cards_5_AI = cdeck.deal_n(5) # validate game state state = validate_and_update_state(cdeck, count, game_state, state) if state == 0: return 0 # raise cherrypy 500 error # calculate AI's first 5 card placements OFCP_AI.loop_elapsed = 0 stime = current_milli_time() iterations_timer = 4000 # Sets time in ms to spend simulating games. # As iterations increases diverges to optimal solution cardPlacementsAI = OFCP_AI.chooseMove(game_state, cards_5_AI, iterations_timer) print "\nTime taken calculating 5 placements:", current_milli_time( ) - stime, "ms" print "Total time spent scoring hands: ", OFCP_AI.loop_elapsed, "ms" state = zip_placements_cards(cardPlacementsAI, cards_5_AI, state) if state == 1: # Error with AI placement return 1 # update game state with deck info state['deck']['cards'] = cdeck.cards state['deck']['current-position'] = cdeck.current_position # records game state in database + remove first5cards key update = games.update({'_id': ObjectId(game_id)}, {'$set': state}) del state['deck'] # don't return deck info to frontend del state['_id'] # state.pop('_id', None) return json.dumps(state) # general case for every other round after initial 5 placements by player and AI elif count < 26: cdeck = deck.Deck(state['deck']['cards'], state['deck']['current-position']) # validate game state state = validate_and_update_state(cdeck, count, game_state, state) if state == 0: return 0 # raise cherrypy 500 error # AI's next move card = str(cdeck.deal_one()) OFCP_AI.loop_elapsed = 0 stime = current_milli_time() iterations_timer = 3000 AI_placement = OFCP_AI.chooseMove(game_state, card, iterations_timer) print "\nTime taken calculating 1 placement:", current_milli_time( ) - stime, "ms" print "Total time spent scoring hands: ", OFCP_AI.loop_elapsed, "ms" state = zip_placements_cards([AI_placement], [card], state) if state == 1: # Error with AI placement return 1 # deal player's next card card = cdeck.deal_one() # update game state with deck info state['deck']['cards'] = cdeck.cards state['deck']['current-position'] = cdeck.current_position # records game state in database state['cardtoplace'] = card update = games.update({'_id': ObjectId(game_id)}, {'$set': state}) # print "\nStored game state in database:", state del state['deck'] # don't return deck info to frontend del state['_id'] # print "\nReturning state to player:", state return json.dumps(state) else: # game over - validate and score game board cdeck = deck.Deck(state['deck']['cards'], state['deck']['current-position']) # validate game state state = validate_and_update_state(cdeck, count, game_state, state) if state == 0: return 0 # raise cherrypy 500 error # update game state with deck info state['deck']['cards'] = cdeck.cards state['deck']['current-position'] = cdeck.current_position # score game board scores_array = helpers.scoring_helper(game_state) # store p1's score in database state['score'] += helpers.scores_arr_to_int(scores_array) print "\nState score recorded as:", state['score'], "!\n" scores_array.append([state['score']]) print "scores_array was", scores_array # records game state in database del state['cardtoplace'] update = games.update({'_id': ObjectId(game_id)}, {'$set': state}) OFCP_AI.reset() # reset AI variables/ states # scores_array format [ [winnerid, winners_bottom_royalty, losers_bottom_royalty], # [winnerid, winners_middle_royalty, losers_middle_royalty] , # [winnerid, winners_top_royalty, losers_top_royalty] ], # [p1foulbool, p2foulbool], # [p1_existing_score] print '\n Scores -->', scores_array, '\n' return json.dumps(scores_array)