package ai;

import controller.Game;

import java.util.Random;

/**
 * The {@code Bot} class represents an automated player for the game.
 * It is designed to simulate player actions in the game by making moves autonomously.
 * The class contains logic to randomly decide between different actions such as moving
 * left, moving right, or performing a long drop of the current game piece (MultiMino).
 *
 * <p>This class is an essential part of the AI (Artificial Intelligence) component of the game.
 * It uses a {@code Random} object to generate random decisions, thereby introducing unpredictability
 * in the bot's gameplay.</p>
 *
 * <p>Each move made by the bot is based on a random selection. The bot can move the current game piece
 * to the left or right or perform a long drop to instantly bring the game piece to the lowest possible
 * position. The actions are executed within the context of the provided {@code Game} instance.</p>
 *
 * <p>After making a move, if the game is not paused, it triggers a repaint of the game window to reflect
 * the changes on the game board.</p>
 *
 * @version 0.1 - 2023-11-29, 16:05 PM
 * @author Matthieu M
 *
 * TODO: bot
 *
 */
public class Bot {
    private Random random;
    private int moveCount;
    private int rotateCount;

    public Bot() {
        random = new Random();
        moveCount = 0;
        rotateCount = 0;
    }

    public void makeMove(Game game) {
        // Step 1: Move left or right between 3 and 7 times
        if (moveCount < 3 || (moveCount < 7 && random.nextBoolean())) {
            boolean moveLeft = random.nextBoolean();
            game.moveMultiMino(moveLeft ? -1 : 1, 0);
            moveCount++;
        }
        // Step 2: Rotate between 1 and 4 times
        else if (rotateCount < 1 || (rotateCount < 4 && random.nextBoolean())) {
            game.rotateMultiMino(game.getCurrentMultiMino());
            rotateCount++;
        }
        // Step 3: Long drop
        else {
            while (game.canMoveMultiMino(game.getCurrentMultiMino(), 0, 1)) {
                game.moveMultiMino(0, 1);
            }
            resetCounts();
        }

        // Repaint the game window if it's not paused
        if (!game.isPaused()) {
            game.repaintWindow();
        }
    }

    private void resetCounts() {
        moveCount = 0;
        rotateCount = 0;
    }
}

package config;

import java.awt.*;

/**
 * The {@code Config} class holds the configuration constants for the game.
 * This includes settings for window size, board dimensions, color schemes, and game timings.
 * This centralized configuration makes it easier to manage and modify the game's settings.
 *
 * @version 0.1 - last updated on 2023-11-18, 13:52 PM
 * @author Matthieu M
 */

public class Config {
    // Prevents instantiation
    private Config() {}

    // Window Settings
    public static final String GAME_TITLE = "Basic Mino Game";
    public static final int WINDOW_WIDTH = 1200;
    public static final int WINDOW_HEIGHT = 900;

    // Board Settings
    public static final Color BACKGROUND_COLOR = new Color(0, 0, 60); // Dark blue
    // Darker background color for the first five rows
    public static final Color DARKER_BACKGROUND_COLOR = new Color(0, 0, 45);
    public static final int CELL_SIZE = 30;
    public static final int BOARD_WIDTH = 7;
    public static final int BOARD_HEIGHT = 20;

    // Game Timings
    public static final int GAME_DELAY = 1000;
    public static final int GAME_DELAY_DECREASE = 300;
    public static final int GAME_DELAY_POINT_INCREMENTS = 3;

    // Score Box Settings
    public static final int SCORE_BOX_WIDTH = 250;
    public static final int SCORE_BOX_HEIGHT = 250;
    public static final int SCORE_BOX_PADDING = 50;
    public static final Color SCORE_BOX_COLOR = Color.GRAY;
    public static final Font SCORE_BOX_FONT = new Font("Arial", Font.BOLD, 16);

    // Controls Box Settings
    public static final int CONTROLS_BOX_PADDING = 50;
    public static final int CONTROLS_BOX_RIGHT_PADDING = 10;
    public static final Color CONTROLS_BOX_COLOR = Color.DARK_GRAY;
    public static final Font CONTROLS_BOX_FONT = new Font("Arial", Font.BOLD, 16);


    // Game Settings
    public static final int POINTS_PER_ROW = 1;

