2048左移JAVA代码实现,200 行代码实现 2048 游戏

原标题:200 行代码实现 2048 游戏

d351d36872ce694c27a723d3c1f775cf.png

作者:Guolanzhe

原文: http://www.guolanzhe.com/?p=522创建游戏文件 2048.py

首先导入需要的包:

importcurses

fromrandomimportrandrange,choice

fromcollectionsimportdefaultdict主逻辑 用户行为

所有的有效输入都可以转换为"上,下,左,右,游戏重置,退出"这六种行为,用 actions表示

actions=['Up','Left','Down','Right','Restart','Exit']

有效输入键是最常见的 W(上),A(左),S(下),D(右),R(重置),Q(退出),这里要考虑到大写键开启的情况,获得有效键值列表:

letter_codes=[ord(ch)forchin'WASDRQwasdrq']

将输入与行为进行关联:

actionsdict = dict(zip(lettercodes, actions * 2))

状态机

处理游戏主逻辑的时候我们会用到一种十分常用的技术:状态机,或者更准确的说是有限状态机(FSM)

你会发现 2048 游戏很容易就能分解成几种状态的转换。

2a6fad6a080b36a10a1bd53d343c0263.png

state存储当前状态, state_actions这个词典变量作为状态转换的规则,它的 key 是状态,value 是返回下一个状态的函数:

Init: init()

Game: game()

Win: lambda: not_game('Win')

Gameover: lambda: not_game('Gameover')

Exit: 退出循环

状态机会不断循环,直到达到 Exit 终结状态结束程序。

下面是经过提取的主逻辑的代码,会在后面进行补全:

defmain(stdscr):

definit():

#重置游戏棋盘

return'Game'

defnot_game(state):

#画出 GameOver 或者 Win 的界面

#读取用户输入得到action,判断是重启游戏还是结束游戏

responses=defaultdict(lambda:state)#默认是当前状态,没有行为就会一直在当前界面循环

responses['Restart'],responses['Exit']='Init','Exit'#对应不同的行为转换到不同的状态

returnresponses[action]

defgame():

#画出当前棋盘状态

#读取用户输入得到action

ifaction=='Restart':

return'Init'

ifaction=='Exit':

return'Exit'

#if 成功移动了一步:

if游戏胜利了:

return'Win'

if游戏失败了:

return'Gameover'

return'Game'

state_actions={

'Init':init,

'Win':lambda:not_game('Win'),

'Gameover':lambda:not_game('Gameover'),

'Game':game

}

state='Init'

#状态机开始循环

whilestate!='Exit':

state=state_actions[state]()用户输入处理

阻塞+循环,直到获得用户有效输入才返回对应行为:

defget_user_action(keyboard):

char="N"

whilecharnotinactions_dict:

char=keyboard.getch()

returnactions_dict[char]矩阵转置与矩阵逆转

加入这两个操作可以大大节省我们的代码量,减少重复劳动,看到后面就知道了。

矩阵转置:

deftranspose(field):

return[list(row)forrowinzip(*field)]

矩阵逆转(不是逆矩阵):

definvert(field):

return[row[::-1]forrowinfield]创建棋盘

初始化棋盘的参数,可以指定棋盘的高和宽以及游戏胜利条件,默认是最经典的 4×4~2048。

classGameField(object):

def__init__(self,height=4,width=4,win=2048):

self.height=height#高

self.width=width#宽

self.win_value=2048#过关分数

self.score=0#当前分数

self.highscore=0#最高分

self.reset()#棋盘重置棋盘操作 随机生成一个 2 或者 4

defspawn(self):

new_element=4ifrandrange(100)>89else2

(i,j)=choice([(i,j)foriinrange(self.width)forjinrange(self.height)ifself.field[i][j]==0])

self.field[i][j]=new_element

#### 重置棋盘

defreset(self):

ifself.score>self.highscore:

self.highscore=self.score

self.score=0

self.field=[[0foriinrange(self.width)]forjinrange(self.height)]

self.spawn()

self.spawn()

#### 一行向左合并

(注:这一操作是在move内定义的,拆出来是为了方便阅读)

defmove_row_left(row):

deftighten(row):# 把零散的非零单元挤到一块

new_row=[iforiinrowifi!=0]

new_row+=[0foriinrange(len(row)-len(new_row))]

returnnew_row

defmerge(row):# 对邻近元素进行合并

pair=False

new_row=[]

foriinrange(len(row)):

ifpair:

new_row.append(2*row[i])

self.score+=2*row[i]

pair=False

