Compare commits

..

11 Commits

Author SHA1 Message Date
c609d5ccb0 hills 2024-08-04 15:11:11 +02:00
d99633e7cf bin to array 2024-08-04 14:58:05 +02:00
98a2879129 move to data 2024-08-04 14:51:10 +02:00
86a805b6e9 improve char showing 2024-08-04 14:49:54 +02:00
2ac8c05e1d handle input 2024-08-04 14:43:52 +02:00
7c62375761 font loading and drawing chars 2024-08-03 11:17:48 +02:00
cf538f2cf5 fix 2024-08-03 11:12:12 +02:00
50fe9d9c6d sdl-main 2024-08-03 11:08:26 +02:00
91328c4aca open font 2024-08-03 10:57:53 +02:00
cf7a9a1f1a font 2024-08-03 10:50:29 +02:00
21aeaab088 correct y 2024-08-03 10:47:56 +02:00
27 changed files with 33516 additions and 11 deletions

View File

@ -11,15 +11,25 @@ find_package(SDL2 CONFIG REQUIRED)
find_package(SDL2_ttf CONFIG REQUIRED)
find_package(CURL REQUIRED)
file(GLOB KULLE_SRC src/data/kulle_*_png.cpp)
file(GLOB KULLE_HEADER src/data/kulle_*_png.hpp)
add_executable(hang_man src/main.cpp
src/Game.cpp
src/Game.hpp
src/State.hpp
src/words.hpp
src/words.cpp
src/data/words.hpp
src/data/words.cpp
src/utils.hpp
src/GuessCorrector.cpp
src/GuessCorrector.hpp
src/default_font.cpp
src/default_font.hpp
${KULLE_SRC}
${KULLE_HEADER}
src/data/hills.cpp
src/data/hills.hpp
)
target_link_libraries(hang_man PRIVATE

61
bin-to-array.py Normal file
View File

@ -0,0 +1,61 @@
"""
Use this script to write data files as c arrays. This is used to stay cross-platform for embedding.
"""
import argparse
import os.path
def format_hex_line(data):
hex_data = ', '.join(f'0x{byte:02x}' for byte in data)
return f' {hex_data},\n'
def hexdump_to_cpp_array(file_name: str, output_dir: str, variable_name: str):
path = os.path.join(output_dir, variable_name)
header_path, source_path = f"{path}.hpp", f"{path}.cpp"
# Header
with open(header_path, 'w') as file:
file.write("#pragma once\n\n")
file.write("#include <cstddef>\n\n")
file.write(f"extern const unsigned char {variable_name}[];\n")
file.write(f"extern const size_t {variable_name}_length;\n")
# Source
byte_count = 0
with open(file_name, 'rb') as bin_file, open(source_path, 'w') as source_file:
source_file.write(f"// This is the bytes of {file_name}\n")
source_file.write(f'#include "{variable_name}.hpp"\n\n')
source_file.write(f"const unsigned char {variable_name}[] = {{\n")
while True:
chunk = bin_file.read(16)
if not chunk:
break
byte_count += len(chunk)
source_file.write(format_hex_line(chunk))
source_file.write("};\n")
source_file.write(f"const size_t {variable_name}_length = {byte_count};\n")
def main():
parser = argparse.ArgumentParser(description="Hexdump a file to a cpp array.")
parser.add_argument("file", help="Path to the binary file to be dumped")
parser.add_argument("-d", "--dir", help="Output directory", metavar="OUTPUT")
parser.add_argument("-n", "--name", help="Name of the array and header/source files", default="data")
args = parser.parse_args()
if args.dir:
try:
hexdump_to_cpp_array(args.file, args.dir, args.name)
path = os.path.join(args.dir, args.name)
print(f"Hex dump written to {path}.hpp & {path}.cpp")
except FileNotFoundError:
print(f"File not found: {args.file}")
except IOError as e:
print(f"Error: {e}")
else:
print("No output dir specified. Exiting.")
if __name__ == "__main__":
main()

View File

@ -1,15 +1,20 @@
#include <iostream>
#include <algorithm>
#include <random>
#include <sstream>
#include "Game.hpp"
#include "SDL.h"
#include "SDL_ttf.h"
#include "words.hpp"
#include "data/words.hpp"
#include "utils.hpp"
#include "default_font.hpp"
#include "State.hpp"
const int CHAR_SIZE = 30;
const int STEP_SIZE = CHAR_SIZE + CHAR_SIZE / 2;
const int UNDERSCORE_DY = 10;
const SDL_Color TEXT_COLOR = {255, 255, 255};
const int MAX_GUESSES = 8;
void Game::Run() {
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
@ -64,7 +69,24 @@ void Game::Run() {
SDL_Quit();
}
Game::Game() {
Game::Game() : m_wrong_guesses(0), m_game_state(State::PLAY) {
const char *defaultFontPath = getDefaultFontPath();
if (defaultFontPath == nullptr) {
std::stringstream ss;
ss << "Font path is not set for this platform (null)";
auto s = ss.str();
std::cerr << s << std::endl;
throw std::runtime_error(s);
}
font = TTF_OpenFont(defaultFontPath, CHAR_SIZE);
if (font == nullptr) {
std::stringstream ss;
ss << "Failed to load font: " << TTF_GetError();
auto s = ss.str();
std::cerr << s << std::endl;
throw std::runtime_error(s);
}
std::random_device random_device{};
std::mt19937 rng(random_device());
@ -81,7 +103,19 @@ Game::Game() {
}
void Game::handle_key(SDL_Keycode event) {
if (!isalpha(event))
return;
bool is_valid = guess_corrector->has_char(event);
if (is_valid) {
guess_corrector->add(event);
if (guess_corrector->is_filled_out())
m_game_state = State::WIN;
} else {
m_wrong_guesses += 1;
if (m_wrong_guesses >= MAX_GUESSES) {
m_game_state = State::GAME_OVER;
}
}
}
void Game::draw(SDL_Renderer *renderer) {
@ -95,13 +129,40 @@ void Game::draw_guesses(SDL_Renderer *renderer) {
size_t len = strlen(word);
int total_width = (len - 1) * STEP_SIZE + CHAR_SIZE;
int start_x = (SCREEN_SIZE.x - total_width) / 2;
int char_y = (SCREEN_SIZE.y / 2) - CHAR_SIZE / 2;
int char_y = (SCREEN_SIZE.y / 4) * 3 - CHAR_SIZE / 2;
for (int i = 0; i < len; i++) {
int here = start_x + i * STEP_SIZE;
const SDL_Rect rect = {here, char_y + UNDERSCORE_DY, CHAR_SIZE, 5};
SDL_SetRenderDrawColor(renderer, 255, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderFillRect(renderer, &rect);
std::optional<char> current_char = guess_corrector->guessed().lock()[i];
if (current_char) {
const char text_to_write[] = {*current_char, '\0'};
SDL_Surface *surface = TTF_RenderText_Blended(font, text_to_write, TEXT_COLOR);
if (surface == nullptr) {
std::cerr << "Failed to create surface: " << TTF_GetError() << std::endl;
continue;
}
SDL_Texture *txt = SDL_CreateTextureFromSurface(renderer, surface);
if (txt == nullptr) {
std::cerr << "Failed to create texture: " << SDL_GetError() << std::endl;
SDL_FreeSurface(surface);
continue;
}
int text_width = surface->w;
int text_height = surface->h;
SDL_Rect text_rect = {here + (CHAR_SIZE - text_width) / 2, char_y - text_height, text_width, text_height};
SDL_RenderCopy(renderer, txt, nullptr, &text_rect);
SDL_DestroyTexture(txt);
SDL_FreeSurface(surface);
}
}
SDL_RenderPresent(renderer);

View File

@ -1,11 +1,13 @@
#pragma once
#include <SDL_rect.h>
#include <SDL_events.h>
#include <vector>
#include <optional>
#include <SDL_render.h>
#include "SDL_rect.h"
#include "SDL_events.h"
#include "SDL_render.h"
#include "SDL_ttf.h"
#include "GuessCorrector.hpp"
#include "State.hpp"
const SDL_Point SCREEN_SIZE{800, 800};
@ -14,6 +16,9 @@ private:
std::vector<const char *> all_words;
std::unique_ptr<GuessCorrector> guess_corrector;
const char *word;
_TTF_Font *font;
int m_wrong_guesses;
State m_game_state;
public:
static void Run();
@ -26,5 +31,6 @@ public:
private:
void draw_guesses(SDL_Renderer *renderer);
};

21
src/data/hills.cpp Normal file
View File

@ -0,0 +1,21 @@
#include "hills.hpp"
#include "kulle_0_png.hpp"
#include "kulle_1_png.hpp"
#include "kulle_2_png.hpp"
#include "kulle_3_png.hpp"
#include "kulle_4_png.hpp"
#include "kulle_5_png.hpp"
#include "kulle_6_png.hpp"
#include "kulle_7_png.hpp"
unsigned const char *hills[] = {
kulle_0_png,
kulle_1_png,
kulle_2_png,
kulle_3_png,
kulle_4_png,
kulle_5_png,
kulle_6_png,
kulle_7_png,
};

3
src/data/hills.hpp Normal file
View File

@ -0,0 +1,3 @@
#pragma once
extern unsigned const char *hills[];

4024
src/data/kulle_0_png.cpp Normal file

File diff suppressed because it is too large Load Diff

6
src/data/kulle_0_png.hpp Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#include <cstddef>
extern const unsigned char kulle_0_png[];
extern const size_t kulle_0_png_length;

3976
src/data/kulle_1_png.cpp Normal file

File diff suppressed because it is too large Load Diff

6
src/data/kulle_1_png.hpp Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#include <cstddef>
extern const unsigned char kulle_1_png[];
extern const size_t kulle_1_png_length;

4123
src/data/kulle_2_png.cpp Normal file

File diff suppressed because it is too large Load Diff

6
src/data/kulle_2_png.hpp Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#include <cstddef>
extern const unsigned char kulle_2_png[];
extern const size_t kulle_2_png_length;

4166
src/data/kulle_3_png.cpp Normal file

File diff suppressed because it is too large Load Diff

6
src/data/kulle_3_png.hpp Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#include <cstddef>
extern const unsigned char kulle_3_png[];
extern const size_t kulle_3_png_length;

4192
src/data/kulle_4_png.cpp Normal file

File diff suppressed because it is too large Load Diff

6
src/data/kulle_4_png.hpp Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#include <cstddef>
extern const unsigned char kulle_4_png[];
extern const size_t kulle_4_png_length;

4219
src/data/kulle_5_png.cpp Normal file

File diff suppressed because it is too large Load Diff

6
src/data/kulle_5_png.hpp Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#include <cstddef>
extern const unsigned char kulle_5_png[];
extern const size_t kulle_5_png_length;

4260
src/data/kulle_6_png.cpp Normal file

File diff suppressed because it is too large Load Diff

6
src/data/kulle_6_png.hpp Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#include <cstddef>
extern const unsigned char kulle_6_png[];
extern const size_t kulle_6_png_length;

4298
src/data/kulle_7_png.cpp Normal file

File diff suppressed because it is too large Load Diff

6
src/data/kulle_7_png.hpp Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#include <cstddef>
extern const unsigned char kulle_7_png[];
extern const size_t kulle_7_png_length;

31
src/default_font.cpp Normal file
View File

@ -0,0 +1,31 @@
#include "default_font.hpp"
#ifdef __linux__
#include <filesystem>
constexpr const char *getLinuxFilePath() {
const char *fonts[] = {"/usr/share/fonts/truetype/DejaVuSans-Bold.ttf", // openSUSE
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", // Debian
"/usr/share/fonts/TTF/DejaVuSans-Bold.ttf", // Arch
"/usr/share/fonts/dejavu-sans-fonts/DejaVuSans-Bold.ttf", // Fedora
};
for (const char *font: fonts)
if (std::filesystem::exists(font))
return font;
return nullptr;
}
#endif
const char *getDefaultFontPath() {
#if defined(_WIN32) || defined(_WIN64)
return R"(C:\Windows\Fonts\Arial.ttf)";
#elif defined(__linux__)
return getLinuxFilePath();
#elif defined(__APPLE__) || defined(__MACH__)
return "/System/Library/Fonts/Supplemental/Arial.ttf";
#else
return nullptr;
#endif
}

3
src/default_font.hpp Normal file
View File

@ -0,0 +1,3 @@
#pragma once
const char *getDefaultFontPath();

View File

@ -1,6 +1,9 @@
#include <iostream>
#define SDL_MAIN_HANDLED
#include <SDL.h>
#include "Game.hpp"
int main() {
int SDL_main(int argc, char *argv[]) {
Game::Run();
return 0;
}