// Declare a global variable to track key presses int key_pressed = 0; // Global variables for canvas dimensions int canvas_width; int canvas_height; // Constants representing game states int GAME_START = 0; int GAME_ENDED = 1; int GAME_SHOW_RESULT = 2; // Constants representing puzzle states int PUZZLE_READY = 0; int PUZZLE_FALLING = 1; int PUZZLE_LANDED = 2; int PUZZLE_IGNORE = 3; // Constants for showing or hiding puzzle int SHOW_PUZZLE = 0; int HIDE_PUZZLE = 1; // Constant for falling speed of puzzles int FALLING_SPEED = 2; // Path to the full image String FULL_IMAGE = "./test_400_600.jpg"; // Global GameState object GameState gs; // Setup function runs once at the beginning void setup() { size(800, 900); // Set canvas size canvas_width = 800; // Initialize canvas width canvas_height = 900; // Initialize canvas height frameRate(30); // Set frame rate gs = new GameState(GAME_ENDED); // Initialize game state } // Draw function runs repeatedly in a loop void draw() { background(204); // Clear the background gs.redraw(); // Call the redraw function in GameState } // Function to draw marks on the canvas void DrawMarks(float marks) { // Convert marks to a string String str_marks = str(marks); textSize(64); // Set text size // Display marks text on the canvas text("marks:", 450, 400); fill(0, 0, 0); // Set text color text(str_marks, 450, 460); // Display marks value fill(0, 0, 0); // Reset text color } // Function to draw "Press to Start" message void DrawPressToStart() { textSize(32); // Set text size // Display instructions for controls text("press \"s\" to start", 450, 480); text("\"j\" = left", 450, 540); text("\"k\" = right", 450, 600); text("\"m\" = down", 450, 660); fill(0, 0, 0); // Set text color } // Function to draw "Game Ended" message void DrawGameEnded() { textSize(32); // Set text size // Display "Game Ended" message and restart instructions text("Game ended", 450, 600); text("press \"s\" to restart", 450, 640); fill(0, 0, 0); // Set text color } // Class representing the game state class GameState { Puzzles puzzles; // Puzzles object in the game int state; // Current state of the game float final_marks; // Final marks earned in the game float each_correct_earn = 100.0 / 16; // Marks earned for each correct puzzle placement // Constructor to initialize game state GameState(int init_state) { state = init_state; // Set initial game state } // Getter method for game state int getState() { return state; } // Method to start the game void start_game() { this.puzzles = new Puzzles(this, FULL_IMAGE); // Create new Puzzles object this.state = GAME_START; // Update game state to start this.puzzles.fall_init_puzzle(); // Initialize the falling puzzle this.final_marks = 0.0; // Reset final marks println("reset marks"); // Print reset marks message } // Method to reset the game void reset_game() { this.state = GAME_ENDED; // Update game state to ended } // Method to end the game void end_game() { this.state = GAME_ENDED; // Update game state to ended println("game ended"); // Print game ended message } // Method to show game result void show_result() { this.state = GAME_SHOW_RESULT; // Update game state to show result print("game show result"); // Print game show result message int correct_placed = 0; // Initialize count for correctly placed puzzles // Iterate through puzzles to check correct placements for (int i = 0; i < 16; i++) { println("--- ---"); println(this.puzzles.puzzle_array[i].puzzle_correct_place); println(this.puzzles.puzzle_array[i].puzzle_user_placed); // Check if puzzle is correctly placed if (this.puzzles.puzzle_array[i].puzzle_correct_place == this.puzzles.puzzle_array[i].puzzle_user_placed) { correct_placed = correct_placed + 1; // Increment correct count } println("--- ---"); } println("correct ?"); println(correct_placed); // Print number of correctly placed puzzles this.final_marks = correct_placed * this.each_correct_earn; // Calculate final marks } // Method to redraw the game void redraw() { if (this.state == GAME_START || this.state == GAME_SHOW_RESULT) { this.puzzles.redraw(); // Redraw puzzles } else if (this.state == GAME_ENDED) { DrawPressToStart(); // Draw "Press to Start" message } if (this.state == GAME_SHOW_RESULT) { DrawGameEnded(); // Draw "Game Ended" message println("draw marks"); // Print draw marks message println(this.final_marks); // Print final marks DrawMarks(this.final_marks); // Draw final marks on the canvas } } } // Function to convert bottom zero coordinate to canvas y coordinate int convert_to_canvas_y(int bottom_zero_coord) { int temp; temp = canvas_height - bottom_zero_coord; // Calculate canvas y coordinate return temp; } // Class representing a puzzle class Puzzle { PImage p_img; // Image for the puzzle int current_x; // Current x coordinate int current_y; // Current y coordinate int current_lane; // Current lane of the puzzle int pos_y; // Y position of the puzzle int lane_puzzle_count; // Count of puzzles in the lane int state; // State of the puzzle int show; // Flag to show or hide the puzzle Puzzles parent_puzzles; // Parent Puzzles object int puzzle_correct_place; // Correct position of the puzzle int puzzle_user_placed; // User placed position of the puzzle // Constructor to initialize puzzle Puzzle(Puzzles puzzles, PImage puzzle_img, int init_pos_x, int init_pos_y, int correct_place) { this.current_x = 99; this.current_y = 99; this.p_img = puzzle_img; // Set puzzle image this.current_lane = 1; // Initialize lane this.state = PUZZLE_READY; // Set initial puzzle state this.pos_y = 0; // Initialize y position this.lane_puzzle_count = 0; // Initialize lane puzzle count this.parent_puzzles = puzzles; // Set parent Puzzles object this.show = HIDE_PUZZLE; // Set initial show flag this.puzzle_correct_place = correct_place; // Set correct place for the puzzle } // Method to get puzzle lane bottom int get_puzzle_lane_bottom(int lane_puzzle_count) { return canvas_height - (150 * (lane_puzzle_count + 1)); // Calculate puzzle lane bottom } // Method to update lane puzzle count void update_lane_puzzle_count(int lane_puzzle_count) { this.lane_puzzle_count = lane_puzzle_count; // Update lane puzzle count } // Method to make puzzle fall to the bottom void fall_to_bottom() { this.pos_y = get_puzzle_lane_bottom(this.parent_puzzles.lane_puzzle_count[this.current_lane]) - 10; // Calculate y position for falling } // Method to redraw the puzzle void redraw() { if (this.state == PUZZLE_FALLING) { this.show = SHOW_PUZZLE; // Set show flag to display puzzle // Check if puzzle is still falling if (this.pos_y < (get_puzzle_lane_bottom(this.parent_puzzles.lane_puzzle_count[this.current_lane]))) { this.pos_y = this.pos_y + FALLING_SPEED; // Move puzzle down } else { this.state = PUZZLE_LANDED; // Change puzzle state to landed } } else if (this.state == PUZZLE_LANDED) { this.parent_puzzles.puzzle_landed(this.current_lane); // Inform parent puzzles about landed puzzle this.state = PUZZLE_IGNORE; // Change puzzle state to ignore this.puzzle_user_placed = lookup_user_puzzle_position(this.current_lane, this.pos_y); // Calculate user placed puzzle } if (this.show == SHOW_PUZZLE) { image(this.p_img, 100 * this.current_lane, this.pos_y); // Draw puzzle on the canvas } } } // Class representing a set of puzzles class Puzzles { PImage img; // Full image for puzzles PImage[] sliced_img = new PImage[16]; // Array to store sliced puzzle images Puzzle[] puzzle_array = new Puzzle[16]; // Array to store puzzle objects int[] puzzle_order = new int[]{12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3}; // Order of puzzles IntList temp_to_shuffle = new IntList(); // Temporary list for shuffling int[] shuffled_puzzle_order = new int[16]; // Shuffled order of puzzles int[] puzzle_state = new int[16]; // State of each puzzle int[][] puzzle_pos_x_y = new int[16][2]; // Positions of puzzles int puzzle_idx = 0; // Index of puzzle int x_div = 400 / 4; // X division for slicing puzzles int y_div = 600 / 4; // Y division for slicing puzzles int lane_puzzle_count[] = new int[]{0, 0, 0, 0}; // Count of puzzles in each lane int current_puzzle = 0; // Index of current falling puzzle int landed_puzzle = 0; // Index of landed puzzle int fallen_puzzle = 0; // Count of fallen puzzles int test_puzzle_idx = 0; // Index of test puzzle GameState parent_gs; // Parent game state object IntList fallen_puzzles; // List of fallen puzzles // Method to load the full image and slice it void load_image(String jpg_file_path) { this.img = loadImage(jpg_file_path); // Load full image this.slice(); // Slice the image } // Method to slice the image into puzzles void slice() { // Initialize puzzle index and i puzzle_idx = 0; int i = 0; // Define x and y rulers for slicing int x_ruler[] = new int[]{0, x_div, 2 * x_div, 3 * x_div}; int y_ruler[] = new int[]{0, y_div, 2 * y_div, 3 * y_div}; // Iterate through rows and columns for slicing for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { puzzle_idx = puzzle_order[i]; // Get puzzle index from order this.sliced_img[puzzle_idx] = this.img.get(x_ruler[x], y_ruler[y], x_div, y_div); // Slice the image i = i + 1; // Increment i } } } // Constructor to initialize puzzles Puzzles(GameState parent_gs, String jpg_file_path) { this.test_puzzle_idx = 0; // Initialize test puzzle index this.parent_gs = parent_gs; // Set parent game state object this.load_image(jpg_file_path); // Load and slice the image for (int i = 0; i < 16; i++) { // Create puzzle objects with sliced images and correct positions this.puzzle_array[i] = new Puzzle(this, sliced_img[i], 1, 1, i); } // Shuffle puzzle order for initial display for (int i = 0; i < 16; i = i + 4) { temp_to_shuffle = new IntList(); temp_to_shuffle.append(i + 0); temp_to_shuffle.append(i + 1); temp_to_shuffle.append(i + 2); temp_to_shuffle.append(i + 3); // Shuffle the temporary list temp_to_shuffle.shuffle(); // Update shuffled puzzle order this.shuffled_puzzle_order[i + 0] = temp_to_shuffle.get(0); this.shuffled_puzzle_order[i + 1] = temp_to_shuffle.get(1); this.shuffled_puzzle_order[i + 2] = temp_to_shuffle.get(2); this.shuffled_puzzle_order[i + 3] = temp_to_shuffle.get(3); } // Initialize fallen puzzles list and other variables this.fallen_puzzles = new IntList(); this.current_puzzle = 0; this.fallen_puzzle = 0; this.landed_puzzle = 0; } // Method to move the active puzzle left void move_left() { if (this.get_active_puzzle().state == PUZZLE_FALLING) { if (this.get_active_puzzle().current_lane > 0) { this.get_active_puzzle().current_lane = this.get_active_puzzle().current_lane - 1; this.get_active_puzzle().update_lane_puzzle_count(1); } } else { println("move ignored"); } } // Method to move the active puzzle right void move_right() { if (this.get_active_puzzle().state == PUZZLE_FALLING) { if (this.get_active_puzzle().current_lane < 3) { this.get_active_puzzle().current_lane = this.get_active_puzzle().current_lane + 1; this.get_active_puzzle().update_lane_puzzle_count(1); } } else { println("move ignored"); } } // Method to move the active puzzle down void move_down() { this.get_active_puzzle().fall_to_bottom(); } // Method to initialize the falling puzzle void fall_init_puzzle() { this.set_active_puzzle(this.shuffled_puzzle_order[this.test_puzzle_idx]); this.get_active_puzzle().state = PUZZLE_FALLING; } // Method to move to the next falling puzzle void fall_next_puzzle() { if (this.fallen_puzzle < (puzzle_array.length - 1)) { this.fallen_puzzle = this.fallen_puzzle + 1; this.test_puzzle_idx = this.test_puzzle_idx + 1; this.set_active_puzzle(this.shuffled_puzzle_order[this.test_puzzle_idx]); gs.puzzles.get_active_puzzle().state = PUZZLE_FALLING; } else { println("all puzzle fallen"); } } // Method to increment lane puzzle count void inc_lane_puzzle_count(int lane) { this.lane_puzzle_count[lane] = this.lane_puzzle_count[lane] + 1; } // Method to handle a landed puzzle void puzzle_landed(int lane) { this.inc_lane_puzzle_count(lane); // Increment lane puzzle count this.fallen_puzzles.append(this.current_puzzle); // Add puzzle to fallen puzzles list // Check if all puzzles have fallen if (this.fallen_puzzles.size() < 16) { gs.puzzles.fall_next_puzzle(); // Move to next falling puzzle } else { println("all puzzle falled"); this.parent_gs.show_result(); // Show game result } } // Method to set the active puzzle void set_active_puzzle(int active_puzzle) { this.current_puzzle = active_puzzle; // Set active puzzle index } // Method to get the active puzzle Puzzle get_active_puzzle() { return this.puzzle_array[this.current_puzzle]; // Return active puzzle object } // Method to redraw the puzzles void redraw() { for (int i = 0; i < this.fallen_puzzles.size(); i++) { this.puzzle_array[this.fallen_puzzles.get(i)].redraw(); // Redraw fallen puzzles } this.get_active_puzzle().redraw(); // Redraw active puzzle } } // Function to lookup user puzzle position based on lane and y position int lookup_user_puzzle_position(int lane, int pos_y) { int[] tmp_list = new int[]{0, 0, 0, 0}; // Initialize temporary list switch (pos_y) { case 750: tmp_list = new int[]{0, 1, 2, 3}; // Update list for y position 750 return tmp_list[lane]; // Return user placed puzzle position case 600: tmp_list = new int[]{4, 5, 6, 7}; // Update list for y position 600 return tmp_list[lane]; // Return user placed puzzle position case 450: tmp_list = new int[]{8, 9, 10, 11}; // Update list for y position 450 return tmp_list[lane]; // Return user placed puzzle position case 300: tmp_list = new int[]{12, 13, 14, 15}; // Update list for y position 300 return tmp_list[lane]; // Return user placed puzzle position default: tmp_list = new int[]{-1, -1, -1, -1}; // Default list for other positions return tmp_list[lane]; // Return user placed puzzle position } } // Function to handle key press events void keyPressed() { if (key_pressed == 0) { // Check key pressed and perform corresponding action if (key == 'j') { gs.puzzles.move_left(); // Move puzzle left } if (key == 'k') { gs.puzzles.move_right(); // Move puzzle right } if (key == 'm') { println("down pressed"); gs.puzzles.move_down(); // Move puzzle down } if (key == 'd') { // Handle other key events } if (key == 's') { gs.start_game(); // Start the game } if (key == 'r') { println("press r to restart"); gs.reset_game(); // Reset the game } if (key == 'n') { // Handle other key events } key_pressed = 1; // Set key pressed flag } } // Function to handle key release events void keyReleased() { key_pressed = 0; // Reset key pressed flag }