else:

ifi+1

pair=True

new_row.append(0)

else:

new_row.append(row[i])

assertlen(new_row)==len(row)

returnnew_row

#先挤到一块再合并再挤到一块

returntighten(merge(tighten(row)))棋盘走一步

通过对矩阵进行转置与逆转,可以直接从左移得到其余三个方向的移动操作

defmove(self,direction):

defmove_row_left(row):

#一行向左合并

moves={}

moves['Left']=lambdafield:[move_row_left(row)forrowinfield]

moves['Right']=lambdafield:invert(moves['Left'](invert(field)))

moves['Up']=lambdafield:transpose(moves['Left'](transpose(field)))

moves['Down']=lambdafield:transpose(moves['Right'](transpose(field)))

ifdirectioninmoves:

ifself.move_is_possible(direction):

self.field=moves[direction](self.field)

self.spawn()

returnTrue

else:

returnFalse判断输赢

defis_win(self):

returnany(any(i>=self.win_valueforiinrow)forrowinself.field)

defis_gameover(self):

returnnotany(self.move_is_possible(move)formoveinactions)

#### 判断能否移动

defmove_is_possible(self,direction):

defrow_is_left_movable(row):

defchange(i):

ifrow[i]==0androw[i+1]!=0:# 可以移动

returnTrue

ifrow[i]!=0androw[i+1]==row[i]:# 可以合并

returnTrue

returnFalse

returnany(change(i)foriinrange(len(row)-1))

check={}

check['Left']=lambdafield:any(row_is_left_movable(row)forrowinfield)

check['Right']=lambdafield:check['Left'](invert(field))

check['Up']=lambdafield:check['Left'](transpose(field))

check['Down']=lambdafield:check['Right'](transpose(field))

ifdirectionincheck:

returncheck[direction](self.field)

else:

returnFalse绘制游戏界面

defdraw(self,screen):

help_string1='(W)Up (S)Down (A)Left (D)Right'

help_string2=' (R)Restart (Q)Exit'

gameover_string=' GAME OVER'

win_string=' YOU WIN!'

defcast(string):

screen.addstr(string+'n')

#绘制水平分割线

defdraw_hor_separator():

line='+'+('+------'*self.width+'+')[1:]

separator=defaultdict(lambda:line)

ifnothasattr(draw_hor_separator,"counter"):

draw_hor_separator.counter=0

cast(separator[draw_hor_separator.counter])

draw_hor_separator.counter+=1

defdraw_row(row):

cast(''.join('|{: ^5} '.format(num)ifnum>0else'| 'fornuminrow)+'|')

screen.clear()

cast('SCORE: '+str(self.score))

if0!=self.highscore:

cast('HGHSCORE: '+str(self.highscore))

forrowinself.field:

draw_hor_separator()

draw_row(row)

draw_hor_separator()

ifself.is_win():

cast(win_string)

else:

ifself.is_gameover():

cast(gameover_string)

else:

cast(help_string1)

cast(help_string2)完成主逻辑

完成以上工作后,我们就可以补完主逻辑了!

defmain(stdscr):

definit():

#重置游戏棋盘

game_field.reset()

return'Game'

defnot_game(state):

#画出 GameOver 或者 Win 的界面

game_field.draw(stdscr)

#读取用户输入得到action,判断是重启游戏还是结束游戏

action=get_user_action(stdscr)

responses=defaultdict(lambda:state)#默认是当前状态,没有行为就会一直在当前界面循环

responses['Restart'],responses['Exit']='Init','Exit'#对应不同的行为转换到不同的状态

returnresponses[action]

defgame():

#画出当前棋盘状态

game_field.draw(stdscr)

#读取用户输入得到action

action=get_user_action(stdscr)

ifaction=='Restart':

return'Init'

ifaction=='Exit':

return'Exit'

ifgame_field.move(action):# move successful

ifgame_field.is_win():

return'Win'

ifgame_field.is_gameover():

return'Gameover'

return'Game'

state_actions={

'Init':init,

'Win':lambda:not_game('Win'),

'Gameover':lambda:not_game('Gameover'),

'Game':game

}

curses.use_default_colors()

game_field=GameField(win=32)

state='Init'

#状态机开始循环

whilestate!='Exit':

state=state_actions[state]()运行

填上最后一行代码:

curses.wrapper(main)

082f513fb9a1db9446300ac66af912fc.png

完整版代码地址:https://github.com/JLUNeverMore/easy_2048-in-200-lines返回搜狐,查看更多

责任编辑:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值