Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

queen-attack: re-implement according to canonical data 2.1.0 #1351

Merged
merged 4 commits into from
Feb 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 16 additions & 26 deletions exercises/queen-attack/example.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,17 @@
def board(pos1, pos2):
validate_position(pos1, pos2)
x1, y1 = pos1
x2, y2 = pos2
b = [['_'] * 8 for i in range(8)]
b[x1][y1] = 'W'
b[x2][y2] = 'B'
return [''.join(r) for r in b]
class Queen(object):
def __init__(self, row, column):
if not 0 <= row <= 7 or not 0 <= column <= 7:
raise ValueError("Invalid queen position: queen out of the board")
self.row = row
self.column = column


def can_attack(pos1, pos2):
validate_position(pos1, pos2)
x1, y1 = pos1
x2, y2 = pos2
dx = x1 - x2 if x1 >= x2 else x2 - x1
dy = y1 - y2 if y1 >= y2 else y2 - y1
if dx == dy or dx == 0 or dy == 0:
return True
return False


def validate_position(pos1, pos2):
if any(x < 0 or x > 7 for x in pos1 + pos2):
raise ValueError('Invalid queen position: queen out of the board')
if pos1 == pos2:
raise ValueError('Invalid queen position: both queens in the same '
'square: {0}'.format(pos1))
def can_attack(self, another_queen):
dx = abs(self.row - another_queen.row)
dy = abs(self.column - another_queen.column)
if dx == dy == 0:
raise ValueError(
'Invalid queen position: both queens in the same square')
elif dx == dy or dx == 0 or dy == 0:
return True
else:
return False
10 changes: 5 additions & 5 deletions exercises/queen-attack/queen_attack.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
def board(white_position, black_position):
pass
class Queen(object):
def __init__(self, row, column):
pass


def can_attack(white_position, black_position):
pass
def can_attack(self, another_queen):
pass
67 changes: 18 additions & 49 deletions exercises/queen-attack/queen_attack_test.py
Original file line number Diff line number Diff line change
@@ -1,92 +1,61 @@
import unittest

from queen_attack import board, can_attack
from queen_attack import Queen


# Tests adapted from `problem-specifications//canonical-data.json` @ v2.0.0
# Tests adapted from `problem-specifications//canonical-data.json` @ v2.1.0

class QueenAttackTest(unittest.TestCase):

# Test creation of Queens with valid and invalid positions
def test_queen_valid_position(self):
try:
board((1, 1), (2, 2))
Queen(2, 2)
except ValueError:
self.fail("Unexpected Exception")

def test_queen_negative_row(self):
with self.assertRaisesWithMessage(ValueError):
board((1, 1), (-2, 2))
Queen(-2, 2)

def test_queen_invalid_row(self):
with self.assertRaisesWithMessage(ValueError):
board((1, 1), (8, 4))
Queen(8, 4)

def test_queen_negative_column(self):
with self.assertRaisesWithMessage(ValueError):
board((1, 1), (2, -2))
Queen(2, -2)

def test_queen_invalid_column(self):
with self.assertRaisesWithMessage(ValueError):
board((1, 1), (4, 8))
Queen(4, 8)

# Test the ability of one queen to attack another
def test_attack_false(self):
self.assertIs(can_attack((2, 4), (6, 6)), False)
self.assertIs(Queen(2, 4).can_attack(Queen(6, 6)), False)

def test_attack_same_row(self):
self.assertIs(can_attack((2, 4), (2, 6)), True)
self.assertIs(Queen(2, 4).can_attack(Queen(2, 6)), True)

def test_attack_same_column(self):
self.assertIs(can_attack((4, 5), (2, 5)), True)
self.assertIs(Queen(4, 5).can_attack(Queen(2, 5)), True)

def test_attack_diagonal1(self):
self.assertIs(can_attack((2, 2), (0, 4)), True)
self.assertIs(Queen(2, 2).can_attack(Queen(0, 4)), True)

def test_attack_diagonal2(self):
self.assertIs(can_attack((2, 2), (3, 1)), True)
self.assertIs(Queen(2, 2).can_attack(Queen(3, 1)), True)

def test_attack_diagonal3(self):
self.assertIs(can_attack((2, 2), (1, 1)), True)
self.assertIs(Queen(2, 2).can_attack(Queen(1, 1)), True)

def test_attack_diagonal4(self):
self.assertIs(can_attack((2, 2), (5, 5)), True)

# Tests beyond this point are not part of the canonical data.

# If either board or can_attack are called with an invalid board position
# they should raise a ValueError with a meaningful error message.
def test_invalid_position_can_attack(self):
with self.assertRaisesWithMessage(ValueError):
can_attack((0, 0), (7, 8))

def test_queens_same_position_board(self):
with self.assertRaisesWithMessage(ValueError):
board((2, 2), (2, 2))
self.assertIs(Queen(2, 2).can_attack(Queen(5, 5)), True)

# Track-specific tests
def test_queens_same_position_can_attack(self):
with self.assertRaisesWithMessage(ValueError):
can_attack((2, 2), (2, 2))

def test_board1(self):
ans = ['________',
'________',
'___W____',
'________',
'________',
'______B_',
'________',
'________']
self.assertEqual(board((2, 3), (5, 6)), ans)

def test_board2(self):
ans = ['______W_',
'_______B',
'________',
'________',
'________',
'________',
'________',
'________']
self.assertEqual(board((0, 6), (1, 7)), ans)
Queen(2, 2).can_attack(Queen(2, 2))

# Utility functions
def setUp(self):
Expand Down