import curses #控制字符界面
from random import randrange, choice
#random.randrange([start], stop[, step]),
# 從指定范圍內(nèi)拳喻,按指定基數(shù)遞增的集合中 獲取一個隨機數(shù)即碗。
#random.choice從序列中獲取一個隨機元素耀怜。
from collections import defaultdict#默認字典
letter_codes = [ord(ch) for ch in 'WASDRQwasdrq']#ord函數(shù)以一個字符為參數(shù)贡茅,返回對應(yīng)的ASCII數(shù)值锐秦,或者Unicode數(shù)值
actions = ['Up', 'Left', 'Down', 'Right', 'Restart', 'Exit']
actions_dict = dict(zip(letter_codes,actions*2)) #zip() 函數(shù)用于將可迭代的對象作為參數(shù),將對象中對應(yīng)的元素打包成一個個元組辅鲸,然后返回由這些元組組成的對象,這樣做的好處是節(jié)約了不少的內(nèi)存腹殿。
#[(W,Up),(A,Left),..(q,Exit)]-->{W:Up, A:Left,...q:Exit}
#用戶輸入
def get_user_action(keyboard):
char = 'N'
while char not in actions_dict:
char = keyboard.getch()
return actions_dict[char]
#矩陣轉(zhuǎn)置
def transpose(field):#進行一個二維列表的轉(zhuǎn)換
return [list(row) for row in zip(*field)]
#矩陣逆轉(zhuǎn)
def invert(field):
return [row[::-1] for row in field]
#創(chuàng)建棋盤
class GameField(object):#class:類的關(guān)鍵字独悴;GameField:自定義類的標識符;object锣尉;要繼承的類名(是一個更大的類刻炒,可以從這個父類中繼承一些功能和特性),object是默認值自沧。
def __init__(self, height=4, width=4, win=2048):#__init__是超類object下的一個初始化對象數(shù)據(jù)的函數(shù)
self.height = height #高
self.width = width #寬
self.win_value = win #過關(guān)分數(shù)
self.score = 0 #當前分數(shù)
self.highscore = 0 #最高分數(shù)
self.reset() #棋盤重置
#重置棋盤
def reset(self):
if self.score > self.highscore:
self.highscore = self.score
self.score = 0
self.field = [[0 for i in range(self.width)] for j in range(self.height)]#嵌套的列表坟奥,四行四列
self.spawn()
self.spawn()#在嵌套的列表里隨機的生成元素
def move(self,direction):#合并
#一行向左合并
def move_row_left(row):
def tighten(row): #把零散的非零單元擠到一起
new_row = [i for i in row if i !=0]
new_row += [0 for i in range(len(row)-len(new_row))]
return new_row
def merge(row): #對鄰近元素進行合并
pair = False
new_row = []
for i in range(len(row)):
if pair:
new_row.append(2 * row[i])#合并
self.score += 2 * row[i]#記錄分數(shù)
pair = False
else:
if i +1 < len(row) and row[i] == row[i + 1]:
pair = True
new_row.append(0)
else:
new_row.append(row[i])
assert len(new_row) == len(row)
return new_row
#先擠到一塊再合并再擠到一起
return tighten(merge(tighten(row)))
#通過對矩陣進行轉(zhuǎn)置和逆轉(zhuǎn),可以直接從左移得到其余三個方向的移動操作
moves = {}
moves['Left'] = lambda field: \
[move_row_left(row) for row in field]
moves['Right'] = lambda field: \
invert(moves['Left'](invert(field)))
moves['Up'] = lambda field: \
transpose(moves['Left'](transpose(field)))
moves['Down'] = lambda field: \
transpose(moves['Right'](transpose(field)))
if direction in moves:
if self.move_is_possible(direction):
self.field = moves[direction](self.field)
self.spawn()
return True
else:
return False
#判斷輸贏
def is_win(self):
return any(any(i >= self.win_value for i in row) for row in self.field)
def is_gameover(self):
return not any(self.move_is_possible(move) for move in actions)
#繪制游戲界面
def draw(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!'
def cast(string):
screen.addstr(string + '\n')#調(diào)用方法把字符串打印到屏幕
#繪制水平分割線
def draw_hor_separator():
line = '+' + ('+------' * self.width + '+')[1:]
separator = defaultdict(lambda: line)
if not hasattr(draw_hor_separator, 'counter'):
draw_hor_separator.counter = 0
cast(separator[draw_hor_separator.counter])
draw_hor_separator.counter += 1
def draw_row(row):
cast(''.join('|{: ^5} '.format(num) if num > 0 else '| ' for num in row)+ '|')
screen.clear()
cast('SCORE: ' + str(self.score))#繪制當前分數(shù)和最高分
if 0 != self.highscore:
cast('HIGHSCORE:' + str(self.highscore))
for row in self.field:
draw_hor_separator()#繪制分割線
draw_row(row)#繪制行
draw_hor_separator()#繪制底邊的線
if self.is_win():
cast(win_string)
else:
if self.is_gameover():
cast(gameover_string)
else:
cast(help_string1)
cast(help_string2)
#棋盤操作
#隨機生成一個2或者4
def spawn(self):
new_element = 4 if randrange(100) > 89 else 2#9:1的比例生成4和2
(i,j) = choice([(i,j) for i in range(self.width) for j in range(self.height) if self.field[i][j] ==0])#通過choice選擇一個未被占領(lǐng)的位置
self.field[i][j] = new_element
#判斷能否移動
def move_is_possible(self,diretion):
def row_is_left_movable(row):#判斷是否可以向左移動
def change(i):
if row[i] == 0 and row[i + 1] !=0:
return True
if row[i] !=0 and row[i + 1] == row[i]:
return True
return False
return any(change(i) for i in range(len(row) - 1))#any,只要有一個是ture結(jié)果就是ture
check = {}
check['Left'] = lambda field: \
any(row_is_left_movable(row) for row in field)
check['Right'] = lambda field: \
check['Left'](invert(field))
check['Up'] =lambda field: \
check['Left'](transpose(field))
check['Down'] =lambda field: \
check['Right'](transpose(field))
if diretion in check:
return check[diretion](self.field)
else:
return False
#主邏輯
def main(stdscr):#標準屏幕,curses模塊
def init():
#重置游戲棋盤
game_field.reset()
return 'Game'
def not_game(state):
#畫出 GameOver 或者 Win 的界面
game_field.draw(stdscr)
#讀取用戶輸入得到的action爱谁,判斷是重啟游戲還是結(jié)束游戲
action = get_user_action(stdscr)
responses = defaultdict(lambda : state)#默認是當前狀態(tài)晒喷,沒有行為就會一直在當前界面循環(huán)
#collections.defaultdict可以接受一個函數(shù)作為參數(shù)來初始化
responses['Restart'],responses['Exit']='Init','Exit'#對應(yīng)不同的行為轉(zhuǎn)換到不同的狀態(tài)
return responses[action]
def game():
#畫出當前棋盤的狀態(tài)
game_field.draw(stdscr)
#讀取用戶輸入得到的action
action = get_user_action(stdscr)
if action == 'Restart':
return 'Init'
if action == 'Exit':
return 'Exit'
if game_field.move(action):
if game_field.is_win():
return 'Win'
if game_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=2048)
state = 'Init'
#狀態(tài)機開始循環(huán)
while state != 'Exit':
state = state_actions[state]()
curses.wrapper(main)#把stdscr對象傳入main函數(shù)里,wrapper接口
200行python實現(xiàn)2048
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
- 文/潘曉璐 我一進店門叮姑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來唉地,“玉大人,你說我怎么就攤上這事传透≡耪樱” “怎么了?”我有些...
- 文/不壞的土叔 我叫張陵朱盐,是天一觀的道長群嗤。 經(jīng)常有香客問我,道長兵琳,這世上最難降的妖魔是什么狂秘? 我笑而不...
- 正文 為了忘掉前任,我火速辦了婚禮躯肌,結(jié)果婚禮上者春,老公的妹妹穿的比我還像新娘。我一直安慰自己清女,他們只是感情好钱烟,可當我...
- 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著嫡丙,像睡著了一般拴袭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上曙博,一...
- 文/蒼蘭香墨 我猛地睜開眼浇坐,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了黔宛?” 一聲冷哼從身側(cè)響起近刘,我...
- 正文 年R本政府宣布代咸,位于F島的核電站蹈丸,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏呐芥。R本人自食惡果不足惜逻杖,卻給世界環(huán)境...
- 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望思瘟。 院中可真熱鬧弧腥,春花似錦、人聲如沸潮太。這莊子的主人今日做“春日...
- 文/蒼蘭香墨 我抬頭看了看天上的太陽铡买。三九已至,卻和暖如春霎箍,著一層夾襖步出監(jiān)牢的瞬間奇钞,已是汗流浹背。 一陣腳步聲響...
推薦閱讀更多精彩內(nèi)容
- 經(jīng)惩昊郏看到很多設(shè)計中用很多小圖片拼接成一張大圖谋旦,覺得很酷炫,給人的感覺也比較高大上屈尼,其實用代碼實現(xiàn)也比較簡單册着。 簡單...
- 開篇語 今天是筆者奶奶生日脾歧,昨天為此準備了不少事情甲捏,也因此花費了很多時間,今天上午接待客人鞭执,下午送我年邁的姑奶奶回...
- https://github.com/yangshun/2048-python 主程序puzzle.py [imp...
- (連載)《美夢如璇·第九章·第一百一十三節(jié)》 Hi司顿,我特別喜歡夏天 夏天有晴明的天空 有溫潤的空氣 有蔥翠的嫩葉 ...