    // Game Controls
    // TODO (MM): implement enums?
    public static final String [] GAME_CONTROLS = {
            "Keyboard Commands",
            "",
            "Controls:",
            "Left Arrow - Move Left",
            "Right Arrow - Move Right",
            "Down Arrow - Move Down",
            "Space Bar (Long Press) - Drop",
            "P - Pause/Resume",
            "ESC - Open Menu"
    };

    // AI
    public static final int BOT_ACTION_DELAY = 200; // time between bot actions

}
package config;

import java.util.*;

/**
 * The {@code MultiMinoTemplates} class contains the definitions of various Pentomino patterns used in the game.
 * It provides a central repository of all the standard Pentomino shapes, represented as 2D arrays. Each array
 * defines the structure of a Pentomino shape, where '1' represents a filled block and '0' represents an empty space.
 *
 * <p>This class is crucial for generating different Pentomino shapes in the game and can be easily extended to
 * include new shapes. The patterns are used by the game engine to render the Pentominos on the game board.</p>
 *
 * <p>Key patterns include X, I, Z, T, U, V, W, Y, L, P, N, and F patterns, each representing a unique Pentomino.</p>
 *
 * @since 0.1
 * @version 0.2 - added getAllPatternVariations() and its helper methods (2023-11-22, 13:46 PM)
 *
 * @author Matthieu M
 *
 */
public class MultiMinoTemplates {

    // Representation of the empty Pentomino
    public static final int[][] EMPTY_PATTERN = {
            {0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0},
    };

    // Representation of the X Pentomino
    public static final int[][] X_PATTERN = {
            {0, 0, 0, 0, 0},
            {0, 0, 1, 0, 0},
            {0, 1, 1, 1, 0},
            {0, 0, 1, 0, 0},
            {0, 0, 0, 0, 0},
    };

    // Representation of the I Pentomino
    public static final int[][] I_PATTERN = {
            {0, 0, 1, 0, 0},
            {0, 0, 1, 0, 0},
            {0, 0, 1, 0, 0},
            {0, 0, 1, 0, 0},
            {0, 0, 1, 0, 0},
    };

    // Representation of the Z Pentomino
    public static final int[][] Z_PATTERN = {
            {0, 0, 0, 0, 0},
            {0, 0, 1, 1, 0},
            {0, 0, 1, 0, 0},
            {0, 1, 1, 0, 0},
            {0, 0, 0, 0, 0},
    };

    // Representation of the T Pentomino
    public static final int[][] T_PATTERN = {
            {0, 0, 0, 0, 0},
            {0, 1, 1, 1, 0},
            {0, 0, 1, 0, 0},
            {0, 0, 1, 0, 0},
            {0, 0, 0, 0, 0},
    };

    // Representation of the U Pentomino
    public static final int[][] U_PATTERN = {
            {0, 0, 0, 0, 0},
            {0, 1, 0, 1, 0},
            {0, 1, 1, 1, 0},
            {0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0},
    };

    // Representation of the V Pentomino
    public static final int[][] V_PATTERN = {
            {0, 0, 0, 0, 0},
            {0, 1, 1, 1, 0},
            {0, 1, 0, 0, 0},
            {0, 1, 0, 0, 0},
            {0, 0, 0, 0, 0},
    };


    // Representation of the W Pentomino
    public static final int[][] W_PATTERN = {
            {0, 0, 0, 0, 0},
            {0, 0, 1, 1, 0},
            {0, 0, 1, 0, 0},
            {0, 1, 1, 0, 0},
            {0, 0, 0, 0, 0},
    };

    // Representation of the Y Pentomino
    public static final int[][] Y_PATTERN = {
            {0, 1, 0, 0, 0},
            {0, 1, 1, 0, 0},
            {0, 1, 0, 0, 0},
            {0, 1, 0, 0, 0},
            {0, 0, 0, 0, 0},
    };

    // Representation of the L Pentomino
    public static final int[][] L_PATTERN = {
            {0, 1, 0, 0, 0},
            {0, 1, 0, 0, 0},
            {0, 1, 0, 0, 0},
            {0, 1, 1, 0, 0},
            {0, 0, 0, 0, 0},
    };

    // Representation of the P Pentomino
    public static final int[][] P_PATTERN = {
            {0, 0, 0, 0, 0},
            {0, 1, 1, 0, 0},
            {0, 1, 1, 0, 0},
            {0, 1, 0, 0, 0},
            {0, 0, 0, 0, 0},
    };

    // Representation of the N Pentomino
    public static final int[][] N_PATTERN = {
            {0, 0, 0, 0, 0},
            {0, 1, 1, 0, 0},
            {0, 0, 1, 1, 1},
            {0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0},
    };

