Programming Fundamentals
A first-year C++ module in two parts: ten coding challenges of rising difficulty, then a console horror RPG that was scrapped and rebuilt as an endless dungeon.
- Type
- University Assignment
- Module
- GDEV40024
- Year
- Oct–Dec 2024
- Team
- Solo
- Campus
- Stoke
- Level
- Level 4 (Year 1)
Two Assignments, One Rollercoaster
GDEV40024 Programming Fundamentals was completed across two assignments. Assignment 1 required ten C++ coding challenges covering core language concepts: ASCII art output, user I/O, a multi-function calculator, text box generation, text casing transformations, a number guessing game, party selection with a shop system, a dynamic inventory manager, a Vector2 math class, and a 16-bit bitwise controller input manipulator.
Assignment 2 required a complete C++ console game. The original concept — a narrative horror RPG titled The Forbidden Hell, inspired by Blair Witch Project, FINAL FANTASY XIII, Silent Hill Homecoming, Slender: The Arrival, Resident Evil 3: Nemesis, and The Evil Within — was scrapped four weeks before the deadline due to over-ambition and time constraints. The battle system alone had grown to 2,300 lines of unfinished code out of approximately 9,000 total. The game was redesigned as an endless dungeon: infinite floors of randomised enemies with dynamically increasing difficulty, a full turn-based battle system, player stats and roles, Windows API integrations, and a console UI library for the main menu.
The thread described the challenges as "a rollercoaster ride — they start nice and slow but become terrifyingly and quickly difficult to manage without trying to research more about C++ using 100+ Google Chrome tabs."
All 10 Challenges
Ten challenges increasing in complexity — from declarative ASCII output to a full bitwise controller manipulator. Each one introduced new C++ concepts and was later refactored for consistent code style.
-
Challenge 1
ASCII Boat
Print an ASCII boat in the console precisely as the brief outlined. The immediate obstacle: C++ treats
\as an escape character, breaking ASCII art strings entirely. The fix was raw string literals (R"(...)"), which allow multi-line strings without escape sequences or repeatedstd::coutcalls. No variables required — purely declarative output. -
Challenge 2
Player Details
Prompt user for name, in-game username, clan tag, and experience — then print them back. Considered the easiest challenge. Notable firsts: a string array for multiple values, an unsigned integer for experience (never negative), and first use of
Windows.hto clear the console. -
Challenge 3
Calculator
A multi-operation calculator: square root, floor, ceiling, rounding, negation, cubed, and custom error codes. Slightly tricky due to rounding to a specific decimal place matching the brief's example output. Required researching
cmathandiomanipheaders. Implementing custom error codes in C++ for the first time. -
Challenge 4
Text Boxes
Generate ASCII text boxes around user input — each character in its own individual box. Validation required no special characters or numbers. Used
isalpha()andisspace()fromctype.h. Concept worked correctly on first attempt — minor tweaks for accuracy. Refactored out ofmain()into boolean helper functions. -
Challenge 5
Text Casing
Four transformations: lower case, upper case, sentence case, alternating/sarcastic case. First three completed quickly. Sentence case was deeply problematic — two to three consecutive broken implementations before the bug was traced to using
.Size()on a string instead of correct index-based iteration. Fixed after returning to the problem with fresh perspective after illness.Bugfor (int i = 0; i < inputString.Size(); i++)—.Size()is not the correct method for iterating string characters in C++. Failure to plan before writing led to three consecutive broken implementations. -
Challenge 6
Number Guessing Game
Generate a random number, prompt the user to guess, calculate the difference, apply error handling for values outside 0–100. Described as "pretty simple" but the brief's use of the word "furthermore" kept revealing additional requirements — described in the thread as "gaslighting." Required careful attention to comparative operators in nested conditionals.
-
Challenge 7
Party Selection
A party of three members and a shop where each member buys a weapon that determines their role. Boolean array to track purchases. A bug appeared post-submission: on shop reset, the second member was queried first instead of iterating from the start. Hours of debugging led nowhere — the code was scrapped and reimplemented using a
Shopclass with an ID field, resolving the ordering bug cleanly.BugAfter shop reset, party member iteration started from the second member. Root cause: poor structural coupling between shop state and party member identity. Fix:Shopclass with ID-basedresetShop(id)function. -
Challenge 8
Dynamic Inventory
Full dynamic inventory supporting: assign slots, add items, remove items, view inventory, view a specific slot, search, view assignable items, restart, help prompt, clear, and exit. First implementation used vectors, two arrays, and a list. Fully rewritten using classes, structs, and
unordered_mapSTL. Each item became a struct with ID and name. Search function made case-insensitive. Final code was described as "presentable and neat." -
Challenge 9
Vector2 Class
A C++ class storing X/Y float coordinates with operator overloads, copy constructor, copy-assignment, and static/instance methods: Dot product, Magnitude, Normalize, Normalized, Distance. Also evaluated whether one vector was within another's field-of-view cone. Described as "overwhelming" — simultaneously learning pointers, class construction, operator overloading, and header declarations.
Reflection"The amount of code required was less than expected — the challenge was psychologically overwhelming but technically achievable once broken down." Cognitive overload is a genuine barrier to retention. -
Challenge 10
Bitwise Controller Input
The most demanding challenge. Manipulate a 16-bit bitfield (
uint16_t) representing controller input for up to 4 players. Lower 12 bits encode button states (DPad, face buttons, shoulder/trigger); upper 4 bits store player index. Fourtypedef structs instructure.h. Functions included:SetBitAtPosition,SetData,SetPlayers,GetPlayers,GetData,TransformInputByPlayer(D-pad rotated per player), and bitfield conversion utilities.On Challenge 10"One of the toughest yet most annoying challenges." Extended focus caused common English words to look wrong — a Stroop-effect-like cognitive fatigue. Unlike Challenge 9, no satisfaction or fun factor — purely a headache.
Code Rewrite
After completing all ten challenges, all code was rewritten for consistent naming conventions and readability. The changes were lost once and had to be completed a second time. Three major systematic changes applied across all challenges:
- Removed
using namespace std;— identified as bad practice. When multiple namespaces are in use, functions can silently collide withstdequivalents. Explicitstd::prefixing applied throughout. - Introduced
while(true)loops — continuously accepting user input without requiring the application to restart between tests, saving significant debugging and recompilation time. - Fragmented
main()— split monolithic main functions into appropriately named sub-functions for readability, maintainability, and isolation of bugs.
Final naming convention pass: camelCase for variables and functions, PascalCase for classes and structs,
SNAKE_CASE for #define and constant definitions.
The Forbidden Hell → Endless Dungeon
Original Concept: The Forbidden Hell
The original game concept was a narrative horror RPG titled The Forbidden Hell. Genre: Action, Adventure, Horror, Sci-Fi, Fantasy. Inspirations: Blair Witch Project, FINAL FANTASY XIII, Silent Hill Homecoming, Slender: The Arrival, Resident Evil 3: Nemesis, and The Evil Within. Planned mechanics included turn-based combat, player roles, an RPG levelling system, narrative story, varied randomised enemies, puzzles, player inventory/skills/abilities, save and load, RNG-based decision making, and BGM/SFX.
The plot: the player is knocked unconscious and wakes in a rural, isolated forest known as "The Forbidden Hell" — a location notorious for
unexplained kidnappings and consistent murders. The player discovers they can cast healing magic when nursing a leg injury. The player's name was
dynamically inserted into the narration via game_introduction().
Endless Dungeon — Development
The redesigned game retained the battle system architecture but scrapped the narrative. Key systems built or extended:
Story / Introduction:
External Functions:
clear_console() extended with loading screen message parameters. Float variant of randomise_number() added.Windows API:
sleep_game(int sleep_time) with customisable duration. disable_console_resize() — thread implementation caused OS hang
before process termination; resolved by using MessageBoxA() to warn the user. change_console_title() added.
WIN32_LEAN_AND_MEAN defined for additional libraries.Player:
is_dead(), is_poisoned(), is_cursed(), is_player_turn(), assign_abilities(),
output_roles(), switch_roles().Enemies:
Battle System
The centrepiece of Assignment 2. Key functions: Battle_Setup() — configures enemy stats and assigns the player's role;
Battle_Start(); Battle_End(); Battle_Cleanup() — deletes pointers and resets all variables;
Game_Over(). Player logic: Battle_Player_Turn(), Battle_Player_Attack(),
Battle_Player_Inflict_Bleed(). Ailment boolean functions for both player and enemy perform specific actions per active ailment —
poison, curse, bleed, etc. Damage calculations factor in weakness, resistance, and immunity. The system uses inheritance.
Named Bugs — Battle System
| Bug | What happened |
|---|---|
| Trillion-HP Enemy: | Enemy HP multiplied by approximately 2 trillion when the player changed roles — game-breaking and critical. |
| Wrong Role Assignment: | Incorrect role assigned to the player under certain conditions. |
| Wrong Battle Log: | Damage log displayed when the player cast the Regenerate buff. |
| No Log on Self-Cure: | No battle log printed when the player chose to cure themselves. |
| HP Exceeding Maximum: | Player HP exceeded max HP after Regenerate was applied. |
| Negative Damage: | Negative damage values not clamped — the enemy could effectively heal the player unintentionally. |
| Protection Duration Not Tracked: | The Protection buff duration was not decremented each turn. |
Final Build — December 9, 2024
Acknowledged getting "carried away" with original plans. The final build was disappointing — unable to implement everything intended. Code was written unnecessarily sophisticatedly, causing mental burnout. Boss BGM sourced from FINAL FANTASY XIII-2; voiceovers from South Park (both credited). Thread archived December 9, 2024.
Foundational C++ Explorations
Tutorial 1 — Basic Output
Task 1: The \t escape sequence inserts a tab space; multiple \t characters insert multiple tabs. Task 2:
5+5 written directly within a cout statement performs the calculation dynamically without pre-assigning a variable — the
result is printed directly.
Tutorial 2 — Arithmetic
Confirmed that arithmetic expressions within cout statements are evaluated at runtime. Task 2 was screenshot-based with no additional
written content captured.
Tutorial 3 — Conditions Part 1
Covered conditional/relational operators and how they use booleans under the hood. Task 1 involved five explicit comparisons with predictions confirmed before running:
| Expression | Result |
|---|---|
(5 < 1) | → 0 / false |
(5 > 1) | → 1 / true |
(5 == 1) | → 0 / false |
(90 != 90) | → 0 / false |
(-5*2)==(5*2) | → 0 / false (−10 ≠ 10) |
Task 2 built progressively: a pass/fail grade calculator expanded with 2:2, 2:1, and 1st class thresholds; a name-equality check for "Bob";
ASCII-value string comparison ('Bob' > 'Car' is false because b = 98 < c = 99); and relational operator examples
with int player_ammo, const int MAX_AMMO, and bool isPlayerOutOfAmmo.
Key Lessons
Naming Conventions
Inconsistent naming was a recurring problem across all challenges — fluctuating between PascalCase, camelCase, snake_case, and kebab-case
within the same codebase. The final naming convention target: camelCase for variables and functions, PascalCase for
classes and structs, SNAKE_CASE for #define and constant definitions.
Namespace Hygiene
Removing using namespace std; improves readability and prevents namespace collisions. If multiple namespaces are in use, functions
can silently conflict with std equivalents. Explicit std:: prefixing makes the origin of every function call
unambiguous.
Cognitive Overload and Retention
Challenge 9 and Challenge 10 both demonstrated that cognitive overload is a real barrier to knowledge retention. Challenge 9's scope was psychologically overwhelming despite being technically achievable once broken down. Challenge 10 induced a Stroop-effect-like fatigue where common English words began to look wrong after hours of focus on bitwise logic. Concepts learned under this kind of overload risk being lost immediately after the task ends.
Over-Functioning
A pattern of "over-functioning" — breaking every small block of logic into its own function — created branching trees of hundreds of unnecessary subfunctions where a single function would have sufficed. This was identified in the final challenge review and corrected. Functions should be extracted only when genuinely warranted: for reuse, readability, or isolation of complexity.
Over-Ambition
Assignment 2's original game concept was too ambitious given the time available and the level of C++ experience at the time. The same pattern had occurred the prior year. The redesign to an endless dungeon was necessary but left the final build feeling incomplete. Writing unnecessarily sophisticated code under time pressure causes mental burnout and produces worse output than simpler, more pragmatic architecture would have.
Iterative Rewrites
Implementing suboptimal solutions first and returning to rewrite them slowed overall progress and introduced new bugs — but ultimately refined programming skills through the revision process. Significant confidence was gained in C++ by the end of the module, particularly around structs, classes, namespaces, and header files.
using namespace std; — always prefix with std:: explicitly.