Part III · Making It Solid

Chapter 14: Finishing the Project

Thirteen chapters ago, this program was one line: writeln("You are standing outside a locked cottage."). Everything since then, every variable, every loop, every function, has been added because the story needed it, not because it was next on a checklist. This chapter closes it out, and takes stock of everything that got you here.

One Last Polish Pass

Two small touches, nothing new to learn, just tying off loose ends with tools you already have. A short title banner at the very top, using write() the way you first met it back in chapter 1:

QF Code example 1
write("=")
for i = 1 to 30
    write("=")
end for
writeln("")
writeln("THE HOLLOW COTTAGE")
write("=")
for i = 1 to 30
    write("=")
end for
writeln("")
writeln("")

And a short farewell at the very end, after the final score:

QF Code example 2
writeln("")
writeln("Thanks for playing.")

Small touches, but they're the difference between a program that just stops and a program that feels like it has a beginning and an end on purpose.

The Complete Program

QF Code example 3
// The Hollow Cottage
// Complete

write("=")
for i = 1 to 30
    write("=")
end for
writeln("")
writeln("THE HOLLOW COTTAGE")
write("=")
for i = 1 to 30
    write("=")
end for
writeln("")
writeln("")

const cottageName = "The Hollow Cottage"

var score = 0

function addScore(amount)
    score = score + amount
    writeln("(+" + amount + " points)")
end function

function showInventory(items)
    writeln("You are carrying:")
    for each item in items
        writeln("- " + item)
    end for
end function

writeln("You are standing outside " + cottageName + ".")

var playerName = input("What is your name, traveler? ")
writeln("Welcome, " + playerName + ".")

var tries = 0
var solved = false

while tries < 3 and not solved
    tries = tries + 1
    var answer = input("There is a riddle carved into the door. It asks: what has keys but no locks? ")

    if lower(trim(answer)) == "piano" then
        writeln("The door swings open. You step inside.")
        solved = true
    else
        writeln("Nothing happens.")
    end if
end while

if not solved then
    writeln("The door refuses to budge. You'll have to find another way in.")
else
    writeln("You step inside. In the corner sits a locked chest with a dial numbered 1 to 100.")

    var secret = randomint(1, 100)
    var guessesLeft = 6
    var found = false

    while guessesLeft > 0 and not found
        var guess = empty
        var validInput = false

        while not validInput
            attempt
                guess = num(input("Turn the dial to a number (1-100): "))
                validInput = true
            error
                writeln("That doesn't look like a number. Try again.")
            end attempt
        end while

        guessesLeft = guessesLeft - 1

        if guess == secret then
            writeln("The chest clicks open!")
            found = true
            addScore(10)
            sound("C4", 150)
            sound("E4", 150)
            sound("G4", 150)
        else
            sound("A3", 200)
            var distance = abs(guess - secret)

            match distance
                when 0 to 5
                    writeln("Very warm. " + guessesLeft + " turns left.")
                when 6 to 20
                    writeln("Warm. " + guessesLeft + " turns left.")
                when else
                    writeln("Cold. " + guessesLeft + " turns left.")
            end match
        end if
    end while

    var inventory = array()
    append(inventory, "rusty key")
    append(inventory, "half-burned candle")

    if not found then
        writeln("The dial jams. The chest stays locked, for now.")
        bell()
    else
        append(inventory, "small silver coin")
        writeln("Inside, you find a small silver coin.")
        showInventory(inventory)
    end if

    var command = input("What do you do? ")
    var words = split(lower(trim(command)), " ")
    var verb = words[0]

    match verb
        when "take"
            showInventory(inventory)
        when "look"
            writeln("A small cottage, one room, one door out.")
        when "quit"
        when "exit"
            writeln("You step back out into the cold.")
        when else
            writeln("Nothing happens.")
    end match
end if

writeln("")
writeln("Final score: " + score)
writeln("")
writeln("Thanks for playing.")

One change from the running checkpoints worth noticing: the riddle at the door now uses lower(trim(answer)), the chapter 7 fix, instead of the plain == it started with back in chapter 3. That's not an accident, it's this book's whole approach in miniature, nothing gets left as it was first written if a later chapter taught you a better way to write it.

A Tour of Everything You Used

Every chapter you worked through is sitting somewhere in that program:

  • Chapter 1: write(), writeln(), comments
  • Chapter 2: var, const, input(), concatenation, num()
  • Chapter 3: if, else, comparison operators
  • Chapter 4: while, the riddle's attempt counter
  • Chapter 5: array(), append(), indexing
  • Chapter 6: showInventory() and addScore(), both functions
  • Chapter 7: lower(), trim(), split(), the command parser
  • Chapter 8: randomint(), abs(), the chest puzzle
  • Chapter 9: match, both in the hints and the command dispatch
  • Chapter 10: attempt/error, guarding the dial input
  • Chapter 11: the global score, updated from inside a function
  • Chapter 12: sound() and bell(), the chest's chime and thud
  • Chapter 13: nothing here, and that was always fine

That's not a small list for something that started as one line of output.

What You Could Add Next

This book is finished, but your game doesn't have to be. A few directions worth trying entirely on your own, with tools you already have:

  • A second room, reached after the chest, with its own description and its own commands
  • An if inventory check that changes an ending depending on what the player is carrying
  • A difficulty setting the player picks at the start, changing the number of riddle attempts or chest guesses
  • A proper help command that lists everything the parser understands

Make It Yours, for the last time in this book, in the biggest sense of that phrase. Everything past this point is entirely your own game now.

Chapter Checkpoint

Open either known-good checkpoint directly in QF Code, or download the .qfc file to keep locally. The IDE opens in a new tab and does not run the program automatically.

Starting code: the Chapter 13 checkpoint.

Completed code (Chapter 14): the complete program above.

Next: the project is done. Chapter 15 looks back at the whole book, and points you toward what comes after it.


Copyright © 2026 Edison Mooers. Published by Gibidda Press. Free for personal learning and qualifying noncommercial educational use. Commercial training, organizational use, redistribution, and adaptation require written permission. Full use terms.