200 lines of python code for 2048 games, python2048

Source: Internet
Author: User

200 lines of python code for 2048 games, python2048

Create a game file 2048.py

First, import the required package:

import cursesfrom random import randrange, choicefrom collections import defaultdict

Main Logic

User behavior

All valid inputs can be converted to "Up, down, left, right, game reset, and exit", expressed in actions

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

Valid input keys are the most common W (top), A (left), S (bottom), D (right), R (reset), Q (exit ), take into account the Enable of the upper-case key to obtain the valid key value list:

letter_codes = [ord(ch) for ch in 'WASDRQwasdrq']

Associate input with behavior:

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

State Machine

When dealing with the game's main logic, we will use a very common technology: the state machine, or, more accurately, the finite state machine (FSM)

You will find that 2048 games can easily be divided into several States for conversion.

State stores the current state. The state_actions dictionary variable serves as the state conversion rule. Its key is the state, and value is the function that returns the next state:

Init: init()Game: game()Win: lambda: not_game('Win')Gameover: lambda: not_game('Gameover')

Exit: Exit the loop

Status opportunities keep repeating until the Exit termination state ends.

The following is the extracted main logic code, which will be supplemented later:

Def main (stdscr): def init (): # reset the Game board return 'game' def not_game (state): # Draw the GameOver or Win interface # Read the user input to get the action, determine whether to Restart the game or stop the game responses = defaultdict (lambda: state) # The default status is the current state. If no action is performed, the responses ['restart'] will be cyclically displayed on the current interface. responses ['delete'] = 'init', 'delete' # convert different behaviors to different States return responses [action] def game (): # Draw the current checkerboard status # Read the user input to get the action if action = 'restart': return 'init 'if action = 'delete': return 'delete' # If successfully moved a step: if the Game wins: return 'win' if the Game fails: return 'gameover' return 'game' state_actions = {'init ': Init, 'win': lambda: not_game ('win'), 'gameover': lambda: not_game ('gameover'), 'game ': game} state = 'init' # The state machine starts loop while state! = 'Exit ': state = state_actions [state] ()

User input processing

Blocking + loop: The corresponding behavior is returned only when valid user input is obtained:

def get_user_action(keyboard): char = "N" while char not in actions_dict: char = keyboard.getch() return actions_dict[char]

Matrix transpose and matrix reversal

By adding these two operations, we can greatly save the amount of code and reduce repetitive work. We can see it later.

Matrix transpose:

def transpose(field): return [list(row) for row in zip(*field)]

Matrix reversal (not Inverse Matrix ):

def invert(field): return [row[::-1] for row in field]

Create a chessboard

Initialize the parameters of the board. You can specify the height and width of the board and the game victory conditions. The default value is the most classic 4 × 4 ~ 2048.

Class GameField (object): def _ init _ (self, height = 4, width = 4, win = 2048): self. height = height # High self. width = width # width self. win_value = 2048 # Pass score self. score = 0 # current score self. highscore = 0 # highest score self. reset () # board reset

Board Operations

Randomly generate a 2 or 4

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 #### reset the checkboard 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 ()### # Merge a row to the left (note: this operation is defined in move and removed for ease of reading) def move_row_left (row): def tighten (row ): # squeeze scattered non-zero units into a piece of 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 ): # merge Adjacent Elements 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 # First squeeze into one and then merge and then squeeze into one return tighten (merge (tighten (row )))

Step by step

By transposing and reversing the matrix, you can directly move the matrix from the left to get the other three directions.

Def move (self, direction): def move_row_left (row): # merge a row to the Left 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 ['low'] = 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

Determine whether to win or lose

Def is_win (self): return 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) #### determine whether def move_is_possible (self, direction): defrow_is_left_movable (row): def change (I ): if row [I] = 0 and row [I + 1]! = 0: # return True if row [I] can be moved. = 0 and row [I + 1] = row [I]: # return True return False return any (change (I) for I in range (len (row) can be merged) -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 ['low'] = lambda field: check ['right'] (transpose (field) if direction in check: return check [direction] (self. field) else: return False

Draw game interface

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') # Draw horizontal split line 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 [Operator]) draw_hor_separator.counter + = 1 def draw_row (row): cast (''. join ('| {: ^ 5 }'. format (num) if num> 0 else '| 'fo R 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)

Complete main logic

After completing the above work, we can complete the main logic!

Def main (stdscr): def init (): # reset the Game board game_field.reset () return 'game' def not_game (state): # Draw the GameOver or Win interface game_field.draw (stdscr) # Read the user input to get the action and determine whether to restart the game or stop the game action = get_user_action (stdscr) responses = defaultdict (lambda: state) # The default status is the current status, if there is no behavior, the current interface will loop responses ['restart'], responses ['exit '] = 'init ', 'Exit '# convert the corresponding behavior to different States return responses [action] def game (): # Draw the current checker status game_field.dr Aw (stdscr) # Read user input to get action = get_user_action (stdscr) if action = 'restart': return 'init 'if action = 'eg ': 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} cu Rses. use_default_colors () game_field = GameField (win = 32) state = 'init' # The state machine starts loop while state! = 'Exit ': state = state_actions [state] ()

Run

Fill in the last line of code:

curses.wrapper(main)

Full Code address: https://github.com/JLUNeverMore/easy_2048-in-200-lines

Summary

The above section describes how to implement the 200-line python code 2048 game. I hope it will help you. If you have any questions, please leave a message and I will reply to you in a timely manner. Thank you very much for your support for the help House website!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.