    // Representation of the N Pentomino
    public static final int[][] F_PATTERN = {
            {0, 0, 0, 0, 0},
            {0, 0, 1, 1, 0},
            {0, 1, 1, 0, 0},
            {0, 0, 1, 0, 0},
            {0, 0, 0, 0, 0},
    };

    /**
     * Retrieves a specified pattern by its name.
     *
     * @param patternName The string name of the pattern to retrieve.
     * @return A 2D integer array representing the requested pattern. Returns {@link #EMPTY_PATTERN} if the name does not match any known pattern.
     */
    public static int[][] getPattern(String patternName) {
        switch (patternName) {
            case "X":
                return X_PATTERN;
            case "I":
                return I_PATTERN;
            case "Z":
                return Z_PATTERN;
            case "T":
                return T_PATTERN;
            case "U":
                return U_PATTERN;
            case "V":
                return V_PATTERN;
            case "W":
                return W_PATTERN;
            case "Y":
                return Y_PATTERN;
            case "L":
                return L_PATTERN;
            case "P":
                return P_PATTERN;
            case "N":
                return N_PATTERN;
            case "F":
                return F_PATTERN;
            default:
                return EMPTY_PATTERN;
        }
    }


    /**
     * Retrieves a random pattern variation. This includes all possible rotations and flips of the patterns.
     *
     * @return A 2D integer array representing a randomly selected pattern variation.
     */
    public static int[][] getRandomPatternVariation() {
        List<int[][]> allVariations = getAllPatternVariations();
        Random random = new Random();
        return allVariations.get(random.nextInt(allVariations.size()));
    }

    /**
     * Rotates a given pattern by 90 degrees clockwise.
     *
     * @param pattern The 2D integer array representing the pattern to rotate.
     * @return A new 2D integer array representing the rotated pattern.
     */
    private static int[][] rotate90(int[][] pattern) {
        final int M = pattern.length;
        final int N = pattern[0].length;
        int[][] rotated = new int[N][M];
        for (int r = 0; r < M; r++) {
            for (int c = 0; c < N; c++) {
                rotated[c][M - 1 - r] = pattern[r][c];
            }
        }
        return rotated;
    }

    /**
     * Flips a given pattern horizontally.
     *
     * @param pattern The 2D integer array representing the pattern to flip.
     * @return A new 2D integer array representing the horizontally flipped pattern.
     */
    private static int[][] flipHorizontal(int[][] pattern) {
        int[][] flipped = new int[pattern.length][pattern[0].length];
        for (int i = 0; i < pattern.length; i++) {
            for (int j = 0; j < pattern[i].length; j++) {
                flipped[i][pattern[i].length - 1 - j] = pattern[i][j];
            }
        }
        return flipped;
    }

    /**
     * Generates all unique variations of a given pattern, including its rotations and horizontal flips.
     *
     * @param pattern The 2D integer array representing the base pattern.
     * @return A list of 2D integer arrays, each representing a unique variation of the pattern.
     */
    public static List<int[][]> generateAllVariations(int[][] pattern) {
        Set<String> seen = new HashSet<>();
        List<int[][]> variations = new ArrayList<>();

        int[][] current = pattern;
        for (int i = 0; i < 4; i++) { // 4 rotations
            current = rotate90(current);
            if (seen.add(Arrays.deepToString(current))) {
                variations.add(current);
            }

            int[][] flippedH = flipHorizontal(current);
            if (seen.add(Arrays.deepToString(flippedH))) {
                variations.add(flippedH);
            }
        }

        return variations;
    }

    /**
     * Compiles all variations of each predefined pattern into a single list. This includes rotations and horizontal flips of each pattern.
     *
     * @return A list of 2D integer arrays, each representing a unique pattern variation from the set of predefined patterns.
     */
    public static List<int[][]> getAllPatternVariations() {
        List<int[][]> allVariations = new ArrayList<>();
        int[][][] patterns = {X_PATTERN, I_PATTERN, Z_PATTERN, T_PATTERN, U_PATTERN, V_PATTERN, W_PATTERN, Y_PATTERN, L_PATTERN, P_PATTERN, N_PATTERN, F_PATTERN};
        for (int[][] pattern : patterns) {
            allVariations.addAll(generateAllVariations(pattern));
        }
        return allVariations;
    }

    // Place additional patterns and methods here
}