Skip to content
📖 The Auto Programming LanguageBook contents

Project: Guessing Game ​

This is the capstone project for Phase 1. Over the first four chapters, you've learned about variables, operators, functions, collections, and control flow. Now it's time to put all of those skills together by building a complete interactive program: a number guessing game.

Here's how the game works: the program picks a secret number between 1 and 100. The player types in a guess, and the program says "Too small!" or "Too big!" until the player gets it right. We'll build this in four stages, adding one feature at a time:

  1. Reading input -- get a guess from the player and print it
  2. Adding a loop -- let the player guess repeatedly with feedback
  3. Random numbers -- pick a different secret number each game
  4. Error handling -- deal with invalid (non-number) input gracefully

Setting Up ​

Create a new Auto project for this chapter:

console
$ automan new guessing_game
$ cd guessing_game

Open src/main.at in your editor. This is where you'll write all the code. Every version of the game we build will live in this single file.

Reading Input ​

The first version of the game doesn't play yet -- it just asks the player for input and echoes it back. This lets us learn two essential built-in functions: input() and print().

A guessing game -- reading user input

Let's walk through this line by line.

The print Function ​

auto
print("Guess the number!")

print is a built-in function that writes text to the terminal. It takes a single str argument and adds a newline at the end. We use it twice: once to announce the game, and once to prompt the player.

The input Function ​

auto
var guess = input()

input() is a built-in function that reads one line of text from the player and returns it as a str. The program pauses here and waits for the user to type something and press Enter. We store the result in guess, declared with var because we'll be reassigning it in later versions.

String Concatenation with + ​

auto
print("You guessed: " + guess)

The + operator concatenates two strings. Auto infers that the result is also a str. If you wrote "a" + 42, the compiler would report a type error -- you need to convert the number to a string first. We'll see how to do that with parse_int in the next section.

Running the Program ​

console
$ automan run
Guess the number!
Please input your guess.
76
You guessed: 76

The program prints the prompts, waits for your input, and echoes it back. Not much of a game yet, but the foundation is in place.

Notice how each target language handles user input differently:

  • Rust uses a custom read_line() function. The result is a String that the transpiler manages.
  • Python maps directly to the built-in input() function. This is the closest match -- Python's input() does exactly what Auto's input() does.
  • C uses fgets() to read into a fixed-size buffer, then strips the trailing newline with strcspn. Manual memory management is required.
  • TypeScript uses the readline module with a callback-based API. The callback receives the user's input as a string.

Adding a Loop ​

Right now the player gets one guess and the program exits. A real game needs to keep asking until the player wins. We also need to convert the string input to a number so we can compare it with the secret number, and give feedback about whether the guess is too high or too low.

Looping until the user guesses correctly

There's a lot of new material here. Let's break it down.

The for true Infinite Loop ​

auto
for true {
    // ...
}

for true creates an infinite loop -- it runs until something inside it explicitly stops it. In Auto, for is the only loop keyword, and it handles all looping patterns. for true means "loop forever." The transpiler maps this to loop in Rust, while True in Python, while (1) in C, and a recursive function in TypeScript.

The parse_int Function ​

auto
var guess = parse_int(guess_str)

input() returns a str, but we need a number to compare with the secret. parse_int converts a string to an integer. If the string is "76", it returns the integer 76. Auto infers that guess has type int.

Note: in this version, if the player types something that isn't a number (like "hello"), parse_int will crash the program. We'll fix that in the final version.

Comparison Operators and if/else ​

auto
if guess == secret {
    print("You win!")
    break
}
if guess < secret {
    print("Too small!")
} else {
    print("Too big!")
}

We use == for equality, &lt; for less-than. The if statement runs its block when the condition is true. The else block runs when the if condition is false.

The break keyword exits the loop immediately. When the player guesses correctly, we print "You win!" and then break, which jumps to the code after the for block -- and since there's nothing after it, the program ends.

Running the Program ​

console
$ automan run
Guess the number!
10
You guessed: 10
Too small!
50
You guessed: 50
Too big!
42
You guessed: 42
You win!

The game works. But there's a problem: the secret number is always 42. If you play twice, you already know the answer. Let's fix that.

Random Numbers ​

To make the game replayable, we need a different secret number each time. The built-in function random_int(min, max) generates a random integer in the given range, inclusive on both ends.

