<commit_before>/**
 * Pong
 *
 * The classic game
 */

#include "pong.h"
#include "assets.h"
#include "config.h"
#include "paddles.h"

#include <SDL.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

#define DEFAULT_BUF_SIZE 16
#define FONT_SIZE 16
#define KEYMAP_MAX SDL_SCANCODE_SLEEP

#define BALL_SPEED 1
#define BALL_DEFAULT_DIR 0 //up and left
#define BALL_DIR_DOWN_MASK 0x1
#define BALL_DIR_RIGHT_MASK 0x2
#define BALL_DIR_DOWN(D) (D & BALL_DIR_DOWN_MASK)
#define BALL_DIR_RIGHT(D) (D & BALL_DIR_RIGHT_MASK)

#define BALL_WALL_BUFFER (WALL_THICKNESS + BALL_SIZE / 2)

#define BALL_INSIDE_PADDLE(P, B) ((B.x > P.x - ))

typedef struct {
    SDL_Renderer *renderer;
    SDL_Texture *font;
    SDL_Texture *sprites;
    int player1Score;
    int player2Score;
    SDL_Rect player1;
    SDL_Rect player2;
    SDL_Point ball;
    int ballDir;
} Pong;

/**
 * Src position for the ball in the sprite sheet
 */
const SDL_Rect ballSrc = {
    .x = 0,
    .y = 0,
    .w = 32,
    .h = 32
};

/**
 * Keymap for keypresses
 */
static uint8_t keymap[KEYMAP_MAX];

/**
 * Handles events from SDL
 * @return 0 if the event loop should stop
 */
static int handle_events()
{
    SDL_Event e;
    SDL_KeyboardEvent *ke;
    while (SDL_PollEvent(&e))
    {
        if (e.type == SDL_QUIT)
        {
            return 0;
        }
        else if (e.type == SDL_KEYDOWN)
        {
            ke = (SDL_KeyboardEvent*)(&e);
            if (ke->keysym.scancode > 0xFF)
                continue;

            keymap[ke->keysym.scancode] = 1;
        }
        else if (e.type == SDL_KEYUP)
        {
            ke = (SDL_KeyboardEvent*)(&e);
            if (ke->keysym.scancode > 0xFF)
                continue;

            keymap[ke->keysym.scancode] = 0;
        }
    }

    return 1;
}

/**
 * Renders a string
 * @param game Game to use for rendering
 * @param str  String to render
 * @param x    X position of the string
 * @param y    Y position of the string
 */
static void draw_string(Pong *game, const char* str, int x, int y)
{
    int i;
    int len = strlen(str);
    SDL_Rect src, dest;

    src.w = FONT_SIZE;
    src.h = FONT_SIZE;

    dest.y = y;
    dest.w = src.w; //no scaling
    dest.h = src.h; //no scaling
    for (i = 0; i < len; i++)
    {
        //determine src based on the current char (it is a 16x16 grid of chars)
        src.x = (str[i] & 0x0F) * FONT_SIZE;
        src.y = ((str[i] & 0xF0) >> 4) * FONT_SIZE;

        //generate dest based on i
        dest.x = x + i * FONT_SIZE;

        SDL_RenderCopy(game->renderer, game->font, &src, &dest);
    }
}

static void pong_tick(Pong *game)
{
    //move the paddles
    paddle_left_tick(keymap, &game->player1);
    paddle_right_tick(keymap, &game->player2);

    //move the ball
    SDL_Point r = {
        .x = BALL_SPEED * (BALL_DIR_RIGHT(game->ballDir) ? 1 : -1),
        .y = BALL_SPEED * (BALL_DIR_DOWN(game->ballDir) ? 1 : -1)
    };

    //perform ball collision testing
    if (game->ball.y <= BALL_WALL_BUFFER || game->ball.y >= (WINDOW_HEIGHT - BALL_WALL_BUFFER))
    {
        //flip our y direction
        game->ballDir ^= BALL_DIR_DOWN_MASK;
        r.y *= -1;
    }
    if (!BALL_DIR_RIGHT(game->ballDir) &&
        (game->ball.x - BALL_SIZE / 2) > game->player1.x && (game->ball.x + r.x - BALL_SIZE / 2) <= game->player1.x &&
        game->ball.y > game->player1.y && game->ball.y < (game->player1.y + game->player1.h))
    {
        //flip our x direction
        game->ballDir ^= BALL_DIR_RIGHT_MASK;
        r.x *= -1;
    }
    else if (BALL_DIR_RIGHT(game->ballDir) &&
        (game->ball.x + BALL_SIZE / 2) < game->player2.x && (game->ball.x + r.x + BALL_SIZE / 2) >= game->player2.x &&
        game->ball.y > game->player2.y && game->ball.y <= (game->player2.y + game->player2.h))
    {
        game->ballDir ^= BALL_DIR_RIGHT_MASK;
        r.x *= -1;
    }

    //perform ball scoring
    if (game->ball.x < 0)
    {
        game->player2Score++;
        game->ball.x = WINDOW_WIDTH / 2;
        game->ball.y = WINDOW_HEIGHT / 2;
    }
    else if (game->ball.x > WINDOW_WIDTH)
    {
        game->player1Score++;
        game->ball.x = WINDOW_WIDTH / 2;
        game->ball.y = WINDOW_HEIGHT / 2;
    }

    //move the ball
    game->ball.x += r.x;
    game->ball.y += r.y;
}

