I don't think board
actually serves any purpose.
Your code for parsing input to black and white piece-locations looks good, and should probably be made into a function.
For debugging, it would be useful to have a function which takes black and white piece-locations and prints the board - for example using the characters #
for black, O
for white, and .
for empty. This will help you to see what your program is doing.
For each direction, you should have a function (ie left
) which returns the next location (or None
if it is on the edge of the board) and another (ie left_lst
) which returns a list of consecutive locations in that direction. So left(17)
returns 16
, left(16)
returns None
, and left_lst(19)
returns [18, 17, 16]
. Hint: how can you implement left_lst
in terms of left
?
Then: for each white piece, check what can be captured by moving toward each direction or away from each direction. You know that there should only be one solution, so as soon as you find it you can return it; if you do not find any, return None
.
Hope that helps!
For fun and interest, here's the solution I came up with. Hope you learn lots!
# https://s3.amazonaws.com/iedu-attachments-question/5a989d787772b7fd88c063aff8393d34_1bee2d300c35eec13edf0a3af515a5a5.pdf
NUM_PROBS = 5
# Board looks like
# 1 2 3 4 5
# 6 7 8 9 10
# 11 12 13 14 15
# 16 17 18 19 20
# 21 22 23 24 25
WIDTH = 5
HEIGHT = 5
# display characters for printing:
WHITE = 'O'
BLACK = '#'
EMPTY = '.'
from itertools import product
def parse(s):
"""
Input: string of comma-delimited integers
ex: "3, 12, 17, 22, 3, 9, 14, 10"
format is num_white, *[white locations], num_black, *[black locations]
Output: [white locations], [black locations]
ex: [12, 17, 22], [9, 14, 10]
"""
ints = [int(i) for i in s.split(',')]
num_white = ints[0]
num_black = ints[num_white + 1]
return ints[1:num_white + 1], ints[-num_black:]
def location_to_coords(location):
"""
Given a location on the board,
return 0-based (y,x) coordinates
ex: location_to_coords(16) returns (3, 0)
"""
return divmod(location - 1, WIDTH)
def coords_to_location(y, x):
"""
Given (y, x) coordinates,
return a location on the board
ex: coords_to_location(3, 0) returns 16
"""
return y * WIDTH + x + 1
def print_board(whites, blacks):
# make an empty board
board = [[EMPTY] * WIDTH for row in range(HEIGHT)]
# add white pieces
for location in whites:
y, x = location_to_coords(location)
board[y][x] = WHITE
# add black pieces
for location in blacks:
y, x = location_to_coords(location)
board[y][x] = BLACK
# show the result
print('\n'.join(''.join(row) for row in board))
def make_dir_fn(dy, dx):
"""
Given a direction, make a function
which, given a location, returns
the next location in that direction
(or None if no such location exists)
"""
def dir_fn(location):
y, x = location_to_coords(location)
if 0 <= y + dy < HEIGHT and 0 <= x + dx < WIDTH:
return coords_to_location(y + dy, x + dx)
else:
return None
return dir_fn
def make_lst_fn(dir_fn):
"""
Given a direction function, make a function
which, given a location, returns a list
of all consecutive locations in that direction
to the edge of the board
"""
def lst_fn(location):
result = []
while True:
location = dir_fn(location)
if location is None:
break
else:
result.append(location)
return result
return lst_fn
# direction functions (one step in the named direction)
left = make_dir_fn( 0, -1)
right = make_dir_fn( 0, 1)
up = make_dir_fn(-1, 0)
down = make_dir_fn( 1, 0)
# relationships between direction functions
dir_fns = [left, right, up, down]
lst_fn = {dir_fn: make_lst_fn(dir_fn) for dir_fn in dir_fns}
opposite_dir_fn = {left: right, right: left, up: down, down: up}
def attack_toward(location, dir_fn, whites, blacks):
"""
Return a list of pieces captured by attacking toward given direction
"""
# make sure attacker is white (swap if needed)
if location in blacks:
whites, blacks = blacks, whites
# make sure we have a valid attacker
if location not in whites:
return []
# make sure we have a space to move to
next_location = dir_fn(location)
if (next_location is None) or (next_location in whites) or (next_location in blacks):
return []
# get list of attacked locations
attacked = lst_fn[dir_fn](next_location)
captured = []
for location in attacked:
if location in blacks:
captured.append(location)
else:
break
return captured
def attack_away(location, dir_fn, whites, blacks):
"""
Return a list of pieces captured by attacking away from given direction
"""
# make sure attacker is white (swap if needed)
if location in blacks:
whites, blacks = blacks, whites
# make sure we have a valid attacker
if location not in whites:
return []
# make sure we have a space to move to
next_location = opposite_dir_fn[dir_fn](location)
if (next_location is None) or (next_location in whites) or (next_location in blacks):
return []
# get list of attacked locations
attacked = lst_fn[dir_fn](location)
captured = []
for location in attacked:
if location in blacks:
captured.append(location)
else:
break
return captured
attack_fns = [attack_toward, attack_away]
def main():
for prob in range(NUM_PROBS):
# get problem
whites, blacks = parse(input())
# pick an attacker, a direction, and an attack method
for location, dir_fn, attack_fn in product(whites, dir_fns, attack_fns):
captured = attack_fn(location, dir_fn, whites, blacks)
# stop when a successful attack is found!
if captured: break
# display results
if captured:
print(", ".join(str(i) for i in sorted(captured)))
else:
print("NONE")
if __name__ == "__main__":
main()