通过python递归来解决孔明棋问题

本文介绍了一个使用Python编写的孔明棋(也称独立钻石棋)求解程序。通过建立坐标系和定义棋子移动规则,程序能够接受用户输入的棋盘状态并寻找解法。虽然代码存在效率问题,但展示了基础的搜索算法和棋盘游戏的实现思路。示例展示了不同输入下的解法输出,表明程序能成功找出至少一种可行的移动路径。
摘要由CSDN通过智能技术生成

孔明棋大家应该都不陌生。(好吧可能不一定)

简单来讲,是一种规则简单,但是过程并不见得容易,可以一个人玩的棋。

他有还一个有趣的名字:法国跳棋独立钻石。

我上手的是vx某小程序。玩法比最经典的32颗棋子多一些。

(经典玩法如下)

 一颗棋子可以跳过邻近一颗棋子(只包含上下左右,而没有斜向),被跳过的棋子就被拿开。

当然如果,跳过后的空位被占了的话,也是无法跳的。如果一颗棋子上下左右都没有棋子的话那就无法移动。当整个棋盘只剩一个棋子就成功了。

棋子越多自由度就越高,每一步的选择就更多,失败的走法总体上比成功地走法多得多,所以成功不算太容易。

所以为了,为了获得一种解法,或者理论上的所有解法,我决定写这样的一个程序。

简单的思路是先建立一个坐标系,如下:

 然后定义棋子空格,移动规则等等。

同样由于没必要实现全自动操作,所以采用一些麻烦但可以接受的方式输入棋盘数据。

如图操作:

 用0代表空缺,用1来代表棋子,用2来代表棋盘上无法到达的部分。

7*7部分只是为了检验和输入方便,需要的是下面那一行。

运行示例如下:

 为了提高速度,只返回了一种可能的解决方案。

大列表中的小列表代表移动,第一个坐标是被移动的棋子的位置,第二个则是被跳过(取走)的棋子的位置。值得一提的是,再返回结果中为了方便,将原坐标系的横纵坐标加一。

如下:

 代码如下:


class Square():
    def __init__(self,position,num):
        self.position = position #定义位置
        self.num = num

    def __str__(self):
        return '[%s,%s]'% (self.position,self.num)

    def getaline(self):
        linelist = []
        for each in wholepart:
            if each.position[1] == self.position[1]:
                linelist.append(each)
        return linelist

    def getarow(self):
        rowlist = []
        for each in wholepart:
            if each.position[0] == self.position[0]:
                rowlist.append(each)
        return rowlist

def getchance():
    chancelist = []
    for each in wholepart:
        if each.num == [1]:
            try:
                for eacharound in wholepart:
                    if eacharound.num == [1] and \
                    eacharound.position[0] == each.position[0] \
                and abs(eacharound.position[1]-each.position[1])==1:
                        if toplace([each,eacharound]).num == []:
                            chancelist.append([each,eacharound])
                    if eacharound.num == [1] and \
                    eacharound.position[1] == each.position[1] \
                and abs(eacharound.position[0]-each.position[0])==1:
                        if toplace([each,eacharound]).num == []:
                            chancelist.append([each,eacharound])
            except AttributeError:
                pass

    return chancelist

def move(chance):
    square1 = chance[0]
    square2 = chance[1]
    if square1.position[0]==square2.position[0]:
        for each in square1.getarow():
            if each.position[1] == 2*square2.position[1]\
                    -square1.position[1]:
                each.num = [1]
                square1.num = []
                square2.num = []
    elif square1.position[1]==square2.position[1]:
        for each in square1.getaline():
            if each.position[0] == 2*square2.position[0]\
                    -square1.position[0]:
                each.num = [1]
                square1.num = []
                square2.num = []

def unmove(chance):
    square1 = chance[0]
    square2 = chance[1]
    if square1.position[0] == square2.position[0]:
        for each in square1.getarow():
            if each.position[1] == 2 * square2.position[1] \
                    - square1.position[1]:
                each.num = []
                square1.num = [1]
                square2.num = [1]
    elif square1.position[1] == square2.position[1]:
        for each in square1.getaline():
            if each.position[0] == 2 * square2.position[0] \
                    - square1.position[0]:
                each.num = []
                square1.num = [1]
                square2.num = [1]

def toplace(choice):
    square1 = choice[0]
    square2 = choice[1]
    if square1.position[1] == square2.position[1]:
        for each in square1.getaline():
            if each.position[0] == 2 * square2.position[0] \
                    - square1.position[0]:
                return each
    if square1.position[0] == square2.position[0]:
        for each in square1.getarow():
            if each.position[1] == 2 * square2.position[1] \
                    - square1.position[1]:
                return each

# 生成整个棋局
wholepart = []
for row in range(7):
    for line in range(7):
        example = Square((row,line),[])
        wholepart.append(example)

replacelist = []
tolist = []
times = 0
enter = input('please enter:')
for i in enter:
    if i != '0':
        tolist.append(int(i))
        replacelist.append(times)
    times = times + 1

h = dict(zip(replacelist,tolist))
for known,t in h.items():
    wholepart[known].num.append(t)


def main():
    global go
    if not go:
        return
    alist = getchance()
    if alist == []:
        times = 0
        for each in wholepart:
            if each.num == [1]:
                times += 1
        if times != 1:
            return
        elif times == 1:
            print('success')
            for h in testlist2:
                print('[(%s,%s),(%s,%s)]'%(h[0][0]+1,h[0][1]+1\
                                           ,h[1][0]+1,h[1][1]+1),end='')
            print()
            go = False

            return
    for eachway in alist:
        move(eachway)
        testlist2.append([eachway[0].position,eachway[1].position])
        main()
        unmove(eachway)
        testlist2.remove([eachway[0].position, eachway[1].position])




testlist2 = []
go = True
main()

文本如下:

2200022
2201022
0011100
0001000
0001000
2200022
2200022

2200022220102200111000001000000100022000222200022

下面提供几个示例:

please enter:2201022221112201111100001000000100022111222211122
success
[(2,3),(3,3)][(2,5),(3,5)][(7,3),(6,3)][(5,3),(4,3)][(3,3),(3,4)][(1,4),(2,4)][(3,5),(3,4)][(3,2),(3,3)][(4,4),(3,4)][(6,5),(6,4)][(7,5),(7,4)][(7,3),(6,3)][(5,3),(5,4)][(5,5),(4,5)][(3,6),(3,5)][(2,4),(3,4)]

Process finished with exit code 0

please enter:2200022220102200111000111110111111122000222200022
success
[(3,4),(2,4)][(4,3),(3,3)][(4,5),(5,5)][(5,7),(5,6)][(6,5),(5,5)][(4,6),(4,5)][(5,4),(4,4)][(4,4),(3,4)][(1,4),(2,4)][(3,5),(3,4)][(2,3),(3,3)][(4,3),(5,3)][(5,1),(5,2)][(6,3),(5,3)][(4,2),(4,3)]

Process finished with exit code 0

 写在最后:代码有很多不足。对于不同的情况,算法所花的时间差别很大,从几秒到几分钟都可能。可能等我学的更多一些才能优化了。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值