commit 813fcd2cb50357d59fcb686caf8b8a27998e9e08 Author: That_One_Nerd Date: Tue Sep 10 10:13:02 2024 -0400 Added the minesweeper game. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ed0b2c --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +# Python cache files. +*/__pycache__/ + +# Build files. +*/bin/ +*/obj/ +convimg.out + +# Other stuff. +.DS_Store diff --git a/Minesweeper/.clangd b/Minesweeper/.clangd new file mode 100644 index 0000000..8823bc7 --- /dev/null +++ b/Minesweeper/.clangd @@ -0,0 +1,3 @@ +CompileFlags: # Add the include folder. + Add: + - "--include-directory=C:\\Users\\kyley\\Desktop\\Coding\\TiCalculatorModding\\Libraries\\CE_C-C++_Toolchain_11.0\\include" diff --git a/Minesweeper/.gitignore b/Minesweeper/.gitignore new file mode 100644 index 0000000..73175e6 --- /dev/null +++ b/Minesweeper/.gitignore @@ -0,0 +1,7 @@ +obj/ +bin/ +src/gfx/*.c +src/gfx/*.h +src/gfx/*.8xv +.DS_Store +convimg.out diff --git a/Minesweeper/24to16color.py b/Minesweeper/24to16color.py new file mode 100644 index 0000000..da832d6 --- /dev/null +++ b/Minesweeper/24to16color.py @@ -0,0 +1,45 @@ +import sys + +INPUT_R = 8 +INPUT_G = 8 +INPUT_B = 8 + +OUTPUT_R = 5 +OUTPUT_G = 6 +OUTPUT_B = 5 + +def convert(color_in: int) -> int: + global INPUT_R, INPUT_G, INPUT_B + global OUTPUT_R, OUTPUT_G, OUTPUT_B + + in_r_max = 2 ** INPUT_R - 1 + in_g_max = 2 ** INPUT_G - 1 + in_b_max = 2 ** INPUT_B - 1 + + out_r_max = 2 ** OUTPUT_R - 1 + out_g_max = 2 ** OUTPUT_G - 1 + out_b_max = 2 ** OUTPUT_B - 1 + + in_b = color_in & in_b_max + in_g = (color_in >> INPUT_B) & in_g_max + in_r = (color_in >> INPUT_B + INPUT_G) & in_r_max + + r_float = in_r / float(in_r_max) + g_float = in_g / float(in_g_max) + b_float = in_b / float(in_b_max) + + out_r = int(r_float * out_r_max) + out_g = int(g_float * out_g_max) + out_b = int(b_float * out_b_max) + + color_out = out_b + (out_g << OUTPUT_B) + (out_r << (OUTPUT_B + OUTPUT_G)) + return color_out + +if len(sys.argv) < 2: + print("Requires color argument.") +elif len(sys.argv) > 2: + print("Too many arguments!") +else: + input_col = int(sys.argv[1], 16) + output_col = convert(input_col) + print(hex(output_col)) diff --git a/Minesweeper/colorconv.py b/Minesweeper/colorconv.py new file mode 100644 index 0000000..0829fbd --- /dev/null +++ b/Minesweeper/colorconv.py @@ -0,0 +1,94 @@ +import math +import sys + +def print_usage(): + print("Usage: colorconv.py ") + print("") + print(" : The color format to convert from.") + print(" : The color format to convert to.") + print(" : The color to convert the format of.") + print("") + print(" Color formats are formatted as their individual channels.") + print(" Ex.") + print(" r8g8b8") + print(" r5g6b5") + print("") + print(" Color data is represented as a number. Must be hexadecimal.") + print(" The output is a single color value in hexadecimal.") + +def total_format_bytes(format: tuple[int, int, int]): + bits = sum(format) + return math.ceil(bits / 8) + +def determine_format(format: str) -> tuple[int, int, int]: + r_ind: int = format.index("r") + g_ind: int = format.index("g") + b_ind: int = format.index("b") + + r_sub: str = format[(r_ind + 1):g_ind] + g_sub: str = format[(g_ind + 1):b_ind] + b_sub: str = format[(b_ind + 1):] + + r_val = int(r_sub) + g_val = int(g_sub) + b_val = int(b_sub) + + return (r_val, g_val, b_val) + +def convert_color(format_in: tuple[int, int, int], format_out: tuple[int, int, int], color_in): + in_r_max = 2 ** format_in[0] - 1 + in_g_max = 2 ** format_in[1] - 1 + in_b_max = 2 ** format_in[2] - 1 + + out_r_max = 2 ** format_out[0] - 1 + out_g_max = 2 ** format_out[1] - 1 + out_b_max = 2 ** format_out[2] - 1 + + in_r: int + in_g: int + in_b: int + + if isinstance(color_in, int): + in_b = color_in & in_b_max + in_g = (color_in >> format_in[2]) & in_g_max + in_r = (color_in >> (format_in[2] + format_in[1])) & in_r_max + else: + in_r = color_in[0] + in_g = color_in[1] + in_b = color_in[2] + + r_float = in_r / float(in_r_max) + g_float = in_g / float(in_g_max) + b_float = in_b / float(in_b_max) + + out_r = int(r_float * out_r_max) + out_g = int(g_float * out_g_max) + out_b = int(b_float * out_b_max) + + color_out = out_b + (out_g << format_out[2]) + (out_r << (format_out[2] + format_out[1])) + return color_out + +def main(argv: list[str]): + argc: int = len(argv) + if argc < 4: + print_usage() + return + elif argc > 4: + print("Too many arguments!\n") + print_usage() + return + + # The first argument is this file. Happens when calling python.exe. + format_in_str: str = argv[1] + format_out_str: str = argv[2] + color_str: str = argv[3] + + format_in: tuple[int, int, int] = determine_format(format_in_str) + format_out: tuple[int, int, int] = determine_format(format_out_str) + color = int(color_str, 16) + + result: int = convert_color(format_in, format_out, color) + formatter: str = "0x{:0" + str(total_format_bytes(format_out) * 2) + "X}" + print(formatter.format(result)) + +if __name__ == "__main__": main(sys.argv) diff --git a/Minesweeper/icon.png b/Minesweeper/icon.png new file mode 100644 index 0000000..08e5182 Binary files /dev/null and b/Minesweeper/icon.png differ diff --git a/Minesweeper/imageconv.py b/Minesweeper/imageconv.py new file mode 100644 index 0000000..771ea54 --- /dev/null +++ b/Minesweeper/imageconv.py @@ -0,0 +1,56 @@ +from colorconv import determine_format, convert_color, total_format_bytes +import sys +from PIL import Image + +def print_usage(): + print("Usage: colorconv.py ") + print("") + print(" : The color format to convert to.") + print(" : The color to convert the format of.") + print("") + print(" Color formats are formatted as their individual channels.") + print(" Ex.") + print(" r8g8b8") + print(" r5g6b5") + print("") + print(" Image data is represented as a path to an image file.") + print(" The output is printed code that represents the sprite.") + +def convert_image(format_out: tuple[int, int, int], image: Image.Image) -> str: + output = "{\n" + counter = 0 + size = image.size[0] * image.size[1] + pixels = image.getdata() + formatter: str = "0x{:0" + str(total_format_bytes(format_out) * 2) + "X}" + for y in range(image.size[1]): + output += " " + for x in range(image.size[0]): + num = convert_color([8, 8, 8], format_out, pixels[y * image.size[0] + x]) + output += formatter.format(num) + if counter < size - 1: output += ", " + counter += 1 + output += "\n" + output += "}" + return output + +def main(argv: list[str]): + argc: int = len(argv) + if argc < 3: + print_usage() + return + elif argc > 3: + print("Too many arguments!\n") + print_usage() + return + + # The first argument is this file. Happens when calling python.exe. + format_out_str: str = argv[1] + image_path: str = argv[2] + + format_out: tuple[int, int, int] = determine_format(format_out_str) + image = Image.open(image_path).convert("RGB") + + result = convert_image(format_out, image) + print(result) + +if __name__ == "__main__": main(sys.argv) diff --git a/Minesweeper/makefile b/Minesweeper/makefile new file mode 100644 index 0000000..ddd5787 --- /dev/null +++ b/Minesweeper/makefile @@ -0,0 +1,16 @@ +# ---------------------------- +# Makefile Options +# ---------------------------- + +NAME = MINESWEE +ICON = icon.png +DESCRIPTION = "Minesweeper by Kyle Gilbert" +COMPRESSED = NO +ARCHIVED = NO + +CFLAGS = -Wall -Wextra -Oz +CXXFLAGS = -Wall -Wextra -Oz + +# ---------------------------- + +include $(shell cedev-config --makefile) diff --git a/Minesweeper/sprites/eight.png b/Minesweeper/sprites/eight.png new file mode 100644 index 0000000..54a1c91 Binary files /dev/null and b/Minesweeper/sprites/eight.png differ diff --git a/Minesweeper/sprites/five.png b/Minesweeper/sprites/five.png new file mode 100644 index 0000000..178a5be Binary files /dev/null and b/Minesweeper/sprites/five.png differ diff --git a/Minesweeper/sprites/flag.png b/Minesweeper/sprites/flag.png new file mode 100644 index 0000000..f2a6f4e Binary files /dev/null and b/Minesweeper/sprites/flag.png differ diff --git a/Minesweeper/sprites/four.png b/Minesweeper/sprites/four.png new file mode 100644 index 0000000..23102d5 Binary files /dev/null and b/Minesweeper/sprites/four.png differ diff --git a/Minesweeper/sprites/mine.png b/Minesweeper/sprites/mine.png new file mode 100644 index 0000000..73c8a26 Binary files /dev/null and b/Minesweeper/sprites/mine.png differ diff --git a/Minesweeper/sprites/one.png b/Minesweeper/sprites/one.png new file mode 100644 index 0000000..7750fa2 Binary files /dev/null and b/Minesweeper/sprites/one.png differ diff --git a/Minesweeper/sprites/seven.png b/Minesweeper/sprites/seven.png new file mode 100644 index 0000000..a291598 Binary files /dev/null and b/Minesweeper/sprites/seven.png differ diff --git a/Minesweeper/sprites/six.png b/Minesweeper/sprites/six.png new file mode 100644 index 0000000..ee5d059 Binary files /dev/null and b/Minesweeper/sprites/six.png differ diff --git a/Minesweeper/sprites/three.png b/Minesweeper/sprites/three.png new file mode 100644 index 0000000..8955a78 Binary files /dev/null and b/Minesweeper/sprites/three.png differ diff --git a/Minesweeper/sprites/two.png b/Minesweeper/sprites/two.png new file mode 100644 index 0000000..ac7566d Binary files /dev/null and b/Minesweeper/sprites/two.png differ diff --git a/Minesweeper/src/libext.h b/Minesweeper/src/libext.h new file mode 100644 index 0000000..228fd02 --- /dev/null +++ b/Minesweeper/src/libext.h @@ -0,0 +1,66 @@ +#include + +template +class vector +{ +private: + int _size; + T* ptr; + +public: + vector() + { + _size = 0; + ptr = new T[0]; + } + ~vector() + { + delete[] ptr; + } + + const T& at(int index) const + { + return ptr[index]; + } + T& at(int index) + { + return ptr[index]; + } + + void add(T item) + { + T* new_ptr = new T[_size + 1]; + memcpy(new_ptr, ptr, _size * sizeof(T)); + new_ptr[_size] = item; + + delete[] ptr; + ptr = new_ptr; + _size++; + } + + void remove_at(int index) + { + T* new_ptr = new T[_size - 1]; + memcpy(new_ptr, ptr, index * sizeof(T)); // Before + memcpy(new_ptr + index, ptr + index + 1, (_size - index) * sizeof(T)); // After + + delete[] ptr; + ptr = new_ptr; + _size--; + } + + + int size() const + { + return _size; + } + + const T& operator[](int index) const + { + return ptr[index]; + } + T& operator[](int index) + { + return ptr[index]; + } +}; diff --git a/Minesweeper/src/main.cpp b/Minesweeper/src/main.cpp new file mode 100644 index 0000000..70015a2 --- /dev/null +++ b/Minesweeper/src/main.cpp @@ -0,0 +1,648 @@ +#pragma region Boilerplate + +#pragma region Disregard +// Removes some errors. Weird. +typedef int int24_t; +typedef unsigned int uint24_t; +#pragma endregion + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#pragma endregion + +#include "libext.h" +#include "sprites.h" + +// Useful macros. +#define VRAM_START ((uint16_t*)0xD40000) +#define SCREEN_WIDTH 320 +#define SCREEN_HEIGHT 240 +#define HEADER_SIZE 30 +#define VRAM_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT) + +#define GET_TILE_INDEX(c, r) ((r) * game.columns + (c)) +#define GET_TILE_AT(c, r) (tiles[(r) * game.columns + (c)]) + +enum DirectionType : uint8_t +{ + DIR_UP, + DIR_LEFT, + DIR_RIGHT, + DIR_DOWN +}; +struct GameInfo +{ + uint8_t columns = 16; // Width + uint8_t rows = 12; // Height + uint16_t mines = 48; +}; +struct ScreenInfo +{ + int8_t scroll_x = 0; + int8_t scroll_y = 0; + + int8_t selection_x = 0; + int8_t selection_y = 0; +}; +enum TileFlags : uint8_t +{ + TILE_NO_FLAGS = 0x00, + TILE_IS_MINE = 0x01, + TILE_REVEALED = 0x02, + TILE_FLAGGED = 0x04 +}; +struct TileInfo +{ + TileFlags flags = TILE_NO_FLAGS; + uint8_t mines_around = 0; +}; + +GameInfo game; +ScreenInfo screen; +TileInfo* tiles = nullptr; +int tile_count; +bool lost = false, won = false; +int remaining_tiles; + +void initialize() +{ + game = GameInfo(); + screen = ScreenInfo(); + + srand(rtc_Time()); +} +void setup_tiles() +{ + if (tiles != nullptr) delete[] tiles; + tile_count = game.columns * game.rows; + tiles = new TileInfo[tile_count]; + + if (game.mines >= tile_count) game.mines = tile_count; + remaining_tiles = tile_count - game.mines; + + // Randomize mine positions. + for (int i = 0; i < game.mines; i++) + { + _choose_pos: + int mine_pos = rand() % tile_count; + + // Using = instead of & and | because we're setting up for the first time. + TileInfo& tile = tiles[mine_pos]; + if (tile.flags & TILE_IS_MINE) goto _choose_pos; // Mine already there, try again. + tile.flags = TILE_IS_MINE; + } + + // Another loop. Calculate the amount of mines around each tile. + for (int r = 0; r < game.columns; r++) + { + for (int c = 0; c < game.rows; c++) + { + TileInfo& tile = GET_TILE_AT(r, c); + if (tile.flags & TILE_IS_MINE) continue; // This is a mine, we know what that means. + + int adjacent_rows[8] = + { + r - 1, + r - 1, + r, + r + 1, + r + 1, + r + 1, + r, + r - 1 + }; + int adjacent_columns[8] = + { + c, + c + 1, + c + 1, + c + 1, + c, + c - 1, + c - 1, + c - 1 + }; + for (int i = 0; i < 8; i++) + { + int ind_row = adjacent_rows[i], + ind_column = adjacent_columns[i]; + if (ind_row < 0 || ind_row >= game.columns || + ind_column < 0 || ind_column >= game.rows) continue; // Tile is hugging the side, ignore this one. + TileInfo& adjTile = GET_TILE_AT(ind_row, ind_column); + if (adjTile.flags & TILE_IS_MINE) tile.mines_around++; // Mine around here. + } + } + } +} + +// Colors and Formatting +constexpr uint16_t background_color = 0xB5D6; // #BDBDBD + +constexpr uint16_t tile_shadow_color = 0x7BEF; +constexpr uint16_t tile_highlight_color = 0xFFFF; +constexpr uint8_t tile_size = 20; +constexpr uint8_t tile_3d_effect_size = 3; + +constexpr uint8_t arrow_size = 14; +constexpr uint8_t arrow_distance = 10; +constexpr uint16_t arrow_color = 0x000; + +constexpr uint16_t selection_color = 0xF800; +constexpr uint16_t win_selection_color = 0x07E0; +constexpr uint16_t selection_width = 3; + +void draw_sprite(int row, int column, uint16_t* sprite, int sprite_width, int sprite_height) +{ + uint16_t pos_x = row + screen.scroll_x, + pos_y = column + screen.scroll_y; + + int pix_x = pos_x * tile_size, + pix_y = pos_y * tile_size; + + if (pix_x < 0 || pix_x >= SCREEN_WIDTH || + pix_y < 0 || pix_y >= SCREEN_HEIGHT) return; // Sprite is off-screen. + + // Find middle of tile and offset by sprite size. + pix_x += (tile_size - sprite_width) / 2; + pix_y += (tile_size - sprite_height) / 2; + + uint16_t* vram = VRAM_START + pix_y * SCREEN_WIDTH + pix_x; + for (int y = 0; y < sprite_height; y++) + { + for (int x = 0; x < sprite_width; x++) + { + memcpy(vram, sprite, sprite_width * sizeof(uint16_t)); + } + vram += SCREEN_WIDTH; + sprite += sprite_width; + } +} + +void render_background() +{ + // Can't use memset! + // The upper byte gets replaced by the lower one. + + // Draw sequential lines to make things faster. + uint16_t* vram = VRAM_START; + for (int x = 0; x < SCREEN_WIDTH; x++) vram[x] = background_color; + + for (int y = 1; y < SCREEN_HEIGHT; y++) + { + memcpy(vram + SCREEN_WIDTH, vram, SCREEN_WIDTH * sizeof(uint16_t)); + vram += SCREEN_WIDTH; + } +} +void render_tile_3d_effect(int row, int column) +{ + uint16_t pos_x = row + screen.scroll_x, + pos_y = column + screen.scroll_y; + + int pix_x = pos_x * tile_size, + pix_y = pos_y * tile_size; + + // First render the highlight with two rectangles. + uint16_t* vram = VRAM_START + pix_y * SCREEN_WIDTH + pix_x + tile_3d_effect_size; + for (int x = 0; x < tile_size - tile_3d_effect_size; x++) vram[x] = tile_highlight_color; + + // Copy line for horizontal part. + for (int y = 0; y < tile_3d_effect_size - 1; y++) + { + memcpy(vram + SCREEN_WIDTH, vram, (tile_size - tile_3d_effect_size) * sizeof(uint16_t)); + vram += SCREEN_WIDTH; + } + + // Copy line for vertical part. + uint16_t* vram_side = vram + (tile_size - tile_3d_effect_size * 2); + for (int y = 0; y < tile_size - tile_3d_effect_size * 2; y++) + { + memcpy(vram_side + SCREEN_WIDTH, vram_side, tile_3d_effect_size * sizeof(uint16_t)); + vram_side += SCREEN_WIDTH; + } + + // Now render the shadow with two rectangles. + vram = VRAM_START + (pix_y + tile_size - tile_3d_effect_size) * SCREEN_WIDTH + pix_x + tile_3d_effect_size - 3; + for (int x = 0; x < tile_size - 3; x++) vram[x] = tile_shadow_color; + + // Copy line for horizontal part. + for (int y = 0; y < tile_3d_effect_size - 1; y++) + { + memcpy(vram + SCREEN_WIDTH, vram, tile_size * sizeof(uint16_t)); + vram += SCREEN_WIDTH; + } + + // Copy line for vertical part. + vram_side = vram - (tile_3d_effect_size - 1) * SCREEN_WIDTH; + for (int y = 0; y < tile_size - tile_3d_effect_size * 2; y++) + { + memcpy(vram_side - SCREEN_WIDTH, vram_side, tile_3d_effect_size * sizeof(uint16_t)); + vram_side -= SCREEN_WIDTH; + } +} +void render_tile_selection(int row, int column, uint16_t color) +{ + uint16_t pos_x = row + screen.scroll_x, + pos_y = column + screen.scroll_y; + + int pix_x = pos_x * tile_size, + pix_y = pos_y * tile_size; + + if (pix_x < 0 || pix_x >= SCREEN_WIDTH || + pix_y < 0 || pix_y >= SCREEN_HEIGHT) return; // Selection is off-screen. + + // Render selection with three rectangles. + uint16_t* vram = VRAM_START + pix_y * SCREEN_WIDTH + pix_x; + for (int x = 0; x < tile_size; x++) vram[x] = color; + + // Copy line for top part. + for (int y = 1; y < selection_width; y++) + { + memcpy(vram + SCREEN_WIDTH, vram, tile_size * sizeof(uint16_t)); + vram += SCREEN_WIDTH; + } + + // Copy line for left part. + uint16_t* vram_side = vram + SCREEN_WIDTH; + for (int y = 0; y < tile_size - selection_width * 2; y++) + { + memcpy(vram_side, vram, selection_width * sizeof(uint16_t)); + vram_side += SCREEN_WIDTH; + } + + // Copy line for right part. + vram_side = vram + SCREEN_WIDTH + (tile_size - selection_width); + for (int y = 0; y < tile_size - selection_width * 2; y++) + { + memcpy(vram_side, vram, selection_width * sizeof(uint16_t)); + vram_side += SCREEN_WIDTH; + } + + // Copy line for bottom part. + uint16_t* new_vram = vram + SCREEN_WIDTH * (tile_size - selection_width * 2 + 1); + for (int y = 0; y < selection_width; y++) + { + memcpy(new_vram, vram, tile_size * sizeof(uint16_t)); + new_vram += SCREEN_WIDTH; + } +} +void render_tile(int row, int column) +{ + constexpr int tiles_visible_x = SCREEN_WIDTH / tile_size, + tiles_visible_y = SCREEN_HEIGHT / tile_size; + + const TileInfo& tile = GET_TILE_AT(row, column); + + int16_t pos_x = row + screen.scroll_x, + pos_y = column + screen.scroll_y; + + if (pos_x < 0 || pos_x >= tiles_visible_x || + pos_y < 0 || pos_y >= tiles_visible_y) return; // Off screen. + + // No need to render the tile background because it's + // just the regular background. + if (tile.flags & TILE_REVEALED) + { + if (tile.flags & TILE_IS_MINE) + { + // Uh oh. + draw_sprite(row, column, (uint16_t*)sprite_mine, 14, 14); + } + else if (tile.mines_around > 0) + { + // Draw number icon. + uint16_t* sprite; + switch (tile.mines_around) + { + case 1: + sprite = (uint16_t*)sprite_one; + break; + + case 2: + sprite = (uint16_t*)sprite_two; + break; + + case 3: + sprite = (uint16_t*)sprite_three; + break; + + case 4: + sprite = (uint16_t*)sprite_four; + break; + + case 5: + sprite = (uint16_t*)sprite_five; + break; + + case 6: + sprite = (uint16_t*)sprite_six; + break; + + case 7: + sprite = (uint16_t*)sprite_seven; + break; + + case 8: + sprite = (uint16_t*)sprite_eight; + break; + } + draw_sprite(row, column, sprite, 14, 14); + } + } + else + { + render_tile_3d_effect(row, column); + if (tile.flags & TILE_FLAGGED) + { + draw_sprite(row, column, (uint16_t*)sprite_flag, 12, 12); + } + } + + // If we lost, show all the mines. + if (lost && (tile.flags & TILE_IS_MINE)) + { + draw_sprite(row, column, (uint16_t*)sprite_mine, 14, 14); + } +} +void render_arrow(DirectionType dir) +{ + uint16_t* vram = VRAM_START; + switch (dir) + { + case DIR_UP: + vram += SCREEN_WIDTH / 2 + arrow_distance * SCREEN_WIDTH; + for (int y = 1; y <= arrow_size; y++) + { + vram += y % 2 == 1 ? SCREEN_WIDTH - 1 : SCREEN_WIDTH; + for (int x = 0; x < 2 * ceil(y / 2.0); x++) vram[x] = arrow_color; + } + break; + + case DIR_LEFT: + vram += SCREEN_WIDTH * SCREEN_HEIGHT / 2 + arrow_distance; + for (int x = 1; x <= arrow_size; x++) + { + vram += x % 2 == 1 ? -SCREEN_WIDTH + 1 : 1; + for (int y = 0; y < 2 * ceil(x / 2.0); y++) vram[SCREEN_WIDTH * y] = arrow_color; + } + break; + + case DIR_RIGHT: + vram += SCREEN_WIDTH * SCREEN_HEIGHT / 2 + (SCREEN_WIDTH - arrow_distance); + for (int x = 1; x <= arrow_size; x++) + { + vram -= x % 2 == 1 ? SCREEN_WIDTH + 1 : 1; + for (int y = 0; y < 2 * ceil(x / 2.0); y++) vram[SCREEN_WIDTH * y] = arrow_color; + } + break; + + case DIR_DOWN: + vram += SCREEN_WIDTH / 2 + (SCREEN_HEIGHT - arrow_distance) * SCREEN_WIDTH; + for (int y = 1; y <= arrow_size; y++) + { + vram -= y % 2 == 1 ? SCREEN_WIDTH + 1 : SCREEN_WIDTH; + for (int x = 0; x < 2 * ceil(y / 2.0); x++) vram[x] = arrow_color; + } + break; + + default: return; + } +} + +void full_render() +{ + constexpr int tiles_visible_x = SCREEN_WIDTH / tile_size, + tiles_visible_y = SCREEN_HEIGHT / tile_size; + + render_background(); + for (int r = 0; r < game.columns; r++) + { + for (int c = 0; c < game.rows; c++) + { + render_tile(r, c); + } + } + + render_tile_selection(screen.selection_x, screen.selection_y, selection_color); + + int min_tile_visible_x = -screen.scroll_x, + max_tile_visible_x = tiles_visible_x - screen.scroll_x; + int min_tile_visible_y = -screen.scroll_y, + max_tile_visible_y = tiles_visible_y - screen.scroll_y; + + if (min_tile_visible_y > 0) render_arrow(DIR_UP); + if (min_tile_visible_x > 0) render_arrow(DIR_LEFT); + if (max_tile_visible_x < game.columns) render_arrow(DIR_RIGHT); + if (max_tile_visible_y < game.rows) render_arrow(DIR_DOWN); +} + +bool check_completion() +{ + return remaining_tiles == 0; +} + +void reveal_tile(int row, int column) +{ + // We have a vector of tile pointers. we loop until every tile in the vector + // is revealed. if it's revealed, remove it, otherwise add its neighbors and repeat. + // This is double its possible size because I don't want to use additional memory for + // storing the row and column for the tile. + + TileInfo& tile = GET_TILE_AT(row, column); + if (tile.flags & TILE_IS_MINE) + { + if (tile.flags & TILE_FLAGGED) return; // Clicked on a mine, but it was flagged already. Don't show. + + // Otherwise, licked on a mine, we have lost. + lost = true; + return; + } + if (tile.flags & TILE_REVEALED) return; // Already revealed. + + vector tile_rows = vector(), + tile_columns = vector(); + tile_rows.add(row); + tile_columns.add(column); + while (tile_rows.size() > 0) + { + int active_row = tile_rows.at(0), + active_column = tile_columns.at(0); + TileInfo& active = GET_TILE_AT(active_row, active_column); + if ((active.flags & TILE_REVEALED) || + (active.flags & TILE_FLAGGED)) + { + // Already revealed or flagged and can't reveal, remove. + tile_rows.remove_at(0); + tile_columns.remove_at(0); + continue; + } + else if (active.flags & TILE_IS_MINE) + { + // Mine, so just reveal. + active.flags = (TileFlags)(active.flags | TILE_REVEALED); + tile_rows.remove_at(0); + tile_columns.remove_at(0); + continue; + } + + // Get neighbors and add them here too. + // If this current tile is a zero tile, reveal all tiles around it. + // Otherwise, only reveal zero tiles nearby, don't reveal other + // non-zero tiles. + int adjacent_rows[8] = + { + active_row - 1, + active_row - 1, + active_row, + active_row + 1, + active_row + 1, + active_row + 1, + active_row, + active_row - 1 + }; + int adjacent_columns[8] = + { + active_column, + active_column + 1, + active_column + 1, + active_column + 1, + active_column, + active_column - 1, + active_column - 1, + active_column - 1, + }; + for (int i = 0; i < 8; i++) + { + int ind_row = adjacent_rows[i], + ind_column = adjacent_columns[i]; + if (ind_row < 0 || ind_row >= game.columns || + ind_column < 0 || ind_column >= game.rows) continue; // Tile is hugging the side, ignore this one. + TileInfo& adjTile = GET_TILE_AT(ind_row, ind_column); + + if (adjTile.flags & TILE_IS_MINE) continue; // Tile is mine, ignore. + if (adjTile.flags & TILE_REVEALED) continue; // Already revealed, ignore. + if (active.mines_around > 0 && adjTile.mines_around > 0) continue; // Non-zero tile can't reveal other non-zero tiles, ignore. + tile_rows.add(ind_row); + tile_columns.add(ind_column); + } + + active.flags = (TileFlags)(active.flags | TILE_REVEALED); + tile_rows.remove_at(0); + tile_columns.remove_at(0); + remaining_tiles--; + } +} +void flag_tile(int row, int column) +{ + TileInfo& tile = GET_TILE_AT(row, column); + if (tile.flags & TILE_REVEALED) return; // Already revealed, ignore. + tile.flags = (TileFlags)(tile.flags ^ TILE_FLAGGED); +} + +void display_win() +{ + // Highlight mines in green. + for (int r = 0; r < game.columns; r++) + { + for (int c = 0; c < game.rows; c++) + { + TileInfo& tile = GET_TILE_AT(r, c); + if (!(tile.flags & TILE_IS_MINE)) continue; // Ignore non-mines. + render_tile_selection(r, c, win_selection_color); + } + } +} + +int main() +{ + // TODO: only full render once. check for empty space and fill that when scrolling. + // TODO: replace the check for out-of-bounds cells with a more optimized for loop. + // this should probably be for 2.0, not this one. + + // Initialize + initialize(); + setup_tiles(); + + while (true) + { + full_render(); + + if (check_completion() || won) + { + won = true; + display_win(); + } + + _getkey: + uint16_t key = os_GetKey(); + + switch (key) + { + case k_Up: + if (lost || won) goto _getkey; // Lost, can't do anything. + screen.scroll_y++; + break; + + case k_Down: + if (lost || won) goto _getkey; // Lost, can't do anything. + screen.scroll_y--; + break; + + case k_Right: + if (lost || won) goto _getkey; // Lost, can't do anything. + screen.scroll_x--; + break; + + case k_Left: + if (lost || won) goto _getkey; // Lost, can't do anything. + screen.scroll_x++; + break; + + case k_4: + if (lost || won) goto _getkey; // Lost, can't do anything. + screen.selection_x--; + if (screen.selection_x < 0) screen.selection_x = 0; + break; + + case k_6: + if (lost || won) goto _getkey; // Lost, can't do anything. + screen.selection_x++; + if (screen.selection_x >= game.columns) screen.selection_x = game.columns - 1; + break; + + case k_8: + if (lost || won) goto _getkey; // Lost, can't do anything. + screen.selection_y--; + if (screen.selection_y < 0) screen.selection_y = 0; + break; + + case k_2: + if (lost || won) goto _getkey; // Lost, can't do anything. + screen.selection_y++; + if (screen.selection_y >= game.rows) screen.selection_y = game.rows - 1; + break; + + case k_Enter: + if (lost || won) goto _getkey; // Lost, can't do anything. + reveal_tile(screen.selection_x, screen.selection_y); + break; + + case k_DecPnt: + if (lost || won) goto _getkey; // Lost, can't do anything. + flag_tile(screen.selection_x, screen.selection_y); + break; + + case k_Clear: return 0; // End. + default: goto _getkey; // Don't re-render if we press the wrong key. + } + } +} diff --git a/Minesweeper/src/sprites.cpp b/Minesweeper/src/sprites.cpp new file mode 100644 index 0000000..7e60c50 --- /dev/null +++ b/Minesweeper/src/sprites.cpp @@ -0,0 +1,162 @@ +#include "sprites.h" + +const uint16_t sprite_flag[144] = { + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xF800, 0xF800, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xF800, 0xF800, 0xF800, 0xF800, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xF800, 0xF800, 0xF800, 0xF800, 0xF800, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xF800, 0xF800, 0xF800, 0xF800, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xF800, 0xF800, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x0000, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x0000, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x0000, 0x0000, 0x0000, 0x0000, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6 +}; + +const uint16_t sprite_mine[196] = { + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x0000, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x0000, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0x0000, 0xB5D6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xB5D6, 0x0000, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xB5D6, 0xB5D6, + 0xB5D6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xB5D6, 0xB5D6, 0xB5D6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0x0000, 0xB5D6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xB5D6, 0x0000, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x0000, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x0000, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6 +}; + +const uint16_t sprite_one[196] = { + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x001E, 0x001E, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x001E, 0x001E, 0x001E, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x001E, 0x001E, 0x001E, 0x001E, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x001E, 0x001E, 0x001E, 0x001E, 0x001E, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x001E, 0x001E, 0x001E, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x001E, 0x001E, 0x001E, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x001E, 0x001E, 0x001E, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x001E, 0x001E, 0x001E, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x001E, 0x001E, 0x001E, 0x001E, 0x001E, 0x001E, 0x001E, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x001E, 0x001E, 0x001E, 0x001E, 0x001E, 0x001E, 0x001E, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6 +}; +const uint16_t sprite_two[196] = { + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x03E0, 0x03E0, 0x03E0, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x03E0, 0x03E0, 0x03E0, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x03E0, 0x03E0, 0x03E0, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0x03E0, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6 +}; +const uint16_t sprite_three[196] = { + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xF000, 0xF000, 0xF000, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xF000, 0xF000, 0xF000, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xF000, 0xF000, 0xF000, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xF000, 0xF000, 0xF000, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xF000, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6 +}; +const uint16_t sprite_four[196] = { + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x000F, 0x000F, 0x000F, 0xB5D6, 0x000F, 0x000F, 0x000F, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x000F, 0x000F, 0x000F, 0xB5D6, 0x000F, 0x000F, 0x000F, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0x000F, 0x000F, 0x000F, 0xB5D6, 0xB5D6, 0x000F, 0x000F, 0x000F, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0x000F, 0x000F, 0x000F, 0xB5D6, 0xB5D6, 0x000F, 0x000F, 0x000F, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x000F, 0x000F, 0x000F, 0x000F, 0x000F, 0x000F, 0x000F, 0x000F, 0x000F, 0x000F, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x000F, 0x000F, 0x000F, 0x000F, 0x000F, 0x000F, 0x000F, 0x000F, 0x000F, 0x000F, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x000F, 0x000F, 0x000F, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x000F, 0x000F, 0x000F, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x000F, 0x000F, 0x000F, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x000F, 0x000F, 0x000F, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6 +}; +const uint16_t sprite_five[196] = { + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x7800, 0x7800, 0x7800, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x7800, 0x7800, 0x7800, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x7800, 0x7800, 0x7800, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x7800, 0x7800, 0x7800, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0x7800, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6 +}; +const uint16_t sprite_six[196] = { + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x03EF, 0x03EF, 0x03EF, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x03EF, 0x03EF, 0x03EF, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x03EF, 0x03EF, 0x03EF, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x03EF, 0x03EF, 0x03EF, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x03EF, 0x03EF, 0x03EF, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x03EF, 0x03EF, 0x03EF, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0x03EF, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6 +}; +const uint16_t sprite_seven[196] = { + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x0000, 0x0000, 0x0000, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x0000, 0x0000, 0x0000, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x0000, 0x0000, 0x0000, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x0000, 0x0000, 0x0000, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x0000, 0x0000, 0x0000, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x0000, 0x0000, 0x0000, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x0000, 0x0000, 0x0000, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x0000, 0x0000, 0x0000, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6 +}; +const uint16_t sprite_eight[196] = { + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x7BEF, 0x7BEF, 0x7BEF, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x7BEF, 0x7BEF, 0x7BEF, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x7BEF, 0x7BEF, 0x7BEF, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x7BEF, 0x7BEF, 0x7BEF, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x7BEF, 0x7BEF, 0x7BEF, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x7BEF, 0x7BEF, 0x7BEF, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x7BEF, 0x7BEF, 0x7BEF, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0x7BEF, 0x7BEF, 0x7BEF, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0x7BEF, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, + 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6, 0xB5D6 +}; diff --git a/Minesweeper/src/sprites.h b/Minesweeper/src/sprites.h new file mode 100644 index 0000000..7ab6751 --- /dev/null +++ b/Minesweeper/src/sprites.h @@ -0,0 +1,14 @@ +#pragma once +#include + +extern const uint16_t sprite_flag[144]; // This one is 12x12! +extern const uint16_t sprite_mine[196]; + +extern const uint16_t sprite_one[196]; +extern const uint16_t sprite_two[196]; +extern const uint16_t sprite_three[196]; +extern const uint16_t sprite_four[196]; +extern const uint16_t sprite_five[196]; +extern const uint16_t sprite_six[196]; +extern const uint16_t sprite_seven[196]; +extern const uint16_t sprite_eight[196]; diff --git a/README.md b/README.md new file mode 100644 index 0000000..92d6cb0 --- /dev/null +++ b/README.md @@ -0,0 +1,14 @@ +# Computer Studies Projects + +Just a few assignments I made for my 12th grade computer studies class. You get to pick your projects, so these are mine. + +I have about 1-2 weeks for each project. Check the Git commits for specific dates or whatever. + +## Projects + +- Minesweeper/ + - I made Minesweeper for the TI-84 calculator. I tried to be somewhat true to the original Windows one. + - 2 is down, 4 is left, 6 is right, 8 is up for your selection. Enter is to mine and the decimal point places a flag. The arrow keys move the board. + - No additional libraries were used, only the built in TI libraries and the [TI CE toolchain](https://github.com/CE-Programming/toolchain). + - Doesn't run great. It uses 16-bit color mode, so the graphics are somewhat slow to render. I attempted to find the way to switch to 4-bit color mode, but I didn't find enough useful info (the best I've found so far is to dissect the GraphX assembly code). Still runs decent though, I've made as many optimizations as I easily could with the renderer, and everything else is fast. + - **WARNING**: This one can't be built without reconfiguring the `.clangd` file to include the path to the toolchain.