Skip to content

Commit 8184dab

Browse files
author
jegner
committed
solve place-queens from ice base island
1 parent d679b1d commit 8184dab

File tree

3 files changed

+201
-0
lines changed

3 files changed

+201
-0
lines changed

berserk-rook.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ def __mul__(self, scale):
2626
return Loc(self.r * scale, self.c * scale)
2727

2828

29+
@staticmethod
2930
def fromChessStr(chessStr):
3031
return Loc(ord(chessStr[1]) - ord('1'), ord(chessStr[0]) - ord('a'))
3132

place-queens.png

932 KB
Loading

place-queens.py

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
'''
2+
author: Jacob Egner
3+
date: 2015-08-04
4+
island: ice base
5+
6+
puzzle URLs:
7+
http://www.checkio.org/mission/place-queens/
8+
https://github.com/Bryukh-Checkio-Tasks/checkio-mission-place-queens
9+
10+
for latest versions of my solutions, see my checkio solution github repo:
11+
https://github.com/jmegner/CheckioPuzzles
12+
'''
13+
14+
15+
import collections
16+
17+
18+
g_boardSize = 8
19+
20+
21+
class Loc(collections.namedtuple('Loc', ['r', 'c'])):
22+
23+
@staticmethod
24+
def fromChessStr(chessStr):
25+
return Loc(ord(chessStr[1]) - ord('1'), ord(chessStr[0]) - ord('a'))
26+
27+
28+
def toChessStr(self):
29+
return chr(self.c + ord('a')) + chr(self.r + ord('1'))
30+
31+
32+
def posDiag(self):
33+
return self.r + self.c
34+
35+
36+
def negDiag(self):
37+
return self.r - self.c + g_boardSize - 1
38+
39+
40+
def hasQueenConflict(self, other):
41+
return( self.r == other.r or self.c == other.c
42+
or self.posDiag() == other.posDiag()
43+
or self.negDiag() == other.negDiag()
44+
)
45+
46+
47+
################################################################################
48+
# below is a fairly efficient solution, with simplicity sacrificed
49+
50+
def place_queens(givenQueenStrs):
51+
queens = [Loc.fromChessStr(queenStr) for queenStr in givenQueenStrs]
52+
53+
rowCounts = [0] * g_boardSize
54+
colCounts = [0] * g_boardSize
55+
posDiagCounts = [0] * (2 * g_boardSize - 1)
56+
negDiagCounts = [0] * (2 * g_boardSize - 1)
57+
58+
for queen in queens:
59+
rowCounts[queen.r] += 1
60+
colCounts[queen.c] += 1
61+
posDiagCounts[queen.posDiag()] += 1
62+
negDiagCounts[queen.negDiag()] += 1
63+
64+
for count in rowCounts + colCounts + posDiagCounts + negDiagCounts:
65+
if count > 1:
66+
return set()
67+
68+
tryMoreQueens(queens, rowCounts, colCounts, posDiagCounts, negDiagCounts)
69+
70+
if len(queens) == g_boardSize:
71+
queenSet = set(queen.toChessStr() for queen in queens)
72+
return queenSet
73+
74+
return set()
75+
76+
77+
def tryMoreQueens(queens, rowCounts, colCounts, posDiagCounts, negDiagCounts):
78+
if len(queens) == g_boardSize:
79+
return True
80+
81+
for r, rowCount in enumerate(rowCounts):
82+
if rowCount:
83+
continue
84+
85+
for c, colCount in enumerate(colCounts):
86+
if colCount:
87+
continue
88+
89+
tryLoc = Loc(r, c)
90+
posDiag = tryLoc.posDiag()
91+
negDiag = tryLoc.negDiag()
92+
93+
if posDiagCounts[posDiag] or negDiagCounts[negDiag]:
94+
continue
95+
96+
queens.append(tryLoc)
97+
rowCounts[r] += 1
98+
colCounts[c] += 1
99+
posDiagCounts[posDiag] += 1
100+
negDiagCounts[negDiag] += 1
101+
102+
if(tryMoreQueens(
103+
queens, rowCounts, colCounts, posDiagCounts, negDiagCounts)
104+
):
105+
return True
106+
107+
queens.pop()
108+
rowCounts[r] -= 1
109+
colCounts[c] -= 1
110+
posDiagCounts[posDiag] -= 1
111+
negDiagCounts[negDiag] -= 1
112+
113+
return False
114+
115+
116+
################################################################################
117+
# below is a very simple but fairly inefficient solution
118+
119+
def place_queens_simple(givenQueenStrs):
120+
givenQueens = [Loc.fromChessStr(queenStr) for queenStr in givenQueenStrs]
121+
122+
for queen1Idx, queen1 in enumerate(givenQueens):
123+
for queen2 in givenQueens[queen1Idx + 1:]:
124+
if queen1.hasQueenConflict(queen2):
125+
return set()
126+
127+
fullQueens = tryMoreQueensSimple(givenQueens)
128+
129+
if len(fullQueens) == g_boardSize:
130+
queenSet = set(queen.toChessStr() for queen in fullQueens)
131+
return queenSet
132+
133+
return set()
134+
135+
136+
def tryMoreQueensSimple(queens):
137+
if len(queens) == g_boardSize:
138+
return queens
139+
140+
for r in range(g_boardSize):
141+
for c in range(g_boardSize):
142+
tryLoc = Loc(r, c)
143+
locHasConflict = False
144+
145+
for queen in queens:
146+
if tryLoc.hasQueenConflict(queen):
147+
locHasConflict = True
148+
break
149+
150+
if not locHasConflict:
151+
fullQueens = tryMoreQueensSimple(queens + [tryLoc])
152+
if fullQueens:
153+
return fullQueens
154+
155+
return []
156+
157+
158+
if __name__ == '__main__':
159+
from itertools import combinations
160+
COLS = "abcdefgh"
161+
ROWS = "12345678"
162+
163+
THREATS = {c + r: set(
164+
[c + ROWS[k] for k in range(8)] +
165+
[COLS[k] + r for k in range(8)] +
166+
[COLS[k] + ROWS[i - j + k] for k in range(8) if 0 <= i - j + k < 8] +
167+
[COLS[k] + ROWS[- k + i + j] for k in range(8) if 0 <= - k + i + j < 8])
168+
for i, r in enumerate(ROWS) for j, c in enumerate(COLS)}
169+
170+
def check_coordinate(coor):
171+
c, r = coor
172+
return c in COLS and r in ROWS
173+
174+
def checker(func, placed, is_possible):
175+
user_set = func(placed.copy())
176+
if not all(isinstance(c, str) and len(c) == 2 and check_coordinate(c) for c in user_set):
177+
print("Wrong Coordinates")
178+
return False
179+
threats = []
180+
for f, s in combinations(user_set.union(placed), 2):
181+
if s in THREATS[f]:
182+
threats.append([f, s])
183+
if not is_possible:
184+
if user_set:
185+
print("Hm, how did you place them?")
186+
return False
187+
else:
188+
return True
189+
if not all(p in user_set for p in placed):
190+
print("You forgot about placed queens.")
191+
return False
192+
if is_possible and threats:
193+
print("I see some problems in this placement.")
194+
return False
195+
return True
196+
197+
assert checker(place_queens, {"b2", "c4", "d6", "e8"}, True), "1st Example"
198+
assert checker(place_queens, {"b2", "c4", "d6", "e8", "a7", "g5"}, False), "2nd Example"
199+
assert checker(place_queens, {"a1", "h8"}, False), "Test Extra 2, conflict in givens"
200+

0 commit comments

Comments
 (0)