static void pong_render(Pong *game)
{
    SDL_Rect rect, src, dest;
    char buf[DEFAULT_BUF_SIZE];

    //clear the target
    SDL_SetRenderDrawColor(game->renderer, 0x00, 0x00, 0x00, SDL_ALPHA_OPAQUE);
    SDL_RenderClear(game->renderer);

    //render the scores
    snprintf(buf, DEFAULT_BUF_SIZE, "%d", game->player1Score);
    draw_string(game, buf, (WINDOW_WIDTH / 2) - 128, 64);
    snprintf(buf, DEFAULT_BUF_SIZE, "%d", game->player2Score);
    draw_string(game, buf, (WINDOW_WIDTH / 2) + 128, 64);

    //render the ball
    src = ballSrc;
    dest.x = game->ball.x - BALL_SIZE / 2;
    dest.y = game->ball.y - BALL_SIZE / 2;
    dest.w = BALL_SIZE;
    dest.h = BALL_SIZE;
    SDL_RenderCopy(game->renderer, game->sprites, &src, &dest);
<commit_msg>Fixed font rendering for scores to be symmetrical<commit_after>/**
 * Pong
 *
 * The classic game
 */

#include "pong.h"
#include "assets.h"
#include "config.h"
#include "paddles.h"

#include <SDL.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

#define DEFAULT_BUF_SIZE 16
#define FONT_SIZE 16
#define KEYMAP_MAX SDL_SCANCODE_SLEEP

#define BALL_SPEED 1
#define BALL_DEFAULT_DIR 0 //up and left
#define BALL_DIR_DOWN_MASK 0x1
#define BALL_DIR_RIGHT_MASK 0x2
#define BALL_DIR_DOWN(D) (D & BALL_DIR_DOWN_MASK)
#define BALL_DIR_RIGHT(D) (D & BALL_DIR_RIGHT_MASK)

#define BALL_WALL_BUFFER (WALL_THICKNESS + BALL_SIZE / 2)

#define BALL_INSIDE_PADDLE(P, B) ((B.x > P.x - ))

typedef struct {
    SDL_Renderer *renderer;
    SDL_Texture *font;
    SDL_Texture *sprites;
    int player1Score;
    int player2Score;
    SDL_Rect player1;
    SDL_Rect player2;
    SDL_Point ball;
    int ballDir;
} Pong;

/**
 * Src position for the ball in the sprite sheet
 */
const SDL_Rect ballSrc = {
    .x = 0,
    .y = 0,
    .w = 32,
    .h = 32
};

/**
 * Keymap for keypresses
 */
static uint8_t keymap[KEYMAP_MAX];

/**
 * Handles events from SDL
 * @return 0 if the event loop should stop
 */
static int handle_events()
{
    SDL_Event e;
    SDL_KeyboardEvent *ke;
    while (SDL_PollEvent(&e))
    {
        if (e.type == SDL_QUIT)
        {
            return 0;
        }
        else if (e.type == SDL_KEYDOWN)
        {
            ke = (SDL_KeyboardEvent*)(&e);
            if (ke->keysym.scancode > 0xFF)
                continue;

            keymap[ke->keysym.scancode] = 1;
        }
        else if (e.type == SDL_KEYUP)
        {
            ke = (SDL_KeyboardEvent*)(&e);
            if (ke->keysym.scancode > 0xFF)
                continue;

            keymap[ke->keysym.scancode] = 0;
        }
    }

    return 1;
}

/**
 * Renders a string
 * @param game Game to use for rendering
 * @param str  String to render
 * @param x    X position of the string
 * @param y    Y position of the string
 */
static void draw_string(Pong *game, const char* str, int x, int y)
{
    int i;
    int len = strlen(str);
    SDL_Rect src, dest;

    src.w = FONT_SIZE;
    src.h = FONT_SIZE;

    dest.y = y;
    dest.w = src.w; //no scaling
    dest.h = src.h; //no scaling
    for (i = 0; i < len; i++)
    {
        //determine src based on the current char (it is a 16x16 grid of chars)
        src.x = (str[i] & 0x0F) * FONT_SIZE;
        src.y = ((str[i] & 0xF0) >> 4) * FONT_SIZE;

        //generate dest based on i
        dest.x = x + i * FONT_SIZE;

        SDL_RenderCopy(game->renderer, game->font, &src, &dest);
    }
}

static void pong_tick(Pong *game)
{
    //move the paddles
    paddle_left_tick(keymap, &game->player1);
    paddle_right_tick(keymap, &game->player2);

    //move the ball
    SDL_Point r = {
        .x = BALL_SPEED * (BALL_DIR_RIGHT(game->ballDir) ? 1 : -1),
        .y = BALL_SPEED * (BALL_DIR_DOWN(game->ballDir) ? 1 : -1)
    };

    //perform ball collision testing
    if (game->ball.y <= BALL_WALL_BUFFER || game->ball.y >= (WINDOW_HEIGHT - BALL_WALL_BUFFER))
    {
        //flip our y direction
        game->ballDir ^= BALL_DIR_DOWN_MASK;
        r.y *= -1;
    }
    if (!BALL_DIR_RIGHT(game->ballDir) &&
        (game->ball.x - BALL_SIZE / 2) > game->player1.x && (game->ball.x + r.x - BALL_SIZE / 2) <= game->player1.x &&
        game->ball.y > game->player1.y && game->ball.y < (game->player1.y + game->player1.h))
    {
        //flip our x direction
        game->ballDir ^= BALL_DIR_RIGHT_MASK;
        r.x *= -1;
    }
    else if (BALL_DIR_RIGHT(game->ballDir) &&
        (game->ball.x + BALL_SIZE / 2) < game->player2.x && (game->ball.x + r.x + BALL_SIZE / 2) >= game->player2.x &&
        game->ball.y > game->player2.y && game->ball.y <= (game->player2.y + game->player2.h))
    {
        game->ballDir ^= BALL_DIR_RIGHT_MASK;
        r.x *= -1;
    }

    //perform ball scoring
    if (game->ball.x < 0)
    {
        game->player2Score++;
        game->ball.x = WINDOW_WIDTH / 2;
        game->ball.y = WINDOW_HEIGHT / 2;
    }
    else if (game->ball.x > WINDOW_WIDTH)
    {
        game->player1Score++;
        game->ball.x = WINDOW_WIDTH / 2;
        game->ball.y = WINDOW_HEIGHT / 2;
    }

    //move the ball
    game->ball.x += r.x;
    game->ball.y += r.y;
}

static void pong_render(Pong *game)
{
    SDL_Rect rect, src, dest;
    char buf[DEFAULT_BUF_SIZE];
    int len;

    //clear the target
    SDL_SetRenderDrawColor(game->renderer, 0x00, 0x00, 0x00, SDL_ALPHA_OPAQUE);
    SDL_RenderClear(game->renderer);

    //render the scores
    snprintf(buf, DEFAULT_BUF_SIZE, "%d", game->player1Score);
    len = strlen(buf);
    draw_string(game, buf, (WINDOW_WIDTH / 2) - 128 - len * FONT_SIZE, 64);
    snprintf(buf, DEFAULT_BUF_SIZE, "%d", game->player2Score);
    draw_string(game, buf, (WINDOW_WIDTH / 2) + 128, 64);

    //render the ball
    src = ballSrc;
    dest.x = game->ball.x - BALL_SIZE / 2;
    dest.y = game->ball.y - BALL_SIZE / 2;
    dest.w = BALL_SIZE;
    dest.h = BALL_SIZE;
    SDL_RenderCopy(game->renderer, game->sprites, &src, &dest);

{'fraction_non_alphanumeric': 0.14360031409501375, 'fraction_numerical': 0.01845308205732234, 'mean_word_length': 2.2698973042362, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 139, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7335154', 'n_tokens_mistral': 4079, 'n_tokens_neox': 3877, 'n_words': 911}