7

我正在用 Python 编写一个国际象棋程序,它需要生成一个骑士的所有动作。对于那些不熟悉国际象棋的人来说,马以 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
4

9 回答 9

9

好的,感谢 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
于 2013-10-15T03:13:22.130 回答
8

为什么不存储它可以移动的相对对?因此,以您的起点,并添加一组可能的移动远离它,然后您只需要进行健全性检查以确保它们仍在边界内,或者不在另一块上。

即给定您的 (2, 4) 起点,选项是 (-2,-1), (-2,+1), (-1,+2), (+2,+1) 相对位置将因此总是一样的。

于 2013-10-15T03:10:05.717 回答
5

不熟悉围棋...

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))
于 2013-10-15T03:17:49.117 回答
4

我建议您使用位板,而不是使用数组。它们不仅非常容易操作,而且还可以减少边界检查的需要。只需 12 个位板,您就可以对整个游戏所需的信息进行编码。

https://www.chessprogramming.org/Bitboards

位板的基本思想是使用 64 位整数,如果位上有一块,则设置为 1。例如,如果您有一个 64 位整数来表示白马,您将在游戏开始时设置第 2 位和第 6 位,因为它们是白马所在的位置。使用这种表示法,计算骑士的动作变得很容易。计算其他棋子的移动也很容易。

有了这个表示,你可以看看这个国际象棋引擎的链接,以获得一个现成的算法来实现骑士的移动。
http://www.mayothi.com/nagaskakichess6.html

于 2014-10-25T04:16:34.490 回答
2

如果您不熟悉解析几何(或复数几何),这听起来可能有点矫枉过正,但是当我对零件的运动进行验证时,我想出了一个非常优雅的数学解决方案。

骑士的移动位于可以定义为 (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]]
于 2020-04-04T23:07:03.383 回答
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)]

从那里您可以简单地将当前位置添加到此列表的每个成员,然后仔细检查有效性。

于 2013-11-29T21:54:41.137 回答
1

完成小猫的回答,

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))
于 2014-01-09T06:22:32.480 回答
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)

我只是存储了所有可能的增量,将它们中的每一个应用于“初始位置”并保存了棋盘内的那些

于 2017-03-17T15:07:04.433 回答
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 出发的可用位置

于 2016-01-07T19:06:19.713 回答