Part II · Growing the Project

Chapter 7: Words and Text

Go back and try something with your chapter 3 riddle: answer with "Piano" instead of "piano", capital P. It fails. Try "piano " with a trailing space, maybe left over from how you typed it. It fails too. Your player knew the right answer both times, and the game told them they were wrong. That's not a puzzle being clever, that's a bug. This chapter gives you the tools to fix it, and to start actually understanding what the player typed instead of just checking it letter for letter.

The Problem With ==

You already know == compares strings exactly, case and all. That's correct behavior, it's just not always the behavior you want. A human typing "Piano" means the same thing as "piano." Your program needs to be told that on purpose.

upper and lower

upper() and lower() convert a string's case:

QF Code example 1
writeln(upper("piano"))   // PIANO
writeln(lower("PIANO"))   // piano

The fix for the riddle check is to force both sides to the same case before comparing:

QF Code example 2
if lower(answer) == "piano" then
    writeln("The door swings open.")
end if

Now "Piano", "PIANO", and "piano" all match.

trim

trim() removes whitespace from the start and end of a string, but leaves anything in the middle alone.

QF Code example 3
writeln(trim("  piano  "))   // "piano"

Combine it with lower(), and the riddle check stops caring about capitalization or stray spaces from typing:

QF Code example 4
if lower(trim(answer)) == "piano" then
    writeln("The door swings open.")
end if

That single line is the fix for both bugs you found a minute ago.

contains, startswith, and endswith

These three let you check for a piece of text without needing an exact, whole-string match:

QF Code example 5
contains("The rusty key", "key")        // TRUE
startswith("take candle", "take")       // TRUE
endswith("half-burned candle", "candle") // TRUE

All three are case-sensitive, so pair them with lower() the same way you just did for the riddle, whenever the player's exact capitalization shouldn't matter.

split

split() breaks a string into an array of pieces, wherever a delimiter you choose shows up.

QF Code example 6
var words = split("take candle", " ")
writeln(words[0])   // take
writeln(words[1])   // candle

This is exactly what turns a typed sentence into something your code can actually reason about, a verb and a target, instead of one long string.

substring and replace

Two more worth knowing, used less often but useful when you need them. substring() pulls out part of a string by position:

QF Code example 7
writeln(substring("cottage", 0, 3))   // cot

replace() swaps out every occurrence of one piece of text for another:

QF Code example 8
writeln(replace("the old door", "old", "new"))   // the new door

Growing the Adventure

Time to give the player real commands instead of yes/no answers.

QF Code example 9
// The Hollow Cottage
// Chapter 7


const cottageName = "The Hollow Cottage"

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("The cottage is dusty but intact.")

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

    writeln("On the floor, you notice a rusty key and a half-burned candle.")

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

    if verb == "take" then
        showInventory(inventory)
    else if verb == "look" then
        writeln("A small cottage, one room, one door out.")
    else
        writeln("Nothing happens.")
    end if
end if

Make It Yours. Add a third command your parser understands, "inventory", "help", whatever fits your game, and give it its own else if branch.

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 6 checkpoint.

Completed code (Chapter 7):

QF Code example 10Open in QF Code
// The Hollow Cottage
// Chapter 7


const cottageName = "The Hollow Cottage"

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("The cottage is dusty but intact.")

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

    writeln("On the floor, you notice a rusty key and a half-burned candle.")

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

    if verb == "take" then
        showInventory(inventory)
    else if verb == "look" then
        writeln("A small cottage, one room, one door out.")
    else
        writeln("Nothing happens.")
    end if
end if

Next: your riddle and your commands both deserve some randomness and a little arithmetic. Chapter 8 brings in QF Code's math library.


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.