2021-10-29 03:11:27 +02:00
#!/usr/bin/python3
2021-10-29 16:59:22 +02:00
import re
2021-10-30 17:19:55 +02:00
def draw_checkerboard ( status , space = " ▒ " , white_norm = " h " , white_knight = " H " , black_norm = " b " , black_knight = " B " , empty = " " , column = " 12345678 " , frstrow = " abcdefgh \n " ) :
""" Draw a checkerboard, status is the virtual representation of the board, as a bi-dimensional array, white/black norm/knight are the representation of the pieces
space is a non - walkable cell , empty is a walkable cell , column contains labels for the left column , frstrow the labels for the first row .
"""
2021-10-29 03:11:27 +02:00
bstr = " "
bstr + = frstrow
for row in range ( 0 , len ( status ) ) :
2021-10-30 03:05:01 +02:00
bstr + = column [ row ]
2021-10-29 03:11:27 +02:00
if row % 2 == 0 :
bstr + = space
for cell in range ( 0 , int ( len ( status ) / 2 ) ) :
if status [ row ] [ cell ] == 1 : #black normal piece
bstr + = black_norm
elif status [ row ] [ cell ] == 2 : #white normal piece
bstr + = white_norm
elif status [ row ] [ cell ] == 3 : #black knight piece
bstr + = black_knight
elif status [ row ] [ cell ] == 4 : #white knight piece
bstr + = white_knight
else : #empty
bstr + = empty
if ( cell < 3 ) :
bstr + = space
2021-10-30 17:19:55 +02:00
if row % 2 != 0 : #odd lines ends with space and a line feed, even ones just with the line feed
2021-10-29 03:11:27 +02:00
bstr + = space + " \n "
else :
bstr + = " \n "
return bstr
def position_resolver ( pos , board ) :
2021-10-30 17:19:55 +02:00
""" Checks if the position is valid and wether it contains a piece or not """
2021-10-29 03:11:27 +02:00
row , col = row_column_translation ( pos [ 1 ] , pos [ 0 ] )
if ( col == - 1 ) :
return - 1
else :
return board [ row ] [ col ]
def row_column_translation ( row , col ) :
2021-10-30 17:19:55 +02:00
""" Converts a coordinate made by a letter/number couple in the index usable with the array that represents the board """
2021-10-29 03:11:27 +02:00
row = int ( row ) - 1
if row % 2 != 0 :
cols = range ( ord ( " a " ) , ord ( " a " ) + 7 , 2 )
else :
cols = range ( ord ( " b " ) , ord ( " b " ) + 7 , 2 )
if ord ( col ) not in cols :
return - 1 , - 1
else :
return row , cols . index ( ord ( col ) )
2021-10-30 17:19:55 +02:00
def traslate_coord ( pos ) :
for en , p in enumerate ( pos ) :
temp_col = chr ( ( int ( pos [ en ] [ 1 ] ) - 1 ) + ord ( " a " ) )
temp_row = ord ( pos [ en ] [ 0 ] ) - ord ( " a " )
pos [ en ] = temp_col
pos [ en ] + = str ( temp_row + 1 )
return pos
def valid_move ( pos_toParse , turn , board , inversion = False ) :
""" Checks if the move is valid, execute it and returns the updated board """
2021-10-29 16:59:22 +02:00
#pos = pos_toParse.split(" ") #tricky part, pos[0] is the starting cell, pos[1] to pos[n] the destination point(s), for every coord, [x][0] is the column (the letter) and [x][1] the row (the number)
2021-10-30 17:19:55 +02:00
pos = re . findall ( " \\ b[abcdefgh][12345678] \\ b " , pos_toParse ) #both row-col and col-row are accepted
if len ( pos ) == 0 :
pos = re . findall ( " \\ b[12345678][abcdefgh] \\ b " , pos_toParse )
for en , x in enumerate ( pos ) :
pos [ en ] = x [ 1 ] + x [ 0 ]
if inversion :
pos = traslate_coord ( pos )
if len ( pos ) < 2 : #less than 2 coords were given, movement is invalid
2021-10-29 16:59:22 +02:00
return - 1
2021-10-29 03:11:27 +02:00
row_start , col_start = row_column_translation ( pos [ 0 ] [ 1 ] , pos [ 0 ] [ 0 ] )
if ( row_start == - 1 ) :
return - 1
if turn == 1 : #black turn
valid_piece = ( 1 , 3 )
foe_piece = ( 2 , 4 )
else : #white turn
valid_piece = ( 2 , 4 )
foe_piece = ( 1 , 3 )
start_cell = position_resolver ( pos [ 0 ] , board )
if start_cell not in valid_piece : #selected an opponent's piece or an empty cell
return - 1
if ( ( start_cell == 1 and abs ( ord ( pos [ 1 ] [ 0 ] ) - ord ( pos [ 0 ] [ 0 ] ) ) == 1 and ord ( pos [ 0 ] [ 1 ] ) - ord ( pos [ 1 ] [ 1 ] ) == - 1 ) or ( start_cell == 2 and abs ( ord ( pos [ 1 ] [ 0 ] ) - ord ( pos [ 0 ] [ 0 ] ) ) == 1 and ord ( pos [ 0 ] [ 1 ] ) - ord ( pos [ 1 ] [ 1 ] ) == 1 ) or ( ( start_cell == 4 or start_cell == 3 ) and abs ( ord ( pos [ 1 ] [ 0 ] ) - ord ( pos [ 0 ] [ 0 ] ) ) == 1 and abs ( ord ( pos [ 1 ] [ 1 ] ) - ord ( pos [ 0 ] [ 1 ] ) ) == 1 ) and len ( pos ) == 2 ) :
move_to = position_resolver ( pos [ 1 ] , board ) #check non-capturing movement, to be valid it must be 1 col shift and 1 row shift, for norm pieces direction is important, and it must be a single move
if ( move_to == 0 ) : #if the cell is empty, the move is valid
row , col = row_column_translation ( pos [ 0 ] [ 1 ] , pos [ 0 ] [ 0 ] )
board [ row ] [ col ] = 0
row , col = row_column_translation ( pos [ 1 ] [ 1 ] , pos [ 1 ] [ 0 ] )
if ( ( row == 0 ) and start_cell == 2 ) : #piece promotion
start_cell = 4
if ( ( row == 7 ) and start_cell == 1 ) :
start_cell = 3
board [ row ] [ col ] = start_cell
return board
2021-10-30 17:19:55 +02:00
else : #destination cell is not empty
2021-10-29 03:11:27 +02:00
return - 1
else :
for x in range ( 0 , len ( pos ) - 1 ) :
if ( start_cell == 1 and abs ( ord ( pos [ 1 ] [ 0 ] ) - ord ( pos [ 0 ] [ 0 ] ) ) == 2 and ord ( pos [ 0 ] [ 1 ] ) - ord ( pos [ 1 ] [ 1 ] ) == - 2 ) or ( start_cell == 2 and abs ( ord ( pos [ 1 ] [ 0 ] ) - ord ( pos [ 0 ] [ 0 ] ) ) == 2 and ord ( pos [ 0 ] [ 1 ] ) - ord ( pos [ 1 ] [ 1 ] ) == 2 ) or ( ( start_cell == 4 or start_cell == 3 ) and abs ( ord ( pos [ 1 ] [ 0 ] ) - ord ( pos [ 0 ] [ 0 ] ) ) == 2 and abs ( ord ( pos [ 1 ] [ 1 ] ) - ord ( pos [ 0 ] [ 1 ] ) ) == 2 ) :
move_to = position_resolver ( pos [ 1 ] , board )
if ( move_to == 0 ) : #check if destination is empty
shift_x = int ( ( ord ( pos [ 1 ] [ 0 ] ) - ord ( pos [ 0 ] [ 0 ] ) ) / 2 )
shift_y = int ( ( ord ( pos [ 1 ] [ 1 ] ) - ord ( pos [ 0 ] [ 1 ] ) ) / 2 )
if ( start_cell == 1 ) : #normal pieces can capture kings (to do: optional rule)
foe_piece = ( 2 , 4 )
#foe_piece = (2,)
elif ( start_cell == 2 ) :
foe_piece = ( 1 , 3 )
#foe_piece = (1,)
row , col = row_column_translation ( chr ( ord ( pos [ 0 ] [ 1 ] ) + shift_y ) , chr ( ord ( pos [ 0 ] [ 0 ] ) + shift_x ) ) #check if an opponent piece lies in between start and destination
if ( board [ row ] [ col ] in foe_piece ) :
board [ row ] [ col ] = 0
row , col = row_column_translation ( pos [ 0 ] [ 1 ] , pos [ 0 ] [ 0 ] )
board [ row ] [ col ] = 0
row , col = row_column_translation ( pos [ 1 ] [ 1 ] , pos [ 1 ] [ 0 ] )
board [ row ] [ col ] = start_cell
if ( ( row == 0 ) and start_cell == 2 ) : #piece promotion
start_cell = 4
if ( ( row == 7 ) and start_cell == 1 ) :
start_cell = 3
pos . pop ( 0 ) #if there are other moves this check loops
2021-10-30 17:19:55 +02:00
else : #one of the pieces moves are invalid
2021-10-29 03:11:27 +02:00
return - 1
2021-10-30 17:19:55 +02:00
else : #destination not empty
2021-10-29 03:11:27 +02:00
return - 1
else :
return - 1
return board
def init_board ( ) :
checkerboard = [ ]
for row in range ( 0 , 8 ) :
if ( row < = 2 ) :
checkerboard . append ( [ 1 , 1 , 1 , 1 ] )
elif ( row > = 5 ) :
checkerboard . append ( [ 2 , 2 , 2 , 2 ] )
else :
checkerboard . append ( [ 0 , 0 , 0 , 0 ] )
return checkerboard
def checkWin ( board ) :
black_won = True
white_won = True
for row in board :
if ( 1 in row ) or ( 3 in row ) :
white_won = False
if ( 2 in row ) or ( 4 in row ) :
black_won = False
return ( white_won , black_won )
def main ( ) :
2021-10-30 17:19:55 +02:00
import sys
column_i = " 12345678 "
frstrow_i = " abcdefgh \n "
inverted = False
try :
if sys . argv [ 1 ] == " i " :
column_i = " abcdefgh "
frstrow_i = " 12345678 \n "
inverted = True
except IndexError :
pass
2021-10-29 03:11:27 +02:00
main_board = init_board ( )
s = " "
turn = False
while ( s != " q " ) :
2021-10-30 17:19:55 +02:00
vis_board = draw_checkerboard ( main_board , column = column_i , frstrow = frstrow_i )
2021-10-29 03:11:27 +02:00
print ( vis_board )
if turn :
s = input ( " Black move: " )
else :
s = input ( " White move: " )
if ( s != " q " ) :
2021-10-30 17:19:55 +02:00
result = valid_move ( s , turn , main_board , inversion = inverted )
2021-10-29 03:11:27 +02:00
if result != - 1 :
main_board = result
winner = checkWin ( main_board )
if winner [ 0 ] :
print ( " White won this game. " )
return turn
if winner [ 1 ] :
print ( " Black won this game. " )
return turn
turn = not turn
else :
print ( " Invalid move " )
return - 1
if __name__ == " __main__ " :
main ( )
quit ( )