前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python编写的数字拼图游戏(含爬山算法人机对战功能)

Python编写的数字拼图游戏(含爬山算法人机对战功能)

作者头像
Python小屋屋主
发布2018-04-16 16:23:45
1.4K0
发布2018-04-16 16:23:45
举报
文章被收录于专栏:Python小屋Python小屋

数字拼图游戏与拼图游戏原理一致,把打乱了的数字或图片经移动,拼成给定的目标数字或图片,其中总有一个空的地方,让相邻(上下左右)的方块移动,直至达到目标。

游戏代码由浙江温州永嘉县教师发展中心应根球老师提供,我略做修改和优化。

代码有点长,用手机阅读可能不太方便,可以复制地址到电脑上用浏览器查看。

import random

#显示数字拼图

def disp(s, d):

#s和d是两个数字字符串,把0换成空格,把数字摆放到指定位置

s = ''.join(s).replace('0', ' ')

d = ''.join(d).replace('0', ' ')

print('''

+---+---+---+ +---+---+---+

| {0[0]} | {0[1]} | {0[2]} | | {1[0]} | {1[1]} | {1[2]} |

|---+---+---| |---+---+---|

| {0[3]} | {0[4]} | {0[5]} | ==> | {1[3]} | {1[4]} | {1[5]} |

|---+---+---| |---+---+---|

| {0[6]} | {0[7]} | {0[8]} | | {1[6]} | {1[7]} | {1[8]} |

|---+---+---| |---+---+---|

'''.format(s, d))

#移动数字

def move(s, numstr):

if (numstr not in "12345678") or (not numstr):

return

t1 = s.index('0')

t2 = s.index(numstr)

#字符在字符串中的位置除3的商对应游戏图中的行下标

#除3的余数对应游戏图中的列下标

t = zip(divmod(t1,3), divmod(t2,3))

t = ''.join([str(abs(i-j)) for i,j in t])

#如果输入的数字与空格相邻则移动

if t in ('01','10'):

s[t1], s[t2] = s[t2], s[t1]

#获取空格周边可移动数字

def getMoveable(s):

#空格位置的行、列坐标

p, q = divmod(s.index('0'), 3)

#空格上下的位置坐标

ls = [(p, i) for i in (q+1, q-1) if i in range(3)]

#空给左右的位置坐标

ls += [(i, q) for i in (p+1, p-1) if i in range(3)]

return ls

#爬山算法状态计算函数,从当前状态s到终态d所需要的总步数

def getInstance(s,d):

#依次计算s和d中相同数字的距离,并求所有距离之和

sumi = 0

for n in '12345678':

t1 = divmod(s.index(n), 3)

t2 = divmod(d.index(n), 3)

sumi += abs(t1[0]-t2[0]) + abs(t1[1]-t2[1])

return sumi

#让机器根据与目标各数字差距之和的策略选定一个移动数字

def choiceNum(s, moveable, d):

tmp = [100,'0']

for i in moveable:

s1 = s[::]

s1[s1.index('0')], s1[s1.index(i)] = i, '0'

getI = getInstance(s1, d)

if getI < tmp[0]:

tmp = getI, i

elif getI == tmp[0]:

tmp = getI, random.choice([i, tmp[1]])

return tmp[1]

#打乱数字拼图顺序,以得到初始状态

def shufflemove(d, times):

s2 = d[::]

mov = '0'

for i in range(times):

mov1 = mov

mov = [s2[x[0]*3+x[1]] for x in getMoveable(s2)]

if mov1 in mov:

mov.remove(mov1)

mov = random.choice(mov)

move(s2, mov)

return s2

#做题,当who为computer时为计算机解题

#当who为human,即非computer时,人工解题

def do(s, d, who):

s1 = s[::]

num = ''

bushu = 0

while True:

if who != 'computer':

disp(s1,d)

#已成功、步数太大或人工放弃时返回

if s1==d or bushu>=1000 or num=='0':

return bushu

#确定可输入的数字

n_of_m = [s1[x[0]*3+x[1]] for x in getMoveable(s1)]

if who == 'computer':

#机器答题不允许后退

if num in n_of_m:

n_of_m.remove(num)

num = choiceNum(s, n_of_m, d)

else:

#人工答题允许后退

prompt = '第{0}步{1}(输入0退出)=>'.format(bushu, n_of_m)

num = input(prompt)[0]

#输入0步数设为999,视为主动放弃并退出

if num == '0':

bushu = 999

#移动数字

move(s1,num)

bushu += 1

#主程序开始

print('-'*34)

print('拼图游戏'.center(34,'*'))

print('''

**玩法:左边的图通过移动空格相邻的数字到

空格处,最终得到右边的图,游戏即完成。只

要输入空格相邻的数字,该数字即被移到空格

处。=>左边的数字为你已经移动的步数及你可

移动的数字。完成任务的步数越少,你的游戏

成绩越高。祝你幸运!

''')

print('-'*34)

#为简化,设定固定数字目标,其中0显示为空方块

d = list('123804765')

#为简化,让机器从目标开始随机逆移动,先只移动6步

#也可以设置难度,移动步数越多,恢复越难。

s = shufflemove(d,6)

#先让计算机用简易爬山算法去解题,由于爬山算法本身的原因,不一定能得到最优解

cpstep = do(s, d, 'computer')

#显示开始与结束状态及机器解题情况

disp(s, d)

print('这个题目机器用了{0}步!\n'.format(cpstep))

if cpstep > 1000:

print("机器用了1000步还没解出,看你的了!\n")

#用于计人工移动的步数

bushu = 0

#人工解题开始

hmstep = do(s, d, 'human')

#显示游戏结果

if hmstep < cpstep:

print("你胜利,真了不起!")

elif hmstep == cpstep:

print("你与机器持平局,加油!")

else:

print("哈,你输给了机器,这可是用爬山算法哦!")

某次玩游戏的过程如下

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-01-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python小屋 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档