diff --git a/03_Animal/lua/Animal.lua b/03_Animal/lua/Animal.lua new file mode 100644 index 00000000..293c53e4 --- /dev/null +++ b/03_Animal/lua/Animal.lua @@ -0,0 +1,181 @@ +-- +-- Animal.lua +-- + +-- maintain a flat table/list of all the known animals +local animals = { + "FISH", + "BIRD" +} + +-- store the questions as a binary tree with each node having a +-- "y" or "n" branch +-- if the node has a member named "a" it's an answer, with an index +-- into the animals list. +-- Otherwise, it's a question that leads to more nodes. +local questionTree = { + q = "DOES IT SWIM", + y = { a = 1 }, + n = { a = 2 } +} + +-- print the given prompt string and then wait for input +-- loops until a non-empty input is given +-- returns the input as an upper-case string +function askPrompt(promptString) + local answered = false + local a + while (not answered) do + print(promptString) + a = io.read() + a = string.upper(a) + if (string.len(a) > 0) then + answered = true + end + end + return a +end + +-- print the given prompt string and then wait for the +-- user to enter a string beginning with "Y" or "N" +function askYesOrNo(promptString) + local a + while ((a ~= "Y") and (a ~= "N")) do + a = askPrompt(promptString) + a = a:sub(1,1) + end + return a +end + +-- prints the introductory text from the original BASIC program +function printIntro() + print(string.format("%32s", " ") .. "ANIMAL") + print(string.format("%15s", " ") .. "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print() + print() + print() + print("PLAY 'GUESS THE ANIMAL'") + print("THINK OF AN ANIMAL AND THE COMPUTER WILL TRY TO GUESS IT.") + print() +end + +-- prints the animals known in the source list +function listKnownAnimals() + print() + print("ANIMALS I ALREADY KNOW ARE:") + + local x + local item + for x = 1,#animals do + -- use string.format to space each animal in a 12-character-wide "cell" + item = string.format("%-12s", animals[x]) + + -- io.write() works like print(), but doesn't automatically add a carriage return/newline + io.write(item) + + -- every fifth item, start a new line + if ((x % 5) == 0) then + io.write("\n") + end + end + + print() + print() +end + +-- Prompts the user for info about the animal they were thinking of, then +-- uses that to add a new branch to the tree +-- curNode: the node in the tree where the computer made a wrong guess +-- branch: the answer the user gave to curNode's question +function addAnimalToTree(curNode, branch) + local newAnimal + local curResponse = curNode[branch] + local guessedIndex = curResponse.a + local guessedAnimal = animals[guessedIndex] + local newQuestion, newAnswer, newIndex + local newNode + + newAnimal = askPrompt("THE ANIMAL YOU WERE THINKING OF WAS A ?") + newQuestion = askPrompt("PLEASE TYPE IN A QUESTION THAT WOULD DISTINGUISH A ".. + tostring(newAnimal).." FROM A "..tostring(guessedAnimal)) + newAnswer = askYesOrNo("FOR A "..tostring(newAnimal).." THE ANSWER WOULD BE?") + + -- add the new animal to the master list at the end, and + -- save off its index in the list + table.insert(animals, newAnimal) + newIndex = #animals + + -- create a new node for the question we just learned + newNode = {} + newNode.q = newQuestion + if (newAnswer == "Y") then + newNode.y = { a = newIndex } + newNode.n = { a = guessedIndex } + else + newNode.y = { a = guessedIndex } + newNode.n = { a = newIndex } + end + + -- replace the previous answer with our new node + curNode[branch] = newNode +end + +-- Starts at the root of the question tree and asks questions about +-- the user's animal until the computer hits an "a" answer node and tries +-- to make a guess +function askAboutAnimal() + local curNode = questionTree + local finished = false + local response, responseIndex + local nextNode, animalName + while (not finished) do + response = askYesOrNo(curNode.q .. "?") + + -- convert the response "Y" or "N" to the lowercase "y" or "n" that we use to name our branches + branch = string.lower(response) + nextNode = curNode[branch] + + -- is the next node an answer node, or another question? + if (nextNode.a ~= nil) then + -- it's an answer, so make a guess + animalName = animals[nextNode.a] + response = askYesOrNo("IS IT A "..tostring(animalName).."?") + if (response == "Y") then + -- we got the correct answer, so prompt for a new animal + print() + print("WHY NOT TRY ANOTHER ANIMAL?") + else + -- incorrect answer, so add a new entry at this point in the tree + addAnimalToTree(curNode, branch) + end + + -- whether we were right or wrong, we're finished with this round + finished = true + else + -- it's another question, so advance down the tree + curNode = nextNode + end + end +end + +-- MAIN CONTROL SECTION + +printIntro() + +-- loop forever until the player requests an exit by entering a blank line +local exitRequested = false +local answer + +while (not exitRequested) do + print("ARE YOU THINKING OF AN ANIMAL?") + answer = io.read() + answer = string.upper(answer) + + if (string.len(answer) == 0) then + exitRequested = true + elseif (answer:sub(1,4) == "LIST") then + listKnownAnimals() + elseif (answer:sub(1,1) == "Y") then + askAboutAnimal() + end +end