Weekly Challenge 281
Sorry for being MIA over the last few weeks. I've moved house and a new job, so haven't had a chance to partake in the challenges over this time.
Each week Mohammad S. Anwar sends out The Weekly Challenge, a chance for all of us to come up with solutions to two weekly tasks. My solutions are written in Python first, and then converted to Perl. It's a great way for us all to practice some coding.
Task 1: Check Color
Task
You are given coordinates, a string that represents the coordinates of a square of the chessboard as shown below:
Write a script to return true
if the square is light, and false
if the square is dark.
My solution
This is relatively straight forward. The first thing I do is check that the provided position is valid (first character is a
-h
and the second character is between 1 and 8).
I then check if the first letter is a
, c
, e
or g
and the number is even, or the first letter is b
, d
, f
or h
and the number is odd, return true
. Otherwise return false
.
def check_color(coords: str) -> bool:
if not re.search('^[a-h][1-8]$', coords):
raise ValueError('Not a valid chess coordinate!')
if coords[0] in ('a', 'c', 'e', 'g') and int(coords[1]) % 2 == 0:
return True
if coords[0] in ('b', 'd', 'f', 'h') and int(coords[1]) % 2 == 1:
return True
return False
Examples
$ ./ch-1.py d3
true
$ ./ch-1.py g5
false
$ ./ch-1.py e6
true
Task 2: Knight’s Move
Task
A Knight in chess can move from its current position to any square two rows or columns plus one column or row away. So in the diagram below, if it starts a S, it can move to any of the squares marked E.
Write a script which takes a starting position and an ending position and calculates the least number of moves required.
My solution
This one is more detailed. I start with the follow variables:
-
deltas
is a tuples of lists (array of arrays in Perl) with the eight ways the knight can move from its current position. -
target
is the cell that we want to reach. For this I convert the first letter to a number from one to 8. It's stored as a tuple, the first value is the column and the second value is the row. -
moves
is the number of moves made and starts at one. -
seen
is a list of cells we have already visited. -
coords
is a list of current positions of a knight. It starts with the starting coordinate.
def knights_move(start_coord: str, end_coord: str) -> int:
for coord in (start_coord, end_coord):
if not re.search('^[a-h][1-8]$', coord):
raise ValueError(
f'The position {coord} is not a valid chess coordinate!')
deltas = ([2, 1], [2, -1], [-2, 1], [-2, -1],
[1, 2], [1, -2], [-1, 2], [-1, -2])
coords = [convert_coord_to_list(start_coord)]
target = convert_coord_to_list(end_coord)
moves = 1
seen = []
I then have a double loop of the current coords
list and the deltas
list. A set a variable new_pos
that represents the new coordinates for the knight. If this leads to a position outside the board or a coordinate we've already been to, I skip it. If it lands on the target, I return the moves
value.
After the loop, I reset the coords
list to the coordinates collected through the iterations, and increment the moves
value by one. This continues until we hit the target coordinate.
while True:
new_coords = []
for coord in coords:
for delta in deltas:
new_pos = (coord[0] + delta[0], coord[1] + delta[1])
if not 0 < new_pos[0] < 9 or not 0 < new_pos[1] < 9 or new_pos in seen:
continue
if new_pos == target:
return moves
new_coords.append(new_pos)
seen.append(new_pos)
coords = new_coords
moves += 1
Examples
$ ./ch-2.py g2 a8
4
$ ./ch-2.py g2 h2
3
Top comments (0)