Text based English Solitaire from Wikipedia

Updated TrustyTony 0 Tallied Votes 345 Views Share

Got inspired to make computer to make moves in English Solitaire, I learned in childhood days to solve by myself consistently, no solving or game play interface at the moment (easy to add though).

I added printing of the ready solution from the wikipedia, also maybe of your interest are the function for columnar printing (not quite general as it expects exactly equal length lists of equal length lines) to reduce the length of printing and debug function to access multidimensional list by tuple (or other iterable) co-ordinates.

Output:

Board style
    a b c    
    d e f    
g h i j k l m
n o p x P O N
M L K J I H G
    F E D    
    C B A    

Board middle empty
    a b c    
    d e f    
g h i j k l m
n o p . P O N
M L K J I H G
    F E D    
    C B A    

Possible moves

ejx
    a b c    
    d . f    
g h i . k l m
n o p x P O N
M L K J I H G
    F E D    
    C B A    
Pieces left: 32
Next moves available:
hij, Jxj, lkj

opx
    a b c    
    d e f    
g h i j k l m
n . . x P O N
M L K J I H G
    F E D    
    C B A    
Pieces left: 32
Next moves available:
dip, FKp, Pxp

EJx
    a b c    
    d e f    
g h i j k l m
n o p x P O N
M L K . I H G
    F . D    
    C B A    
Pieces left: 32
Next moves available:
jxJ, LKJ, HIJ

OPx
    a b c    
    d e f    
g h i j k l m
n o p x . . N
M L K J I H G
    F E D    
    C B A    
Pieces left: 32
Next moves available:
fkP, pxP, DIP

     ejx               lkj               cfk               Pkf     
    a b c             a b c             a b .             a b .    
    d . f             d . f             d . .             d . f    
g h i . k l m     g h i j . . m     g h i j k . m     g h i j . . m
n o p x P O N     n o p x P O N     n o p x P O N     n o p x . O N
M L K J I H G     M L K J I H G     M L K J I H G     M L K J I H G
    F E D             F E D             F E D             F E D    
    C B A             C B A             C B A             C B A    


     DIP               GHI               JIH               mNG     
    a b .             a b .             a b .             a b .    
    d . f             d . f             d . f             d . f    
g h i j . . m     g h i j . . m     g h i j . . m     g h i j . . .
n o p x P O N     n o p x P O N     n o p x P O N     n o p x P O .
M L K J . H G     M L K J I . .     M L K . . H .     M L K . . H G
    F E .             F E .             F E .             F E .    
    C B A             C B A             C B A             C B A    


     GHI               ijk               ghi               LKJ     
    a b .             a b .             a b .             a b .    
    d . f             d . f             d . f             d . f    
g h i j . . .     g h . . k . .     . . i . k . .     . . i . k . .
n o p x P O .     n o p x P O .     n o p x P O .     n o p x P O .
M L K . I . .     M L K . I . .     M L K . I . .     M . . J I . .
    F E .             F E .             F E .             F E .    
    C B A             C B A             C B A             C B A    


     JIH               HOl               lkj               jih     
    a b .             a b .             a b .             a b .    
    d . f             d . f             d . f             d . f    
. . i . k . .     . . i . k l .     . . i j . . .     . h . . . . .
n o p x P O .     n o p x P . .     n o p x P . .     n o p x P . .
M . . . . H .     M . . . . . .     M . . . . . .     M . . . . . .
    F E .             F E .             F E .             F E .    
    C B A             C B A             C B A             C B A    


     CFK               pKF               ABC               CFK     
    a b .             a b .             a b .             a b .    
    d . f             d . f             d . f             d . f    
. h . . . . .     . h . . . . .     . h . . . . .     . h . . . . .
n o p x P . .     n o . x P . .     n o . x P . .     n o . x P . .
M . K . . . .     M . . . . . .     M . . . . . .     M . K . . . .
    . E .             F E .             F E .             . E .    
    . B A             . B A             C . .             . . .    


     Mng               ghi               abc               cfk     
    a b .             a b .             . . c             . . .    
    d . f             d . f             d . f             d . .    