Generating a random secret number

The only change from Listing 5-2 is the first line inside main:

auto
var secret = random_int(1, 100)

Instead of hard-coding 42, we call random_int(1, 100) to get a random integer between 1 and 100. The type of secret is inferred as int. We also update the opening message to tell the player the range.

Now each time you run the program, you get a different secret number. Try it a few times:

console
$ automan run
Guess the number between 1 and 100!
50
You guessed: 50
Too big!
25
You guessed: 25
Too small!
37
You guessed: 37
You win!

Much better. But there's still one more issue to fix.

Error Handling ​

What happens if the player types something that isn't a number? Right now, parse_int("hello") crashes the program. That's not a great user experience. Instead, we should detect the bad input, print a message, and let the player try again.

In Auto, parse_int returns an optional integer: ?int. An optional value is either a real integer or none (meaning "no value"). We can check for none to handle the error case.

The complete guessing game with input validation

This is the final version of the game. Let's look at what's new.

Optional Types and none ​

auto
var guess = parse_int(guess_str)
if guess == none {
    print("Please enter a valid number!")
    continue
}

parse_int now returns ?int (read "optional int") instead of plain int. An optional type means the value can either be an integer or none. When the player types "hello", parse_int returns none -- there's no valid integer to extract. When the player types "42", it returns 42.

We check guess == none to detect the error case. If the input was invalid, we print a message and use continue to skip the rest of the loop body and start the next iteration, asking the player again.

In Phase 2, you'll learn about Auto's full error handling with !T and the unwrap operator. For now, checking == none is the basic way to handle optional values.

The continue Keyword ​

continue skips the rest of the current loop iteration and goes back to the condition check. Combined with for true, it effectively means "start the loop over from the top." This is perfect for skipping bad input without counting it as a guess.

Counting Attempts ​

auto
var attempts = 0
// ...
attempts = attempts + 1

We added an attempts counter that starts at 0 and increments by 1 each time the player enters a valid guess. When the player wins, we include the count in the victory message. Note that we only increment attempts after the none check, so invalid inputs don't count.

Running the Final Version ​

console
$ automan run
Guess the number between 1 and 100!
Please input your guess.
hello
Please enter a valid number!
Please input your guess.
50
You guessed: 50
Too big!
Please input your guess.
25
You guessed: 25
Too small!
Please input your guess.
37
You guessed: 37
You win! You got it in 3 tries!

The game handles all the edge cases: non-number input, too-high guesses, too-low guesses, and correct guesses. It counts attempts, gives feedback, and exits cleanly when the player wins.

Look at how each target language handles the "invalid input" check:

  • Rust uses Option&lt;i64&gt; with .ok() (converts Result to Option), .is_none() for the check, and .unwrap() to extract the value after the check.
  • Python uses a try/except ValueError block. If int() fails on bad input, it raises ValueError, and the except branch handles it.
  • C uses strtoll() which sets endptr to the first non-numeric character. If *endptr != '\0', the input contained non-digit characters.
  • TypeScript checks isNaN(guess) after parseInt(). If the input wasn't a valid number, parseInt returns NaN (Not a Number).

Summary ​

Congratulations -- you've built a complete interactive game in Auto! This project brought together everything you learned in Phase 1:

  • Variables (var) -- secret, attempts, guess, guess_str all use var to hold values that change during the game
  • Functions (fn) -- the entire game lives in main(), and we called built-in functions like print(), input(), parse_int(), and random_int()
  • Operators -- ==, &lt;, + for comparison and concatenation
  • Control flow -- if/else for branching, for true for looping, break to exit, continue to skip
  • Types -- int, str, ?int (optional int), with the compiler inferring types from context
  • Collections -- not used directly in this game, but you now know arrays, objects, maps, and sets from Chapter 4

This is the end of Phase 1. You now have a solid foundation in Auto's core syntax and semantics. In Phase 2, we'll go deeper:

  • Phase 2 introduces let for immutable bindings, the is keyword for pattern matching, custom types with type, extension methods with ext, and full error handling with !T.
  • Phase 3 covers generics, interfaces, concurrency, and more advanced language features.

Take a moment to review what you've learned. Try modifying the guessing game on your own: change the range, add a maximum number of attempts, or print a different message depending on how quickly the player wins. You have all the tools you need.

Released under the MIT License.