""" Mancala game v1.0 Lyndon While, 3 April 2014 The program prompts the user for the game size X, then it plays a game of Mancala between two random players and creates an SVG file MancalaGameX.svg that shows the history of the board during the game. Each board is annotated with the next move made, and the final board is annotated with the average branching factor during the game. Software to run the program is available from python.org. Get Python 3. The size of the displayed boards and the fonts used can be controlled by changing the variable size below. The colours used in the display can be controlled by changing the variable colours. Please report any bugs on help3001. Unless they're embarrassing ones. :-) """ import random import copy #a board position is a 2x7 list with the stores at the ends #a player is 0 or 1, and is used to index the board #a move is a list of indices into a board #------------------------------------------------------------- This is the display code size = 5 #controls the board-size and fonts - don't change anything else side = size * 5 housefont = size * 2 storefont = size * 3 colours = [(0, 0, 0), (255,150,150), (215,215,0)] # black pink green-yellow def mkhouse(k, p, x, r): h = side * (3.4 + k + r // 10 * 9) v = side * (1.5 - p + r % 10 * 3) return (colours[p + 1], [(h, v), (h + side, v), (h + side, v + side), (h, v + side), (h, v)], #text placement and font (h + side / 2 - len(str(x)) * side / 8, v + 2 * side / 3, str(x), housefont)) def mkstore(p, x, r): h = side * (9.4 - 7 * p + r // 10 * 9) v = side * (0.5 + r % 10 * 3) return (colours[p + 1], [(h, v), (h + side, v), (h + side, v + 2 * side), (h, v + 2 * side), (h, v)], #text placement and font (h + side / 2 - len(str(x)) * side / 5, v + 6 * side / 5, str(x), storefont)) def writeColor(c): (r, g, b) = c return "".join(["rgb(", str(r), ",", str(g), ",", str(b), ")"]) def writeText(t): (h, v, z, s) = t return "".join(["", z, "\n"]) def writePolygons(f, ps): for (c, p, t) in ps: f.write("\n") f.write(writeText(t)) def mancalaDisplay(b, m, r, f): if r % 2 == 1: t = "green" else: t = "pink" if r < 10: f.write(writeText((size, side * (1.0 + r % 10 * 3), t + "'s", housefont))) f.write(writeText((size, side * (1.5 + r % 10 * 3), "move", housefont))) #display the move f.write(writeText((size + side * (2 + (r - 1) // 10 * 9), side * (3 + (r - 1) % 10 * 3), "".join([str(k + 1) for k in m]), housefont))) writePolygons(f, [mkhouse(k, p, b[p][5 * p + k * (1 - 2 * p)], r) for p in range(2) for k in range(6)] + [mkstore( p, b[p][6], r) for p in range(2)]) #------------------------------------------------------------- This is the game mechanics code def moves(b, p): #returns a list of legal moves for player p on board b zs = [] #for each non-empty house on p's side for m in [h for h in range(6) if b[p][h] > 0]: #if the final seed will be sown in p's store if (b[p][m] + m) % 13 == 6: #copy b, make move m, and check for recursive possibilities c = copy.deepcopy(b) move(c, p, [m]) ms = moves(c, p) if ms == []: zs += [[m]] else: zs += [[m] + n for n in ms] else: zs += [[m]] return zs def move(b, p, ms): #make the move ms for player p on board b for m in ms: x = b[p][m] b[p][m] = 0 (capturePossible, z) = sow(b, p, m + 1, 6, x) #if the last seed was sown in an empty house on p's side, with seeds opposite if capturePossible and b[p][z] == 1 and b[1 - p][5 - z] > 0: b[p][6] += b[p][z] + b[1 - p][5 - z] b[p][z] = 0 b[1 - p][5 - z] = 0 def sow(b, p, m, y, x): #sow x seeds for player p on board b, starting from house m, with limit y #the limit is used to exclude the opponent's store #it returns (possibleCapture, lastHouseSown) while x > 0: for z in range(m, min(y + 1, m + x)): b[p][z] += 1 x -= y + 1 - m p = 1 - p m = 0 y = 11 - y return (y == 5, z) def mancala(n): #start with n seeds in each small house b = [[n] * 6 + [0] for p in [0, 1]] #open the SVG file f = open("".join(["MancalaGame", str(n), ".svg"]), 'w') f.write("\n") mancalaDisplay(b, [], 0, f) r = 1 p = 0 tm = 0 #while both players have seeds in their small houses while all ([sum(b[p][:6]) > 0 for p in [0, 1]]): ms = moves(b, p) m = random.choice(ms) move(b, p, m) mancalaDisplay(b, m, r, f) r += 1 p = 1 - p tm += len(ms) #move the remaining seeds to the stores for p in [0, 1]: for k in [0, 1, 2, 3, 4, 5]: b[p][6] += b[p][k] b[p][k] = 0 mancalaDisplay(b, [round(tm / (r - 1), 2)], r, f) f.write("\n") f.close() def main(): mancala(int(input("What size game? "))) main()