g h . . . . .     . . i . . . .     . . i . . . .     . . i . k . .
. o . x P . .     . o . x P . .     . o . x P . .     . o . x P . .
. . K . . . .     . . K . . . .     . . K . . . .     . . K . . . .
    . E .             . E .             . E .             . E .    
    . . .             . . .             . . .             . . .    


     kPI               dip               pKF               FED     
    . . .             . . .             . . .             . . .    
    d . .             . . .             . . .             . . .    
. . i . . . .     . . . . . . .     . . . . . . .     . . . . . . .
. o . x . . .     . o p x . . .     . o . x . . .     . o . x . . .
. . K . I . .     . . K . I . .     . . . . I . .     . . . . I . .
    . E .             . E .             F E .             . . D    
    . . .             . . .             . . .             . . .    


     DIP               Pxp               opx     
    . . .             . . .             . . .    
    . . .             . . .             . . .    
. . . . . . .     . . . . . . .     . . . . . . .
. o . x P . .     . o p . . . .     . . . x . . .
. . . . . . .     . . . . . . .     . . . . . . .
    . . .             . . .             . . .    
    . . .             . . .             . . .
""" Defining solitaire board based on wikipedia article
    http://en.wikipedia.org/wiki/Peg_solitaire, checking for moves,
    printing the solutions given in wikipedia from the given solution string
    in columnar format
"""

from pprint import pprint

def make_board_from_shape(board_string):
    return [line for line in board_string.splitlines() if line]

def make_board(empty):
    return dict((symbol, '.') if symbol in empty else (symbol, symbol)
                for symbol in positions)

def make_moves(board_style):
    moves = []
    # original board and transpose and remove spacing between letters
    # (top-down and left-right)
    for sol in (solitaire, zip(*(s[::2] for s in solitaire))):
        moves += [''.join((a,b,c))
                  for line_a, line_b, line_c in zip(sol, sol[1:], sol[2:])
               for a, b, c in zip(line_a, line_b, line_c)
                  if not ' ' in a + b + c]
    # reversed directions also possible (down-top and right-left)
    moves += [m[::-1] for m in moves]
    return moves

def get_by_iter(data, iterable):
    for t in iterable:
        data = data[t]
    return data

def is_hole(c):
    return c == '.'

def  board_string(board, solitaire):
    return [''.join(board[c] if not is_hole(c) else '.' for c in row)
            for row in solitaire]

def print_board(board, solitaire):
    print('\n'.join(board_string(board, solitaire)))

def valid_move(board, m):
    return (len(m) == 3 and
            is_hole(board[m[2]]) and
            not(is_hole(board[m[0]])) and
            not(is_hole(board[m[1]])))

def move2_to_move3(move, moves):
    return next(m for m in moves if m[0]+m[-1]== move)

def possible_moves(board, moves):
    return (m for m in moves if valid_move(board, m))

def make_dicts(solitaire):
    positions = dict((c, (line_ind, column_ind))
                     for line_ind, line in enumerate(solitaire)
                     for  column_ind, c in enumerate(line))
    return (positions, dict((indexes, c) for c, indexes in positions.items()))

def pack_lines_and_print(new_lines, old_lines=None, limit=80,
                         separator=5*' ', group_separator='\n\n'):
    if old_lines is None:
        return new_lines
    elif len(old_lines[0])+len(new_lines[0])+len(separator) > limit:
        print '\n'.join(old_lines) + group_separator
        return new_lines
    else:
        return [separator.join(line) for line in zip(old_lines, new_lines)]

def print_packed(data, separator=5*' '):
    lines = pack_lines_and_print(data[0], separator=separator)
    for d in data[1:]:
        lines = pack_lines_and_print(d, lines, separator=separator)
    print '\n'.join(lines)

def apply_moves(board, *moves):
    for move in moves:
        #assert valid_move(board, move)
        board[move[0]], board[move[1]], board[move[2]] = '.', '.', move[2]

def count_pieces(board):
    return sum(not is_hole(p) for p in board.values())

