Python Day 14: Snake Game and SimpleRev CTF Challenge

The Python content practiced today is Python Day 14 – Snake Game.Reference link:https://mp.weixin.qq.com/s/_Ww9sXfxoMIfHfVafu7HCAUsing the arcade library to set up the framework – pip install arcade

import arcade  # Import the arcade library for graphics rendering and game development
import random  # Import the random library for generating random numbers

# Define a 2D vector class to represent position and direction
class Vector2:
    def __init__(self, x, y):
        self.x = x  # x coordinate
        self.y = y  # y coordinate

    # Define vector addition to allow direct addition of two Vector2 objects
    def __add__(self, other):
        return Vector2(self.x + other.x, self.y + other.y)

    # Define equality operation to compare two Vector2 objects
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

# Direction dictionary storing unit vectors for up, down, left, right movement
DIRECTIONS = {
    "up": Vector2(0, 1),     # Move up
    "down": Vector2(0, -1),  # Move down
    "left": Vector2(-1, 0),  # Move left
    "right": Vector2(1, 0),  # Move right
}

# Game state class storing the snake's position, direction, food, etc.
class GameState:
    def __init__(self, width=20, height=20):
        self.snake = [Vector2(5, 5)]  # Initialize snake position, initial length is 1
        self.direction = DIRECTIONS["right"]  # Initial direction is right
        self.food = self._generate_food()  # Generate food
        self.score = 0  # Score
        self.game_over = False  # Flag indicating if the game is over

    # Generate food ensuring it does not appear on the snake's body
    def _generate_food(self):
        while True:
            new_food = Vector2(random.randint(0, 19), random.randint(0, 19))  # Randomly generate food position in the range 0-19
            if new_food not in self.snake:  # Ensure food does not appear on the snake's body
                return new_food

# Snake game window class, inheriting from arcade.Window
class SnakeGame(arcade.Window):
    def __init__(self):
        super().__init__(width=400, height=400, title="Snake Game")  # Set window size and title
        self.cell_size = 20  # Size of each cell
        self.game = GameState()  # Create game state object
        arcade.set_background_color(arcade.color.BLACK)  # Set background color to black

        # Control snake's movement speed (in seconds)
        self.move_interval = 0.2  # Move every 0.2 seconds
        self.time_since_last_move = 0.0  # Record time since last move

    # Draw game content
    def on_draw(self):
        self.clear()  # Clear the screen
        # Draw each segment of the snake
        for segment in self.game.snake:
            arcade.draw_rect_filled(
                arcade.rect.XYWH(
                    segment.x * self.cell_size + 1,  # Calculate x coordinate for drawing
                    segment.y * self.cell_size + 1,  # Calculate y coordinate for drawing
                    self.cell_size - 2,  # Width
                    self.cell_size - 2   # Height
                ),
                arcade.color.GREEN  # Set snake color to green
            )
        # Draw food
        arcade.draw_circle_filled(
            self.game.food.x * self.cell_size + self.cell_size // 2,  # Calculate food's x coordinate
            self.game.food.y * self.cell_size + self.cell_size // 2,  # Calculate food's y coordinate
            self.cell_size // 2 - 2,  # Calculate food's radius
            arcade.color.RED  # Set food color to red
        )
        # Display score
        arcade.draw_text(
            f"Score: {self.game.score}",  # Text content
            10, self.height - 30,  # Text position (top left)
            arcade.color.WHITE,  # Text color
            16  # Text size
        )

    # Game logic update, called once per frame
    def on_update(self, delta_time):
        if not self.game.game_over:  # Only update if the game is not over
            self.time_since_last_move += delta_time  # Accumulate time

            # Move only if accumulated time exceeds move interval
            if self.time_since_last_move >= self.move_interval:
                self.time_since_last_move = 0.0  # Reset timer
                self._move_snake()  # Move snake
                self._check_collisions()  # Check for collisions

    # Move snake
    def _move_snake(self):
        new_head = self.game.snake[-1] + self.game.direction  # Calculate new head position
        self.game.snake.append(new_head)  # Add new head to snake
        if new_head == self.game.food:  # If snake eats food
            self.game.score += 1  # Increase score by 1
            self.game.food = self.game._generate_food()  # Generate new food
        else:
            self.game.snake.pop(0)  # If not eating food, remove tail (maintain length)

    # Check if snake hits wall or bites itself
    def _check_collisions(self):
        head = self.game.snake[-1]  # Get head position
        if not (0 <= head.x < 20 and 0 <= head.y < 20):  # Check if out of bounds
            self.game.game_over = True  # End game
        if head in self.game.snake[:-1]:  # Check if bites itself
            self.game.game_over = True  # End game

    # Handle keyboard input
    def on_key_press(self, key, modifiers):
        # Up arrow key, prevent direct reversal
        if key == arcade.key.UP and self.game.direction != DIRECTIONS["down"]:
            self.game.direction = DIRECTIONS["up"]
        # Down arrow key, prevent direct reversal
        elif key == arcade.key.DOWN and self.game.direction != DIRECTIONS["up"]:
            self.game.direction = DIRECTIONS["down"]
        # Left arrow key, prevent direct reversal
        elif key == arcade.key.LEFT and self.game.direction != DIRECTIONS["right"]:
            self.game.direction = DIRECTIONS["left"]
        # Right arrow key, prevent direct reversal
        elif key == arcade.key.RIGHT and self.game.direction != DIRECTIONS["left"]:
            self.game.direction = DIRECTIONS["right"]

# Run the game
if __name__ == "__main__":
    game = SnakeGame()  # Create game window
    arcade.run()  # Run game

The actual running effect is:Python Day 14: Snake Game and SimpleRev CTF ChallengeToday’s CTF content practiced isSimpleRevPython Day 14: Snake Game and SimpleRev CTF ChallengeProblem-solving reference link:https://www.cnblogs.com/murasame520/p/18519135

Key Points: Big-endian, Little-endian, Analyzing Pseudocode

As usual, first check the shell, 64-bit program:

Python Day 14: Snake Game and SimpleRev CTF ChallengeAnalyze in IDA64, shift+f12:Python Day 14: Snake Game and SimpleRev CTF ChallengeEnter the key strings:Python Day 14: Snake Game and SimpleRev CTF ChallengeCtrl+x cross-reference:Python Day 14: Snake Game and SimpleRev CTF ChallengeView disassembled code:Python Day 14: Snake Game and SimpleRev CTF ChallengeThis problem examines the judgment of big-endian and little-endian, but the author is not very familiar with this part of knowledge. Therefore, the content from the reference link is quoted here.

Write a script

text = 'killshadow'
key = 'adsfkndcls'
flag = ''
v5 = len(key)
for i in range(10):   # Input ten characters, so loop ten times
    for j in range(ord('A'), ord('z')+1):  # Try all letters to find characters that can make the if condition succeed
        str2 = (j -39 - ord(key[i % v5]) +97) % 26 + 97 # Directly copy the original encryption here, ord(key[i % v5]) is needed because python cannot directly convert strings to ascii codes
        if chr(str2) == text[i]:  # Compare the calculated ascii code chr() with the text content
            flag += chr(j)                break   # The break here means if the if condition succeeds once, end this inner loop and start the second outer loop, if there is no break, it will output many other characters that satisfy the condition
print(flag)

The output result is KLDQCUDFZO, therefore flag{KLDQCUDFZO}.

Python Day 14: Snake Game and SimpleRev CTF Challenge

The problem-solving is correct, solved, time to get off work!

Leave a Comment