我如何产生所有骑士的动作?

时间:2013-10-15 03:03:39

标签: python chess

我正在用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

9 个答案:

答案 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

获得的可用位置