def show_solution(solution_string, moves, solitaire):
    empty, colon, rest = solution_string.partition(':')
    board = make_board(empty)
    end, eq, move2 = rest.partition('=')
    move2 = move2.replace('/', ',')
    solution = []
    for move in (move2_to_move3(m, moves) for m in move2.split(',')):
        apply_moves(board, move)
        b = board_string(board, solitaire)
        b.insert(0,move.center(len(b[0])))
        solution.append(b)
    print_packed(solution)
        
solitaire = make_board_from_shape("""
    a b c    
    d e f    
g h i j k l m
n o p x P O N
M L K J I H G
    F E D    
    C B A    
""")

print('Board style')
print('\n'.join(solitaire))
print('')

solutions = '''
x:x=ex,lj,ck,Pf,DP,GI,JH,mG,GI,ik,gi,LJ,JH,Hl,lj,jh,CK,pF,AC,CK,Mg,gi,ac,ck,kI,dp,pF,FD,DP,Pp,ox
x:x=ex,lj,xe/hj,Ki,jh/ai,ca,fd,hj,ai,jh/MK,gM,hL,Fp,MK,pF/CK,DF,AC,JL,CK,LJ/PD,GI,mG,JH,GI,DP/Ox
j:j=lj,Ik,jl/hj,Ki,jh/mk,Gm,Hl,fP,mk,Pf/ai,ca,fd,hj,ai,jh/MK,gM,hL,Fp,MK,pF/CK,DF,AC,JL,CK,LJ/Jj
i:i=ki,Jj,ik/lj,Ik,jl/AI,FD,CA,HJ,AI,JH/mk,Hl,Gm,fP,mk,Pf/ai,ca,fd,hj,ai,jh/gi,Mg,Lh,pd,gi,dp/Ki
e:e=xe/lj,Ik,jl/ck,ac,df,lj,ck,jl/GI,lH,mG,DP,GI,PD/AI,FD,CA,JH,AI,HJ/pF,MK,gM,JL,MK,Fp/hj,ox,xe
d:d=fd,xe,df/lj,ck,ac,Pf,ck,jl/DP,KI,PD/GI,lH,mG,DP,GI,PD/CK,DF,AC,LJ,CK,JL/MK,gM,hL,pF,MK,Fp/pd
b:b=jb,lj/ck,ac,Pf,ck/DP,GI,mG,JH,GI,PD/LJ,CK,JL/MK,gM,hL,pF,MK,Fp/xo,dp,ox/xe/AI/BJ,JH,Hl,lj,jb
b:x=jb,lj/ck,ac,Pf,ck/DP,GI,mG,JH,GI,PD/LJ,CK,JL/MK,gM,hL,pF,MK,Fp/xo,dp,ox/xe/AI/BJ,JH,Hl,lj,ex
a:a=ca,jb,ac/lj,ck,jl/Ik,pP,KI,lj,Ik,jl/GI,lH,mG,DP,GI,PD/CK,DF,AC,LJ,CK,JL/dp,gi,pd,Mg,Lh,gi/ia
a:p=ca,jb,ac/lj,ck,jl/Ik,pP,KI,lj,Ik,jl/GI,lH,mG,DP,GI,PD/CK,DF,AC,LJ,CK,JL/dp,gi,pd,Mg,Lh,gi/dp
'''.strip().splitlines()

moves = make_moves(solitaire)
#pprint(moves)

positions, symbols = make_dicts(solitaire)
#print('x', positions['x'], symbols[positions['x']], get_by_iter(solitaire, positions['x']))
print('Board middle empty')
board = make_board('x')
print_board(board,solitaire)
# demonstrate move check by alternative first moves
print '\nPossible moves\n'
for move in possible_moves(board, moves):
    new_board = dict(board.items())
    apply_moves(new_board, move)
    print_board(new_board, solitaire)
    print('Pieces left: %i' % count_pieces(new_board))
    print('Next moves available:')
    print(', '.join(possible_moves(new_board, moves)))
    print('')
# showing first of solutions
show_solution(solutions[0], moves, solitaire)