Maison >développement back-end >Tutoriel Python >Apprenez étape par étape à implémenter le mini-jeu 2048 en Python
Je pense que le jeu 2048 doit être familier à tout le monde. L'article suivant présente principalement comment utiliser Python pour implémenter le mini-jeu 2048. L'article le présente en détail à travers des commentaires et des exemples de codes. comprendre et l'apprentissage a une certaine valeur de référence. Les amis dans le besoin devraient y jeter un œil.
Avant-propos
Règles du jeu 2048 : Déplacez simplement les touches de direction pour faire superposer les chiffres, et obtenez le score après chaque superposition de ces chiffres . La partie est gagnée lorsque le nombre 2048 apparaît. En même temps, chaque fois que vous déplacez les touches de direction, un chiffre 2 ou 4 sera généré aléatoirement dans la zone vide de la matrice carrée 4*4. Si le carré est rempli de chiffres, alors c'est GameOver.
Schéma logique principal
Schéma logique : Le noir est Couche logique, le bleu est la méthode externe, le rouge est la méthode intra-classe, vous le saurez plus tard~
Laissez-moi vous expliquer la logique principale ligne par ligne . main()
fonction et y croise des fonctions et des classes définies en externe.
Interprétation du code logique principal (voir la fin de l'article pour le code complet)
Le code logique principal est comme suit, suivi de la fonction principale Interprétation de certaines méthodes :
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]()
Interprétation une par une (la case de code sera marquée comme à venir de l'extérieur, s'il n'y a pas de marquage, cela vient de l'intérieur) : Définition Fonction principale
def main(stdscr):
def init(): #重置游戏棋盘 game_field.reset()
reset provient d'une classe définie en externe, l'une des game_field=GameField
Méthode reset :
Externe :
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'
Renvoie l'état d'un jeu en cours. game_field=GameField
Le statut est défini ultérieurement :
La définition du bas de la fonction principale :
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 est une méthode dans la classe importée 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的一些高级概念,我就不做多的介绍了。
La fonction mot du Méthode de dessin ici, je n'expliquerai pas trop, ce sont juste quelques concepts simples.
Mais il utilise un excellent code rationalisé.
Certains endroits suggèrent de découvrir certains concepts avancés de Python, mais je n'entrerai pas dans les détails.
#读取用户输入得到action,判断是重启游戏还是结束游戏 action = get_user_action(stdscr)
Lire le comportement de l'utilisateur, la fonction est issue de la définition initiale du code
#来自外部定义的函数 def get_user_action(keyboard): char = "N" while char not in actions_dict: char = keyboard.getch() return actions_dict[char]
À la fin, c'est-à-dire la troisième étape de l'exécution de la fonction principale, l'instance de state = state_actions[state]()
est définie :
#主函数底部: 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()
La définition de la fonction est similaire à la not_game()
déjà mentionnée ci-dessus , sauf que game()
Avec la boucle interne, c'est à dire si ce n'est pas Redémarrer/Sortir ou juger de l'état après le coup, si ce n'est pas la fin du jeu, ce sera toujours dans la game()
boucle interne .
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()
La signification ici est : state=state_actions[state]
peut être vu comme : state=init()
ou state=not_game(‘Win')
ou un autre not_game(‘Gameover')/game()
Sans plus attendre, voici ma dernière photo de réussite. De plus, vous pouvez déterminer vos conditions de gain finales en définissant win=32 dans les dernières lignes !
Code complet
#-*- 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)
Pour plus d'instructions étape par étape sur la façon d'implémenter le mini-jeu 2048 en Python, veuillez prêter attention au site Web PHP chinois !