def test_reformat_hand_xyy_yx6(self): # test an invalid hand to check error handling print "\nTest #9 reformat_hand_xyy_yx6 ~ invalid 3" # disable stdout to avoid screen clutter f = open(os.devnull, 'w') sys.stdout = f result = helpers.reformat_hand_xyy_yx("3_non_existent", 3) f.close() # re-enable stdout sys.stdout = sys.__stdout__ self.assertEqual(None, result) print "Passed!"
def test_reformat_hand_xyy_yx5(self): # test an invalid hand to check error handling print "\nTest #8 reformat_hand_xyy_yx5 ~ invalid 5 #2" # disable stdout to avoid screen clutter f = open(os.devnull, 'w') sys.stdout = f result = helpers.reformat_hand_xyy_yx("c05c07d07d08s13", 100) f.close() # re-enable stdout sys.stdout = sys.__stdout__ self.assertEqual(None, result) print "Passed!"
def test_reformat_hand_xyy_yx3(self): # test a valid 3 card hand print "\nTest #6 reformat_hand_xyy_yx3 ~ valid 3" result = helpers.reformat_hand_xyy_yx("c03d03s03", 3) self.assertEqual("3C3D3S", result) print "Passed!"
def test_reformat_hand_xyy_yx2(self): # test another valid hand to format print "\nTest #5 reformat_hand_xyy_yx2 ~ valid 5 #2 " result = helpers.reformat_hand_xyy_yx("s07c10d01c05c08", 5) self.assertEqual("5C7S8CTCAD", result) print "Passed!"
def test_reformat_hand_xyy_yx1(self): # test a valid hand to format print "\nTest #4 reformat_hand_xyy_yx1 ~ valid 5 #1 " result = helpers.reformat_hand_xyy_yx("c09c10c11c12c13", 5) self.assertEqual("9CTCJCQCKC", result) print "Passed!"
def place_5(game_state, cards, sim_timer, test_deck=None): ''' takes game_state, first 5 cards and allocated simulated time in ms as inputs. Aggregates scores for simulations of each permutation of the first possible placements and returns an optimal placement as a list with index i = card i+1's allocated row e.g. return [1,1,2,2,3] = card 1 in row 1, card 2 in row 1, card 3 in row 2, card 4 in row 2, card 5 in row 3''' # if a test deck is passed assign it to global if test_deck != None: global deck deck = test_deck try: cdic = {cards[0]:1, cards[1]:2, cards[2]:3, cards[3]:4, cards[4]:5} # keep a permanent record of which card was which index except Exception: print "Invalid cards passed to place_5:", cards raise Exception print "\n####\nPlace_5:", cards, "\nSimulation Timer:", sim_timer, "ms.\n" cstring = "" for i in range(0,5): cstring += cards[i][0] + cards[i][1] + cards[i][2] print cstring cstring = helpers.reformat_hand_xyy_yx(cstring, 5) cformatted = [] for i in xrange(0,10,2): tstr = cstring[i] + cstring[i+1] cformatted.append(tstr) # ctemp = 13 elements: 5 cards + 8 '' blanks (13 containers on a player's OFC board) ctemp = cards[:] for i in range(0,8): ctemp.append(None) pbot = set(itertools.combinations(ctemp,5)) # produce set of combinations for a 5 card row pbot = list(pbot) pmid = pbot[:] # combinations middle same as bottom ptop = set(itertools.combinations(ctemp,3)) # produce set of combinations for a 3 card row ptop = list(ptop) rowlists = [pbot, pmid, ptop] x = set(itertools.product(*rowlists)) # product of all possible row combinations # histogram maps frequency of each rank - used to prune states to reduce complexity when there are pairs, trips etc. # e.g. if we have pair of Aces removes states where these aces are not placed together # as it is very unlikely this would be an optimal placement hist = produce_histogram(cformatted) if hist == None: raise ValueError("Invalid values passed to produce_histogram") print "Histogram:", hist, "\n" highestfreq = 1 # look for quads or trips or a pair thatrank = None for item in hist: if item[1] > highestfreq: highestfreq = item[1] thatrank = item[0] nexthighestfreq = 1 secondrank = None if highestfreq < 4: # look for 2nd pair for item in hist: if item[1] > nexthighestfreq and item[0] is not thatrank: nexthighestfreq = item[1] secondrank = item[0] # look for straights and higher, return immediately if found cards1 = helpers.reformat_hand_xyy_yx("".join(cards), 5) hand_score = hands.score_5(cards1) if hand_score[0] >= 5: print "Found", hands.classify_5(cards1), ", choosing this in bottom row!" return [1,1,1,1,1] print "Highest Freq:",highestfreq,"Rank:",thatrank,"... Next Highest Freq:",nexthighestfreq,"Rank:",secondrank final = [] # post-processing removes duplicates and validates state has all cards placed for rows in x: duplicate = False c_count = 0 for pos in rows[0]: if pos is not None: c_count += 1 if pos in rows[1] or pos in rows[2]: duplicate = True break if not duplicate: for pos in rows[1]: if pos is not None: c_count += 1 if pos in rows[2]: duplicate = True break for pos in rows[2]: if pos is not None: c_count += 1 if c_count == 5 and not duplicate: final.append(rows) final2 = [] # 2nd round of post-processing if there are pairs, trips or quads - remove states that don't place these optimally if thatrank is not None: for state in final: counts = [0,0,0] for i in range(0,3): for x in state[i]: if x is not None: x = int(x[1] + x[2]) if x == 1: x = 14 if x == thatrank: counts[i] += 1 if counts[0] < highestfreq and counts[1] < highestfreq and counts[2] < highestfreq: # not all placed together # remove this non-optimal state pass else: final2.append(state) # append this state which has all instances of thatrank paired together else: final2 = final final3 = [] # 3rd round for any second pair if secondrank is not None: for state in final2: counts = [0,0,0] for i in range(0,3): for x in state[i]: if x is not None: x = int(x[1] + x[2]) if x == 1: x = 14 if x == secondrank: counts[i] += 1 if counts[0] < nexthighestfreq and counts[1] < nexthighestfreq and counts[2] < nexthighestfreq: # not all placed together # remove this non-optimal state pass else: final3.append(state) # append this state which has all instances of thatrank paired together else: final3 = final2 final4 = [] # 4th round - if there are still lots of states to consider, prune some sub-optimal placements e.g. all cards placed in middle if len(final3) > 20: for state in final3: # remove states with an empty or full bottom row count = 0 for item in state[0]: if item is not None: count += 1 if count > 0 and count < 5: count = 0 for item in state[2]: if item is not None: count += 1 # prune states which have dumped 3 cards top if count < 3: final4.append(state) else: final4 = final3 final = final4 final2 = None #wipe final3 = None #wipe final4 = None #wipe s_count = 0 for state in final: s_count += 1 #print str(s_count) + ":", state print "Total states:", s_count current_milli_time = lambda: int(round(time.time() * 1000)) # produce every possible initial game state dictionary for AI placements state_id = 1 states_scores = [] random.shuffle(final) for state in final: gs_copy = copy.deepcopy(game_state) for item in state[0]: # bottom if item is not None: gs_copy = simulate_append_card(gs_copy, 1, item, False) for item in state[1]: # middle if item is not None: gs_copy = simulate_append_card(gs_copy, 2, item, False) for item in state[2]: # top if item is not None: gs_copy = simulate_append_card(gs_copy, 3, item, False) stime = current_milli_time() s_ev = 0 iterations = 0 while ( (current_milli_time() - stime) < (sim_timer / s_count) ): # each state gets an equal % of iteration time s_ev += simulateGame(gs_copy, None, None, False) # simulates random placements of rest of cards on game board and returns EV iterations += 1 states_scores.append([state_id, s_ev, iterations]) state_id += 1 print "\nSTATE SCORES:", states_scores, "\n\n" # find the state selection with the highest EV highest_ev = 0 best_state_score = [0,0,0] count = 0 for result in states_scores: print "State:", final[count], "-> Total score", result[1], "from", result[2], "iterations = EV:", "{0:.2f}".format(float(result[1])/float(result[2])) if float(result[1])/float(result[2]) > highest_ev: # total ev / iterations -> equal weighting between all states , find best score best_state_score = result highest_ev = result[1] count += 1 print "\nBest state score:", best_state_score best_state_id = best_state_score[0] best_state = final[best_state_id -1] print "~best state got:", best_state ftw = open("states_ev.txt", "w") s = "" for line in states_scores: s = "ID: " + str(line[0]) + ", EV: " + str(line[1]) + " from " + str(line[2]) + " iterations. " s += str(final[line[0]-1]) + "\n" ftw.write(s) ftw.close() brow = best_state[0] mrow = best_state[1] trow = best_state[2] r_placements = [0,0,0,0,0] for item in brow: if item is not None: t = cdic[item] r_placements[t -1] = 1 # bottom for item in mrow: if item is not None: t = cdic[item] r_placements[t -1] = 2 # middle for item in trow: if item is not None: t = cdic[item] r_placements[t -1] = 3 # top a = "\nPlacements: " for i in range(0,5): a += cards[i] + " -> Row " + str(r_placements[i]) if i is not 4: a += ", " else: a += "." print a return r_placements