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

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

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

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

我上手的是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、付费专栏及课程。

余额充值