- βΒ Previous
- Building Your First Ada Library
- NextΒ β
- Concurrent Input Handling
Get Latest Code
π Beginning of Lesson 3 β Two Options
Each lesson starts with a new machine, you need to pull the latest code first, then either resume your own progress or start from the official snapshot.
Clone your fork (replace <YOUR_GITHUB_USERNAME>):
git clone https://github.com/<YOUR_GITHUB_USERNAME>/snake-tutorial.git
cd ~/sandbox/snake-tutorial
π °οΈ Option A β Resume from Your Fork (Recommended)
Check out your saved progress to a branch:
git checkout -b lesson-03-work origin/lesson-02-work
β You're now ready to start Lesson 3 from your own progress.
π ±οΈ Option B β Start from Official Course Snapshot
Check out and push to your origin the starting point for Lesson 3 :
git remote add upstream https://github.com/GNAT-Academic-Program/snake-tutorial.git
git fetch upstream
git checkout -b lesson-03-work upstream/lesson-03-start
git push -u origin lesson-03-work
β You're now starting Lesson 3 from the clean official reference code.
Add the Loop
Let's create a game loop! This will handle our different gameplay states and keep the game running.
- Edit
snake_game.adbto add a loop around the existing code - Add loop structure around the
Noki.Logcall:loop Noki.Log ("Welcome to my Snake Game!"); end loop; - Add a delay to slow down the loop so we can see the output:
- On the line after
Noki.Log ("Welcome to my Snake Game!")add:
delay 1.0; - On the line after
Your complete code inside the Snake_Game procedure should look like this:
loop
Noki.Log ("Welcome to my Snake Game!");
delay 1.0;
end loop;
π Code Review - Complete snake_game.adb
Your complete file should look like this:
with Noki;
procedure Snake_Game is
begin
loop
Noki.Log ("Welcome to my Snake Game!");
delay 1.0;
end loop;
end Snake_Game;
Build and run:
cd ~/sandbox/snake-tutorial/noki/snake_game
alr build
bin/snake_game
β If something goes wrong: If you don't see Build finished successfully in ..., re-check the instructions carefully and start again from step 1.
β
Expected result: Welcome to my Snake Game! appearing every second over and over.
π€― Heads Up! This program will run forever! Use Ctrl+C in the terminal to stop it.
Create a Custom Game State Type
Let's create our first user-defined Ada type! We'll use an enumeration to manage different game states.
- Add the type definition to the declarative part of the Snake_Game procedure:
- After
procedure Snake_Game isand beforebegin, add:
type Game_State_T is (Welcome, Play, Game_Over, Undefined); Game_State : Game_State_T := Welcome; - After
- Understanding the syntax:
- First line creates a new enumeration type
Game_State_Twith four possible values - Second line declares a variable
Game_Stateof typeGame_State_T, initialized toWelcome - Ada syntax:
variable_name : variable_type := initial_value
- First line creates a new enumeration type
- Replace the simple log with state handling:
- Remove the
Noki.Log ("Welcome to my Snake Game!");line - Add a case statement between
loopandend loop:
case Game_State is when Welcome => Noki.Log ("Welcome to Snakotron!"); Game_State := Play; when Play => Noki.Log ("We are playing."); Game_State := Game_Over; when Game_Over => Noki.Log ("Game Over!"); Game_State := Undefined; when others => Noki.Log ("Press Ctrl+C to abort program!"); end case; - Remove the
π Code Review - Complete snake_game.adb
Your complete snake_game.adb should look exactly like this:
with Noki;
procedure Snake_Game is
type Game_State_T is (Welcome, Play, Game_Over, Undefined);
Game_State : Game_State_T := Welcome;
begin
loop
case Game_State is
when Welcome =>
Noki.Log ("Welcome to Snakotron!");
Game_State := Play;
when Play =>
Noki.Log ("We are playing.");
Game_State := Game_Over;
when Game_Over =>
Noki.Log ("Game Over!");
Game_State := Undefined;
when others =>
Noki.Log ("Press Ctrl+C to abort program!");
end case;
delay 1.0;
end loop;
end Snake_Game;
Build and run:
alr build
bin/snake_game
β If something goes wrong: Check that your case statement syntax matches exactly, including the when clauses and semicolons.
β Expected result:
Build finished successfully in ... seconds.
Welcome to Snakotron!
We are playing.
Game Over!
Press Ctrl+C to abort program!
Press Ctrl+C to abort program!
...
π€― Heads Up! This program will run forever! Use Ctrl+C in the terminal to stop it.
Control the Game Rendering Using ANSI Escape Codes
Let's control our terminal rendering! Right now our output just appends to the terminal. For a proper game, we need to update what's displayed instead.
Quick ANSI background: ESC (ASCII 27, hex 0x1B) + [ = Control Sequence Introducer (CSI). This tells the terminal "what follows is a command, not text to print."
- Create a reusable CSI constant in
noki.ads:- Before the
procedure Log (S : String);line, add:
CSI : constant String := Character'Val (16#1B#) & '['; - Before the
- Add a screen clearing function right after the CSI line:
function Clear_Screen return String is (CSI & "2J" & CSI & "H");
This builds the ANSI command: clear screen (2J) + move cursor to home (H). - Use it in our game loop by opening
snake_game.adband adding this right afterloop:Noki.Log (Noki.Clear_Screen);
π Code Review - Complete snake_game.adb
Your complete snake_game.adb should look like this:
with Noki;
procedure Snake_Game is
type Game_State_T is (Welcome, Play, Game_Over, Undefined);
Game_State : Game_State_T := Welcome;
begin
loop
Noki.Log (Noki.Clear_Screen);
case Game_State is
when Welcome =>
Noki.Log ("Welcome to Snakotron!");
Game_State := Play;
when Play =>
Noki.Log ("We are playing.");
Game_State := Game_Over;
when Game_Over =>
Noki.Log ("Game Over!");
Game_State := Undefined;
when others =>
Noki.Log ("Press Ctrl+C to abort program!");
end case;
delay 1.0;
end loop;
end Snake_Game;
Build and run:
alr build
bin/snake_game
β Expected result: Instead of scrolling text, you'll see only the current message updating in place as the game state advances.
π€― Heads Up! The terminal now clears and redraws each frame - this is the foundation of all terminal-based games!
Save Your Progress
π― End of Lesson 3 β Save Your Progress
To keep your work safe and accessible, push it to your fork.
Make sure you're at the root of the repo:
cd ~/sandbox/snake-tutorial
Make sure you're on your work branch:
git status
- π¨ If you're NOT on branch
lesson-03-work, run:git checkout -b lesson-03-work
Stage and commit your progress:
git add .
git commit -m "Lesson 3 progress"
Push to your fork:
git push origin lesson-03-work
β Expected result: Your fork now has a lesson-3-work branch with your code so far.
Level up your Server Side game β Join 15,000 engineers who receive insightful learning materials straight to their inbox
- βΒ Previous
- Building Your First Ada Library
- NextΒ β
- Concurrent Input Handling