Ich glaube, dass das Spiel 2048 jedem bekannt sein muss. Der Artikel stellt hauptsächlich die Verwendung von Python zur Implementierung des 2048-Minispiels vor. Ich glaube, dass es jedem helfen wird Verstehen und Lernen hat einen gewissen Referenzwert. Freunde in Not sollten einen Blick darauf werfen.
Vorwort
2048 Spielregeln: Bewegen Sie einfach die Richtungstasten, um die Zahlen zu überlagern, und erhalten Sie die Punktzahl nach jeder Überlagerung dieser Zahlen . Das Spiel ist gewonnen, wenn die Zahl 2048 erscheint. Gleichzeitig wird bei jeder Bewegung der Richtungstasten zufällig eine Zahl 2 oder 4 im leeren Bereich der 4*4-Quadratmatrix generiert. Wenn das Quadrat mit Zahlen gefüllt ist, dann ist es GameOver.
Hauptlogikdiagramm
Logikdiagramm: Schwarz ist Logikschicht, Blau ist eine externe Methode, Rot ist eine klasseninterne Methode, das werden Sie später erfahren~
Lassen Sie mich die Hauptlogik Zeile für Zeile erklären . main()
Funktion und überschneiden sich darin extern definierte Funktionen und Klassen.
Interpretation des Hauptlogikcodes (den vollständigen Code finden Sie am Ende des Artikels)
Die Hauptlogik main ist wie folgt, gefolgt von der Hauptfunktion. Interpretation einiger Methoden:
def main(stdscr): def init(): #重置游戏棋盘 game_field.reset() return 'Game' def not_game(state): #画出 GameOver 或者 Win 的界面 game_field.draw(stdscr) #读取用户输入得到action,判断是重启游戏还是结束游戏 action = get_user_action(stdscr) responses = defaultdict(lambda: state) #默认是当前状态,没有行为就会一直在当前界面循环 responses['Restart'], responses['Exit'] = 'Init', 'Exit' #对应不同的行为转换到不同的状态 return responses[action] def game(): #画出当前棋盘状态 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): # move successful 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=32) state = 'Init' #状态机开始循环 while state != 'Exit': state = state_actions[state]()
Interpretation nacheinander (das Codefeld wird als kommend markiert). von außen, wenn keine Markierung vorhanden ist, kommt es von innen): Definition Hauptfunktion
def main(stdscr):
def init(): #重置游戏棋盘 game_field.reset()
reset kommt von einer extern definierten Klasse, einer von game_field=GameField
Methode reset:
Extern:
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() #其中highscore为程序初始化过程中定义的一个变量。记录你win游戏的最高分数记录。
return 'Game'
Gibt den Status eines laufenden Spiels zurück. game_field=GameField
Der Status wird später definiert:
Die untere Definition der Hauptfunktion:
state_actions = { 'Init': init, 'Win': lambda: not_game('Win'), 'Gameover': lambda: not_game('Gameover'), 'Game': game }
def not_game(state): #画出 GameOver 或者 Win 的界面 game_field.draw(stdscr)
draw ist eine Methode in der importierten Klasse game_field=GameField
:
#来自外部类 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') 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)) if 0 != self.highscore: cast('HGHSCORE: ' + 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) #这里面的draw方法的字函数我就不做多的解释了,很简单的一些概念。 #但是又运用到了很优秀的精简代码。 #有的地方建议去查一下python的一些高级概念,我就不做多的介绍了。
Die Wortfunktion von Hier werde ich nicht zu viel über die Zeichenmethode erklären, es sind nur ein paar einfache Konzepte.
Aber es verwendet hervorragenden, optimierten Code.
Manchmal wird empfohlen, sich einige fortgeschrittene Konzepte von Python anzuschauen, aber ich werde nicht zu sehr auf die Einführung eingehen.
#读取用户输入得到action,判断是重启游戏还是结束游戏 action = get_user_action(stdscr)
Benutzerverhalten lesen, die Funktion stammt aus der anfänglichen Definition des Codes
#来自外部定义的函数 def get_user_action(keyboard): char = "N" while char not in actions_dict: char = keyboard.getch() return actions_dict[char]
Am Ende, also im dritten Schritt der Hauptfunktionsausführung, wird die Instanz von state = state_actions[state]()
definiert:
#主函数底部: state = 'Init' #状态机开始循环 while state != 'Exit': state = state_actions[state]()
responses = defaultdict(lambda: state) #默认是当前状态,没有行为就会一直在当前界面循环 responses['Restart'], responses['Exit'] = 'Init', 'Exit' #对应不同的行为转换到不同的状态 return responses[action]
def game(): #画出当前棋盘状态 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): # move successful if game_field.is_win(): return 'Win' if game_field.is_gameover(): return 'Gameover' return 'Game' #game()函数的定义类似于上面已经讲过的not_game(),只是game()有了内部循环 #即如果不是Restart/Exit或者对move之后的状态进行判断,如果不是结束游戏,就一直在game()内部循环。
game()
Die Definition der Funktion ähnelt der bereits oben genannten not_game()
, außer dass game()
Mit der internen Schleife, das heißt, wenn es sich nicht um Neustart/Beenden oder um die Beurteilung des Zustands nach dem Zug handelt, wenn es nicht das Ende des Spiels ist, wird es immer in der game()
internen Schleife sein.
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' #状态机开始循环 while state != 'Exit': state = state_actions[state]() #此处的意思是:state=state_actions[state] 可以看做是: #state=init()或者state=not_game(‘Win')或者是另外的not_game(‘Gameover')/game()
Die Bedeutung hier ist: state=state_actions[state]
kann gesehen werden als: state=init()
oder state=not_game(‘Win')
oder ein anderes not_game(‘Gameover')/game()
Hier ist ohne weiteres mein letztes Erfolgsbild. Außerdem können Sie Ihre endgültigen Gewinnbedingungen festlegen, indem Sie in den letzten Zeilen win=32 festlegen!
Vollständiger Code
#-*- coding:utf-8 -*- import curses from random import randrange, choice # generate and place new tile from collections import defaultdict letter_codes = [ord(ch) for ch in 'WASDRQwasdrq'] actions = ['Up', 'Left', 'Down', 'Right', 'Restart', 'Exit'] actions_dict = dict(zip(letter_codes, actions * 2)) def transpose(field): return [list(row) for row in zip(*field)] def invert(field): return [row[::-1] for row in field] class GameField(object): def __init__(self, height=4, width=4, win=2048): self.height = height self.width = width self.win_value = win self.score = 0 self.highscore = 0 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): # squeese non-zero elements together 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] 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))) 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') 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)) if 0 != self.highscore: cast('HGHSCORE: ' + 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) def spawn(self): new_element = 4 if randrange(100) > 89 else 2 (i,j) = choice([(i,j) for i in range(self.width) for j in range(self.height) if self.field[i][j] == 0]) self.field[i][j] = new_element def move_is_possible(self, direction): def row_is_left_movable(row): def change(i): # true if there'll be change in i-th tile if row[i] == 0 and row[i + 1] != 0: # Move return True if row[i] != 0 and row[i + 1] == row[i]: # Merge return True return False return any(change(i) for i in range(len(row) - 1)) 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 direction in check: return check[direction](self.field) else: return False def main(stdscr): def init(): #重置游戏棋盘 game_field.reset() return 'Game' def not_game(state): #画出 GameOver 或者 Win 的界面 game_field.draw(stdscr) #读取用户输入得到action,判断是重启游戏还是结束游戏 action = get_user_action(stdscr) responses = defaultdict(lambda: state) #默认是当前状态,没有行为就会一直在当前界面循环 responses['Restart'], responses['Exit'] = 'Init', 'Exit' #对应不同的行为转换到不同的状态 return responses[action] def game(): #画出当前棋盘状态 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): # move successful 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=32) state = 'Init' #状态机开始循环 while state != 'Exit': state = state_actions[state]() curses.wrapper(main)
Weitere X-Schritt-für-Schritt-Anleitungen zur Implementierung des 2048-Minispiels in Python finden Sie auf der chinesischen PHP-Website!