thecodingidiot.com

Who Wants to Be a Game Developer?The Display

The Display

tci_printf is functionally identical to printf — the output is the same. The difference is that it writes to a file descriptor directly, without the standard I/O library.

This page uses it exclusively: the prize ladder, the highlighted current level, the question text, the option letters, the audience bar chart, the win screen — all of it goes through tci_printf. Not because printf would fail, but because this is what we built.

This page implements the three display functions and the three exit screens.


ANSI escape codes[1]

The terminal interprets sequences starting with \033[ as formatting instructions rather than printable text. \033 is the escape character (ASCII 27); the [ that follows opens the sequence. The terminal acts on it silently — the sequences themselves never appear on screen.

Three sequences are used in this game:

SequenceEffect
\033[33mForeground yellow
\033[32mForeground green
\033[0mReset all formatting

A string wrapped between \033[33m and \033[0m appears yellow in the terminal. Everything after \033[0m returns to the default colour.


display_ladder

The ladder renders from level 15 at the top to level 1 at the bottom. The current level is highlighted in yellow. Safe levels get a * prefix in green:

void    display_ladder(int level, int safe_level)
{
    int  i;
 
    tci_printf("\n");
    for (i = LEVELS - 1; i >= 0; i--) {
        if (i == level)
            tci_printf("\033[33m");
        if (SAFE[i])
            tci_printf("\033[32m  *\033[0m");
        else
            tci_printf("   ");
        if (i == safe_level && i != level)  /* yellow takes priority when both match */
            tci_printf("\033[32m");
        tci_printf(" %2d: %s", i + 1, PRIZES[i]);  /* i + 1: PRIZES is 0-indexed, display is not */
        if (i == level || (i == safe_level && i != level))
            tci_printf("\033[0m");
        tci_printf("\n");
    }
    tci_printf("\n");
}

The colour is opened before the row content and reset after, so each row is self-contained. When safe_level == -1, the condition i == safe_level is never true — no valid level index is -1 — so no green tint is applied and the argument needs no special handling.


display_question

The question block shows the question text, then each option letter and string. Options eliminated by the 50:50 lifeline are skipped:

void    display_question(question_t *q, int hidden[4])
{
    int         i;
    const char  letters[] = "ABCD";    /* indexed by i to produce the option letter */
 
    tci_printf("%s\n\n", q->text);
    for (i = 0; i < 4; i++) {
        if (!hidden[i])
            tci_printf("  %c. %s\n", letters[i], q->opts[i]);
    }
    tci_printf("\n");
}

letters[0] is 'A', letters[1] is 'B', and so on — a string literal used as a lookup table. The same technique appears in display_audience below with "ABCD"[i].

hidden[i] = 1 means option i is not displayed. The correct answer is never hidden; handle_lifeline in the next page ensures this.


display_audience

The audience lifeline shows a fake percentage bar chart weighted toward the correct answer. The percentages are generated with rand() and scaled to sum close to 100:

void    display_audience(question_t *q)
{
    int  pcts[4];
    int  total;
    int  scaled;
    int  i;
    int  j;
 
    for (i = 0; i < 4; i++)
        pcts[i] = 2 + rand() % 8;              /* 2–9 raw points for wrong answers */
    pcts[q->answer] = 58 + rand() % 16;        /* 58–73 raw points for the correct answer */
    total = 0;
    for (i = 0; i < 4; i++)
        total += pcts[i];
    tci_printf("\nAsk the Audience:\n\n");
    for (i = 0; i < 4; i++) {
        scaled = (pcts[i] * 100) / total;      /* normalise raw score to percentage */
        tci_printf("  %c: ", "ABCD"[i]);
        for (j = 0; j < scaled / 3; j++)       /* one '#' per 3 percentage points */
            tci_printf("#");
        tci_printf(" %d%%\n", scaled);          /* %% prints a literal % */
    }
    tci_printf("\n");
}

The raw scores do not need to sum to 100 — the scaling step handles that. Each raw score is divided by the total and multiplied by 100 to produce the displayed percentage.

Integer division means the displayed values will not always sum to exactly 100. That is acceptable for fake audience data.


Exit screens

Three outcomes end the game: a win, a loss, and a walk away. Each gets a dedicated function.

display_win uses green to mark the top prize:

void    display_win(void)
{
    tci_printf("\n\033[32m");
    tci_printf("  Congratulations! You have won £1,000,000!\n");
    tci_printf("\033[0m\n");
}

display_loss shows what the player leaves with — the banked safe level amount, or nothing:

void    display_loss(int safe_level)
{
    tci_printf("\nWrong answer.\n");
    if (safe_level >= 0)
        tci_printf("You leave with %s.\n\n", PRIZES[safe_level]);
    else
        tci_printf("You leave with £0.\n\n");
}

display_walkaway confirms the banked prize. The player walks before answering the current level, so the banked amount is the prize from the previous level — PRIZES[level - 1]:

void    display_walkaway(int level)
{
    tci_printf("\nYou walk away with %s.\n\n",
               level > 0 ? PRIZES[level - 1] : "£0");  /* level not yet answered */
}

level > 0 guards the edge case where the player walks before answering question 1. At that point level is 0 and PRIZES[-1] does not exist, so the result is "£0".


Test the display

Add a temporary test to main.c after loading questions to verify the ladder and question render correctly:

    int  hidden[4] = {0, 0, 0, 0};
 
    display_ladder(0, -1);
    display_question(questions[0], hidden);
    free_questions(questions, count);
    return (0);

Run with a two-question questions.txt:

make re
./game questions.txt

The terminal should show the prize ladder with level 1 highlighted in yellow, safe levels marked with a green *, and the first question with all four options visible.

Once the output looks right, remove the test code and restore the stub. The display functions are complete.

Footnotes

  1. ANSI escape code - Wikipedia