2048游戏规则:简单的移动方向键让数字叠加,并且获得这些数字每次叠加后的得分,当出现2048这个数字时游戏胜利。同时每次移动方向键时,都会在这个4*4的方格矩阵的空白区域随机产生一个数字2或者4,如果方格被数字填满了,那么就GameOver了。
来一步步的进行剖析:
(1)生成4*4的棋盘, 其中数据结构为列表嵌套列表
field=[[0forjinrange(4)]foriinrange(4)]
(2)创建函数random_create, 在棋盘的一个随机位置插入一个数字2或者4,其中2的几率大
importrandom defrandom_create(): i=random.choice(range(4)) j=random.choice(range(4)) value=random.choice([2,2,2,4]) field[i][j]=value
(3)如果随机插入数字的位置已经有内容, 如何解决覆盖原有数字的问题
defrandom_creat(): whileTrue: i=random.choice(range(4)) j=random.choice(range(4)) ifli[i][j]==0: li[i][j]=4ifrandom.randint(1,100)>80else2 break random_creat() random_creat()
(4)将生成的数据, 通过图像画出来
defdraw_sep(): print('+-----'*4+'+') defdraw_num(row): print(''.join('|{:^5}'.format(num)ifnum!=0else'|'fornuminrow)+'|') forrowinli: draw_sep() draw_num(row) draw_sep()
(5)矩阵的反转
definvert(field): return[row[::-1]forrowinfield]
(6)矩阵的转秩
deftranspose(field): return[list(row)forrowinzip(*field)]
(7)判断棋盘是否可移动
defis_row_change(row): #row #判断一行内容是否可以移动 defis_change(i): #判断每两个元素之间是否可以移动 ifrow[i]==0androw[i+1]!=0: returnTrue ifrow[i]!=0androw[i+1]==row[i]: returnTrue else: returnFalse returnany([is_change(index)forindexinrange(len(row)-1)])
(8)判断这个棋盘是否可左右上下移动
defis_move_left(field): returnany([is_row_change(row)forrowinfield]) defis_move_right(field): #对于列表元素进行反转 field=invert(field) print(field) returnis_move_left(field) defis_move_up(field): #对于列表元素进行转置 field=transpose(field) returnis_move_left(field) defis_move_down(field): #反转+转置 field=transpose(field) returnis_move_right(field)
棋盘的移动,相加
deftight(row):#[2,0,2,0] #最快的方式,通过排序实现........... returnsorted(row,key=lambdax:ifx==0) score=0 #相加 defmerge(row):#[2,2,0,0] #[0,1,2] foriinrange(len(row)-1): #如果两个值相等,前一个元素*2,后一个元素改为0。 ifrow[i]==row[i+1]: row[i]*=2 row[i+1]=0 #如果覆盖成功,就给得分 globalscore score+=row[i] returnrow
棋盘左右上下移动相加
defmove_row_left(self,row): returnself.tight(self.merge(self.tight(row))) defmove_left(self,field): return[self.move_row_left(row)forrowinfield] defmove_right(self,field): field=self.invert(field) returnself.invert([self.move_row_left(row)forrowinfield]) defmove_up(self,field): returnself.transpose([self.move_row_left(row)forrowinself.transpose(field)]) defmove_down(self,field): returnself.invert(self.transpose([self.move_row_left(row) forrowinself.invert(self.transpose(field))]))
(9)判断游戏的胜利与结束
#判断游戏何时胜利:当棋盘中出现2048时,就代表着游戏胜利 defvictory(field): li=[yforrowinliforyinrow] ifmax(li)>=2048: print('Victory') defgame_over(filed): ifall((is_move_left(filed),is_move_right(filed),is_move_up(filed),is_move_down(filed)))==False: print('GameOver')
这样程序的各个部分就写好了,将各个部分封装到一个类里面,再导入curses模块来控制游戏,就可以了。
相关推荐:《Python教程》
下面是完整的代码:
importcurses fromitertoolsimportchain fromrandomimportchoice classGameField(object): #初始化信息 def__init__(self,width=4,height=4,win_value=8): self.width=width self.height=height self.win_value=win_value self.score=0#当前得分 self.highscore=0#最高分 self.moves={} self.moves['Left']=self.is_move_left self.moves['Right']=self.is_move_right self.moves['Down']=self.is_move_down self.moves['Up']=self.is_move_up self.movesDict={} self.movesDict['Left']=self.move_left self.movesDict['Right']=self.move_right self.movesDict['Down']=self.move_down self.movesDict['Up']=self.move_up defreset(self):#重置棋盘 ifself.score>self.highscore: self.highscore=self.score#更新最高分 self.score=0 #需求1:生成4*4的棋盘,其中数据结构选择列表嵌套列表; self.field=[[0forjinrange(self.width)] foriinrange(self.height)] #在棋盘的一个随机位置插入一个数字2或者4 self.random_create() self.random_create() defrandom_create(self): #在棋盘的一个随机位置插入一个数字2或者4 #field[0][3]=2 whileTrue: i,j=choice(range(self.height)),choice(range(self.width)) ifself.field[i][j]==0: self.field[i][j]=choice([2,2,2,4]) break defdraw(self,stdscr): defdraw_sep(): stdscr.addstr('+'+"-----+"*self.width+'\n') defdraw_one_row(row): stdscr.addstr("".join('|{:^5}'.format(num)ifnum!=0else"|"fornuminrow)+'|'+'\n') #清屏 stdscr.clear() stdscr.addstr("2048".center(50,'-')+'\n') stdscr.addstr("当前分数:"+str(self.score)+'\n') ifself.highscore!=0: stdscr.addstr("最高分:"+str(self.highscore)+'\n') forrowinself.field: draw_sep() draw_one_row(row) draw_sep() #判断是否赢或者输 ifself.is_win(): stdscr.addstr("胜利!!!!"+'\n') ifself.is_gameover(): stdscr.addstr("游戏结束!!!!"+'\n') stdscr.addstr("游戏帮助:上下左右键(R)RestartQ(Quit)") defis_win(self): returnmax(chain(*self.field))>=self.win_value defis_gameover(self): #任何方向都不能移动的时候,游戏结束 returnnotany([self.move_is_possible(direction) fordirectioninself.moves]) @staticmethod definvert(field): #矩阵进行反转 return[row[::-1]forrowinfield] #print(invert(li)) @staticmethod #矩阵的转置 deftranspose(field): return[list(row)forrowinzip(*field)] @staticmethod defis_row_change(row): #row #需求3.判断一行内容是否可移动。 defis_change(i):#0 #判断每两个元素之间是否可移动 ifrow[i]==0androw[i+1]!=0: returnTrue ifrow[i]!=0androw[i]==row[i+1]: returnTrue returnFalse returnany([is_change(index)forindexinrange(len(row)-1)]) #判断这个棋盘是否可向左移动 defis_move_left(self,field): returnany([self.is_row_change(row)forrowinfield]) defis_move_right(self,field): #对于列表元素进行反转 field=self.invert(field) print(field) returnself.is_move_left(field) defis_move_up(self,field): #对于列表元素进行转置 field=self.transpose(field) returnself.is_move_left(field) defis_move_down(self,field): #反转+转置 field=self.transpose(field) returnself.is_move_right(field) defmove_is_possible(self,direction):#'left' #判断用户选择的方向是否可移动 ifdirectioninself.moves: returnself.moves[direction](self.field) else: returnFalse #将棋盘每一行的非0数向前移动,0向后移动; @staticmethod deftight(row):#[2,0,2,0] #最快的方式,通过排序实现........... returnsorted(row,key=lambdax:1ifx==0else0) defmerge(self,row):#[2,2,0,0] #[0,1,2] foriinrange(len(row)-1): #如果两个值相等,前一个元素*2,后一个元素改为0。 ifrow[i]==row[i+1]: row[i]*=2 row[i+1]=0 #如果覆盖成功,就给得分 self.score+=row[i] returnrow#[4,0,0,0] defmove_row_left(self,row): returnself.tight(self.merge(self.tight(row))) defmove_left(self,field): return[self.move_row_left(row)forrowinfield] defmove_right(self,field): field=self.invert(field) returnself.invert([self.move_row_left(row)forrowinfield]) defmove_up(self,field): returnself.transpose([self.move_row_left(row)forrowinself.transpose(field)]) defmove_down(self,field): returnself.invert(self.transpose([self.move_row_left(row) forrowinself.invert(self.transpose(field))])) defmove(self,direction):#'left' #判断用户选择的方向是否可移动 ifdirectioninself.movesDict: #判断是否可移动 ifself.move_is_possible(direction): self.field=self.movesDict[direction](self.field) self.random_create() returnTrue else: returnFalse defget_user_action(stdscr): action=stdscr.getch() ifaction==curses.KEY_UP: return'Up' ifaction==curses.KEY_DOWN: return'Down' ifaction==curses.KEY_LEFT: return'Left' ifaction==curses.KEY_RIGHT: return'Right' ifaction==ord('r'): return'Restart' ifaction==ord('q'): return'Exit' defmain(stdscr): action=stdscr.getch() definit(): #初始化棋盘的操作 game_field.reset() game_field.draw(stdscr) return'Game' defgame(): game_field.draw(stdscr) action=get_user_action(stdscr) ifaction=='Restart': return'Init' ifaction=='Exit': return'Exit' ifgame_field.move(action): ifgame_field.is_win(): return'Win' ifgame_field.is_gameover(): return'GameOver' return'Game' defnot_game(): game_field.draw(stdscr) whileTrue: action=get_user_action(stdscr) ifaction=='Restart': return'Init' ifaction=='Exit': return'Exit' state_actions={ 'Init':init, 'Game':game, 'Win':not_game, 'GameOver':not_game, } game_field=GameField() state='Init' #如果当前状态不是退出,那么一直执行 whilestate!='Exit': #执行当前状态需要操作的内容,并返回,下一次的状态为什么. state=state_actions[state]() curses.wrapper(main)
实现双人版的2048游戏
importcurses importrandom fromitertoolsimportchain classGameField(object): def__init__(self,width=4,height=4,win_value=2048): self.width=width self.height=height self.win_value=win_value self.score1=0 self.score2=0 self.highscore=0 self.moves={} self.moves['Left1']=self.is_left_move self.moves['Right1']=self.is_right_move self.moves['Up1']=self.is_up_move self.moves['Down1']=self.is_down_move self.moves['Left2']=self.is_left_move self.moves['Right2']=self.is_right_move self.moves['Up2']=self.is_up_move self.moves['Down2']=self.is_down_move self.movesDict1={} self.movesDict2={} self.movesDict1['Left1']=self.left_move self.movesDict1['Right1']=self.right_move self.movesDict1['Up1']=self.up_move self.movesDict1['Down1']=self.down_move self.movesDict2['Left2']=self.left_move self.movesDict2['Right2']=self.right_move self.movesDict2['Up2']=self.up_move self.movesDict2['Down2']=self.down_move defrandom_create1(self): whileTrue: i,j=random.randint(0,self.height-1),random.randint(0,self.width-1) ifself.field1[i][j]==0: self.field1[i][j]=random.choice([2,2,2,4]) break defrandom_create2(self): whileTrue: i,j=random.randint(0,self.height-1),random.randint(0,self.width-1) ifself.field2[i][j]==0: self.field2[i][j]=random.choice([2,2,2,4]) break defreset(self): self.field1=[[0forjinrange(self.width)]foriinrange(self.height)] self.score1=0 self.field2=[[0forjinrange(self.width)]foriinrange(self.height)] self.score2=0 self.random_create1() self.random_create1() self.random_create2() self.random_create2() defdraw(self,stdscr): stdscr.clear() self.score1=sum(chain(*self.field1)) self.score2=sum(chain(*self.field2)) ifmax(self.score1,self.score2)>self.highscore: self.highscore=max(self.score1,self.score2) stdscr.addstr('最高分:'+str(self.highscore)+'') stdscr.addstr('玩家1分数:'+str(self.score1)+'') stdscr.addstr('玩家2分数:'+str(self.score2)+'\n') forrowinself.field1: stdscr.addstr('+'+'-----+'*self.width+'\n') stdscr.addstr("".join('|{:^5}'.format(num)ifnum!=0else"|"fornuminrow)+'|'+'\n') stdscr.addstr('+'+'-----+'*self.width+'\n') ifself.is_win1(): stdscr.addstr('胜利\n') ifself.is_gameover1(): stdscr.addstr('游戏结束\n') forrowinself.field2: stdscr.addstr('+'+'-----+'*self.width+'\n') stdscr.addstr("".join('|{:^5}'.format(num)ifnum!=0else"|"fornuminrow)+'|'+'\n') stdscr.addstr('+'+'-----+'*self.width+'\n') ifself.is_win2(): stdscr.addstr('胜利\n') ifself.is_gameover2(): stdscr.addstr('游戏结束\n') stdscr.addstr("玩家1:上下左右键玩家2:wasd键(R)重置(Q)退出") defis_win1(self): returnmax(chain(*self.field1))>=self.win_value defis_win2(self): returnmax(chain(*self.field2))>=self.win_value defis_gameover1(self): returnnotany([self.is_move_possible1(direction)fordirectioninself.moves]) defis_gameover2(self): returnnotany([self.is_move_possible2(direction)fordirectioninself.moves]) @staticmethod definvert(field): return[row[::-1]forrowinfield] @staticmethod deftranspose(field): return[list(row)forrowinzip(*field)] @staticmethod defis_row_change(row): foriinrange(len(row)-1): ifrow[i]==0androw[i+1]!=0: returnTrue elifrow[i]!=0androw[i]==row[i+1]: returnTrue else: returnFalse defis_left_move(self,field): returnany([self.is_row_change(i)foriinfield]) defis_right_move(self,field): returnany([self.is_row_change(i)foriinself.invert(field)]) defis_up_move(self,field): returnany([self.is_row_change(i)foriinself.transpose(field)]) defis_down_move(self,field): returnany([self.is_row_change(i)foriinself.invert(self.transpose(field))]) defis_move_possible1(self,direction): ifdirectioninself.moves: returnself.moves[direction](self.field1) else: returnFalse defis_move_possible2(self,direction): ifdirectioninself.moves: returnself.moves[direction](self.field2) else: returnFalse @staticmethod defrow_move(row): row=sorted(row,key=lambdax:1ifx==0else0) foriinrange(len(row)-1): ifrow[i]==row[i+1]: row[i]*=2 row[i+1]=0 returnsorted(row,key=lambdax:1ifx==0else0) defleft_move(self,field): return[self.row_move(i)foriinfield] defright_move(self,field): returnself.invert([self.row_move(i)foriinself.invert(field)]) defup_move(self,field): returnself.transpose([self.row_move(i)foriinself.transpose(field)]) defdown_move(self,field): returnself.transpose(self.invert([self.row_move(i)foriinself.invert(self.transpose(field))])) defmove1(self,direction): ifdirectioninself.movesDict1andself.is_move_possible1(direction): self.field1=self.movesDict1[direction](self.field1) self.random_create1() returnTrue else: returnFalse defmove2(self,direction): ifdirectioninself.movesDict2andself.is_move_possible2(direction): self.field2=self.movesDict2[direction](self.field2) self.random_create2() returnTrue else: returnFalse defget_user_action(stdscr): action=stdscr.getch() ifaction==curses.KEY_UP: return'Up1' elifaction==curses.KEY_DOWN: return'Down1' elifaction==curses.KEY_LEFT: return'Left1' elifaction==curses.KEY_RIGHT: return'Right1' elifaction==ord('r'): return'Restart' elifaction==ord('q'): return'Exit' elifaction==ord('w'): return'Up2' elifaction==ord('s'): return'Down2' elifaction==ord('a'): return'Left2' elifaction==ord('d'): return'Right2' defmain(stdscr): definit(): game_field.reset() game_field.draw(stdscr) return'Game' defgame(): game_field.draw(stdscr) action=get_user_action(stdscr) ifaction=='Restart': return'Init' ifaction=='Exit': return'Exit' ifactionin('Up1','Down1','Left1','Right1'): ifgame_field.move1(action): ifgame_field.is_win1(): return'Win' ifgame_field.is_gameover1(): return'GameOver' ifactionin('Up2','Down2','Left2','Right2'): ifgame_field.move2(action): ifgame_field.is_win2(): return'Win' ifgame_field.is_gameover2(): return'GameOver' return'Game' defnot_game(): game_field.draw(stdscr) whileTrue: action=get_user_action(stdscr) ifaction=='Restart': return'Init' ifaction=='Exit': return'Exit' game_field=GameField() state='Init' state_actions={ 'Init':init, 'Game':game, 'Win':not_game, 'GameOver':not_game } whilestate!='Exit': state=state_actions[state]() curses.wrapper(main)
下一篇