我正在用Python编写一个Chess程序,需要生成一个骑士的所有动作。对于那些不熟悉国际象棋的人来说,骑士会以L形移动。
所以,给定(2, 4)
的位置,骑士可以移动到(0, 3)
,(0, 5)
,(1, 2)
,(3, 2
)等等。 (最多)八个不同的动作。
我想编写一个名为knight_moves
的函数,它在列表中生成这些元组。在Python中最简单的方法是什么?
def knight_moves(position):
''' Returns a list of new positions given a knight's current position. '''
pass
答案 0 :(得分:6)
为什么不存储它可以移动的相对对?因此,从你的起点开始,添加一组可能的移动,然后你只需要进行一次完整性检查以确保它们仍在边界内,或者不在另一块上。
即给定(2,4)起点,选项为(-2,-1),( - 2,+ 1),( - 1,+ 2),(+ 2,+ 1) 因此,相对位置将始终相同。
答案 1 :(得分:4)
好的,非常感谢Niall Byrne,我想出了这个:
from itertools import product
def knight_moves(position):
x, y = position
moves = list(product([x-1, x+1],[y-2, y+2])) + list(product([x-2,x+2],[y-1,y+1]))
moves = [(x,y) for x,y in moves if x >= 0 and y >= 0 and x < 8 and y < 8]
return moves
答案 2 :(得分:4)
不熟悉国际象棋......
deltas = [(-2, -1), (-2, +1), (+2, -1), (+2, +1), (-1, -2), (-1, +2), (+1, -2), (+1, +2)]
def knight_moves(position):
valid_position = lambda (x, y): x >= 0 and y >= 0 and ???
return filter(valid_position, map(lambda (x, y): (position[0] + x, position[1] + y), deltas))
答案 3 :(得分:3)
我建议您使用位板,而不是使用数组。它们不仅易于操作,而且还减少了边界检查的需要。只需12个位板,您就可以编码整个游戏所需的信息。
https://www.chessprogramming.org/Bitboards
位板的基本思想是使用64位整数,如果位上存在一块则设置为1。例如,如果你有一个64位整数来表示白色骑士,你可以在游戏开始时设置第2和第6位,因为它们是白骑士所在的位置。使用这种表示法,可以很容易地计算出骑士的动作。很容易计算其他部分&#39;也动了。
通过这种表示,您可以查看这个国际象棋引擎的链接,以获得现成的算法来实现骑士的移动。
http://www.mayothi.com/nagaskakichess6.html
答案 4 :(得分:1)
这是一个简单的实现:
def knights_moves():
a = []
b = (1, 2)
while 1:
a.append(b)
b = (-b[0], b[1])
a.append(b)
b = (b[1], b[0])
if b in a:
return a
[(1, 2), (-1, 2), (2, -1), (-2, -1), (-1, -2), (1, -2), (-2, 1), (2, 1)]
从那里你可以简单地将当前位置添加到此列表的每个成员,然后仔细检查有效性。
答案 5 :(得分:1)
完成xiaowl的回答,
possible_places = [(-2, -1), (-2, +1), (+2, -1), (+2, +1), (-1, -2), (-1, +2), (+1, -2), (+1, +2)]
def knight_moves(cur_pos):
onboard = lambda (x, y): x >= 0 and y >= 0 and x<8 and y<8
eval_move = lambda(x,y): (cur_pos[0] + x, cur_pos[1] + y)
return filter(onboard, map(eval_move, possible_places))
答案 6 :(得分:1)
对于骑士的动作:
def getAllValidMoves(x0, y0):
deltas = [(-2, -1), (-2, +1), (+2, -1), (+2, +1), (-1, -2), (-1, +2), (+1, -2), (+1, +2)]
validPositions = []
for (x, y) in deltas:
xCandidate = x0 + x
yCandidate = y0 + y
if 0 < xCandidate < 8 and 0 < yCandidate < 8:
validPositions.append([xCandidate, yCandidate])
return validPositions
print getAllValidMoves(3,3)
我只是存储了所有可能的增量,将它们中的每一个应用到“初始位置”并保存了棋盘内的那些
答案 7 :(得分:1)
如果您不熟悉解析几何(或复数几何),这听起来像是一个过大的杀伤力,但是当您遇到以下问题时,我想出了一个非常优雅的数学解决方案 我正在对零件运动进行验证。
骑士的举动位于一个圆上,可以定义为 (x-x_0)^ 2 +(y-y_0)^ 2 = 5其中x_0和y_0是骑士当前的坐标。如果切换到极坐标,则可以使用以下简单代码获取所有可能的坐标:
import math
def knight_moves(x,y):
new_positions=[]
r=math.sqrt(5) #radius of the circle
for phi in [math.atan(2),math.atan(1/2)]: #angles in radians
for quadrant in range(4):
angle=phi+quadrant*math.pi/2 # add 0, 90, 180, 270 degrees in radians
new_x=round(x+r*math.cos(angle))
new_y=round(y+r*math.sin(angle))
if max(new_x,new_y,7-new_x,7-new_y)<=7: #validation whether the move is in grid
new_positions.append([new_x,new_y])
return(new_positions)
def validate_knight_move(x,y,x_0,y_0):
return((x-x_0)**2+(y-y_0)**2==5)
x_0=2
y_0=4
moves=knight_moves(x_0,y_0)
print(moves)
validation=[validate_knight_move(move[0],move[1],x_0,y_0) for move in moves]
print(validation)
[[3, 6], [0, 5], [1, 2], [4, 3], [4, 5], [1, 6], [0, 3], [3, 2]]
[True, True, True, True, True, True, True, True]
这里要指出一点,验证位置比直接构造要容易得多。因此,最好尝试一下所有可能的移动是否都位于圆上:
def knight_moves2(x,y):
new_positions=[]
for dx in [-2,-1,1,2]:
for dy in [-2,-1,1,2]:
if(validate_knight_move(x+dx,y+dy,x,y)): #is knight move?
if max(x+dx,y+dy,7-(x+dx),7-(y+dy))<=7: #validation whether the move is in grid
new_positions.append([x+dx,y+dy])
return(new_positions)
new_positions=knight_moves2(x_0,y_0)
print(new_positions)
[[0, 3], [0, 5], [1, 2], [1, 6], [3, 2], [3, 6], [4, 3], [4, 5]]
答案 8 :(得分:0)
from itertools import product
def moves():
""" The available (relative) moves"""
a = list(product( (1, -1), (2,-2)))
return a + [tuple(reversed(m)) for m in a]
def neighbors(a,b):
# true if x,y belongs in a chess table
in_table = lambda (x, y): all((x < 8, y < 8, x >= 0, y >= 0))
# returns the possible moving positions
return filter(in_table, [(a+x, b+y) for x, y in moves()])
“邻居”是骑士可以从a,b
获得的可用位置