Monday, June 10, 2013
Brute force Mastermind
Python came to rescue when playing Mastermind with 8 colors permitting repetition and the use of empty slot(s). Much faster and fun than directly using my brain, but received some rather strong objections from my 12 year old :) Here you go.
# Online syntax coloring: http://tohtml.com/python import itertools import random NONE=0 BLACK=1 BLUE=2 GREEN=3 ORANGE=4 PURPLE=5 RED=6 WHITE=7 YELLOW=8 COLORS = { NONE: "NONE", BLACK: "BLACK", BLUE: "BLUE", GREEN: "GREEN", ORANGE:"ORANGE", PURPLE:"PURPLE", RED: "RED", WHITE: "WHITE", YELLOW:"YELLOW", } SLOT_NUM = 5 # pick 5 colors in each turn # Return true if the given target is consistent with the history; # false otherwise def match_history(x): for t in history: a = [0]*len(COLORS) for i in x: a[i] += 1 red_c = 0 white_c = 0 # Count reds for i in range(SLOT_NUM): if t[i] == x[i]: red_c += 1 a[t[i]] -= 1 if red_c != history[t][RED]: return False # Count whites for i in range(SLOT_NUM): if t[i] != x[i]: if a[t[i]] > 0: white_c += 1 a[t[i]] -= 1 if white_c != history[t][WHITE]: return False return True def all_possibilities(): # All unique colors from 0 to 8 c = [0, 1, 2, 3, 4, 5, 6, 7, 8] for x in itertools.product(c, repeat=SLOT_NUM): yield x def display(guess): print str(tuple(map(lambda i: COLORS[i], guess))).replace("'","") def guess_next(): # Find all possible guesses matched = [x for x in all_possibilities() if match_history(x)] hit = len(matched) if hit == 1: print "The only possible permutation:\n" map(lambda x: display(x), matched) elif hit > 1: if hit <= 30: print hit, "possible permutations:\n" map(lambda x: display(x), matched) else: # More than 30 print "Randomly picking 30 out of", hit, "possible permutations:\n" for i in range(30): r = random.randrange(hit) count = 0 for x in matched: if count == r: display(x) break count += 1 else: print "Are you sure the history is valid ?" history = { (PURPLE, YELLOW, NONE, ORANGE, NONE): {RED: 2, WHITE: 0}, (GREEN, YELLOW, BLACK, ORANGE, RED): {RED: 0, WHITE: 1}, # (PURPLE, BLUE, WHITE, WHITE, NONE): {RED: 0, WHITE: 1}, } guess_next()