Luet oppimateriaalin englanninkielistä versiota. Mainitsit kuitenkin taustakyselyssä osaavasi suomea. Siksi suosittelemme, että käytät suomenkielistä versiota, joka on testatumpi ja hieman laajempi ja muutenkin mukava.
Suomenkielinen materiaali kyllä esittelee englanninkielisetkin termit.
Kieli vaihtuu A+:n sivujen yläreunan painikkeesta. Tai tästä: Vaihda suomeksi.
Chapter 10.2: Peeveli
Background for Upcoming Assignments
A recap
The facts listed below should be already familiar. Revisit the earlier chapters or the Scala Reference for details as needed.
Collections such as buffers and vectors have many first-order methods (such as
take
,contains
, andindexOf
; Chapter 4.2) and higher-order methods (such asfilter
,map
, andmaxBy
; Chapters 6.3, 7.1, and 10.1).String
s consist of elements of typeChar
, each of which represents a single letter or other character (Chapter 5.2).String
s have many methods that are specific to string processing (such astrim
andtoUpperCase
; Chapter 5.2).String
s are objects; they are collections with characters as elements (Chapter 5.2). The things you can do with a collection, such as loop over it withfor
, you can also do with aString
(Chapter 5.6).String
s share many first-order methods with other collections (such astake
,contains
, andindexOf
; Chapter 5.2).
Now, knowing that String
s are collections, it’s natural that they too have
higher-order methods, many of which you already know.
Examples of higher-order methods on String
s
Let’s use foreach
to print each of a string’s elements (characters):
"Hi!".foreach(println)H i !
Now let’s take a longer string and filter
out everything but lower-case letters. We’ll
be assisted by the isLower
method on Char
s:
"Let's offroad!".filter( _.isLower )res0: String = etsoffroad
sorted
sorts characters as per their natural ordering (Chapter 10.1), which is defined
by Unicode:
"Let's offroad!".sortedres1: String = " !'Ladeffoorst"
With sortBy
, we can — for instance — sort the letters by their lower-case
equivalents:
"Let's offroad!".sortBy( _.toLower )res2: String = " !'adeffLoorst"
Calling toLower
on a Char
produces its lower-case version.
Observe the difference between this output and the earlier one.
The map
method constructs its return value by applying its parameter function to each
character in the string. Here are a couple of examples:
"Let's offroad!".map( char => if char.isLower then char.toUpper else char.toLower )res3: String = lET'S OFFROAD! "Hi!".map( _.isLower )res4: IndexedSeq[Boolean] = Vector(false, true, false)
Peeveli, a Word Game
Background: the game of Hangman
Hangman is a classic word game for two: one player — the riddler — picks a word and the other player — the guesser — tries to figure out what the word is, guessing one letter at a time. The length of the word is known to both players. Each time the guesser picks a letter, the riddler must reveal all those positions in the target word where that letter appears. If the letter doesn’t appear in the target word at all, the guess is a miss and the riddler draws an additional element into a line drawing of a hanging stick figure.
If the guesser misses a few times, the drawing will be completed and the guesser loses the game. The guesser wins in case they manage to reveal the entire word.
That’s pretty much all there is to it, but you can read up on the game in Wikipedia if you like. Hangman will probably remind some readers of Wordle, a game that went viral in December 2021 and is something like a cross between Hangman and Mastermind.
There are many digital variants of Hangman in which the computer takes the role of the riddler and the human player is the guesser. Just like the traditional pen-and-paper version, these variants are based on the premise that the guesser can trust the riddler.
Our take on Hangman is different. In the game we’re about to program, the riddler is something called Peeveli, and it doesn’t play fair.
Cheating at Hangman
In a regular game of Hangman, the riddler picks the target word at the start of the game and scrupulously reveals letters as the correct answers accumulate. But what if the riddler wasn’t trustworthy?
Imagine the scene. The game has just started, you are the guesser, and the riddler has just — unbeknownst to you — picked the target word BAZAAR. The concealed word initially looks like this:
_ _ _ _ _ _
If you now guess A, the riddler should reveal three copies of that letter. But they could instead mentally switch their original target word for an A-less one — such as BELIEF — and inform you that there is no A and your guess is a miss.
Imagine another scene. You’ve managed to guess all but one of the letters in this five-letter word, but the next incorrect guess will lose you the game.
_ E L A Y
Suppose you haven’t guessed the letters D, R, and B yet. Only three possible answers exist in English: DELAY, RELAY, and BELAY. However, no matter which of the three letters you pick, the riddler can pretend they were thinking of one of the other two words. You can’t beat the dishonest riddler!
Introduction to Peeveli
In the game of Peeveli, the computer is the riddler and the human player is the guesser. The game is hard to beat because the computer cheats methodically. It uses a vast vocabulary in combination with a devious algorithm: it doesn’t actually pick a target word at all, instead keeping track of all the existing words that continue to be plausible correct solutions, given the previous guesses and the letters already revealed as a consequence. Whenever the player guesses a letter, Peeveli tries to keep its options open: it selects which (if any) letters to reveal so that there are as many potential solutions left as possible.
Imagine a scenario with you as the riddler. The target word is supposed to have four letters. Further imagine that there are no four-letter words in English apart from the ten listed below. The target word must therefore be one of those ten.
ALSO AREA AUNT GURU HAWK IDEA JUJU PLAY TUNA ZERO
Your opponent’s first guess is the letter A. What should you do?
First, you should see where the A’s appear in the list of known four-letter words.
ALSO AREA AUNT GURU HAWK IDEA JUJU PLAY TUNA ZERO
Now you can identify a few groups of words with different patterns of A’s in them:
Group |
Description |
Words |
---|---|---|
|
Begins and ends with an A. |
AREA |
|
One A as the first letter. |
ALSO, AUNT |
|
One A as the second letter. |
HAWK |
|
One A as the third letter. |
PLAY |
|
One A as the last letter. |
IDEA, TUNA |
|
No A’s at all. |
GURU, JUJU, ZERO |
This basically means that you need to pick one of six alternatives. A good basic strategy is to pick the largest group, which in this instance is the last one. So you inform your opponent that the word has no A’s and memorize the three plausible solutions that are left: GURU, JUJU, and ZERO.
If the vocabulary had additionally contained APEX and ARMY, which begin with an A, the
group A___
would have been the largest. In that scenario, you would have revealed the
initial A and memorized the plausible solutions ALSO, APEX, ARMY, and AUNT.
Suppose you’ve chosen the group with GURU, JUJU, and ZERO, and your opponent’s next
guess is the letter U. This results in the groups _U_U
(with GURU and JUJU) and
____
(with ZERO). The former is larger, so you tell your opponent there are U’s in
the second and fourth slots.
Whenever your opponent guesses a letter that doesn’t appear in any of the plausible solutions, you have only a single group that contains all the words that remain. Obviously, you’ll then pick that group.
Occasionally, you’ll find that there are multiple groups of equal size. In such cases, you could pick an arbitrary group or break the tie by choosing the group that reveals the fewest letters. In any case, you wouldn’t reveal the correct answer unless forced to.
The Peeveli module
The module Peeveli contains a partial implementation of the game described above. The GUI is in working order but the riddler is sorely lacking in smarts.
Task description
Try playing the game as given. The app object is
o1.peeveli.gui.PeeveliApp
. You’ll notice several things:The riddler is really lenient, not at all what we intended. It accepts all guesses and always reveals one more letter of the target word on each guess.
The game doesn’t end when it should.
You can change vocabularies in the menu. You’ll need to do that if you want to play with English words.
You can enable a testing mode where Peeveli uses the text console to print out all the remaining plausible solutions after each guess. (The given riddler meekly prunes down the list to just one solution, though.)
Study the module’s Scaladocs and program code.
Implement the missing parts that make Peeveli work as cleverly as we planned above.
A clarification
In the above description of Peeveli’s algorithm, we mentioned that when word groups are equal in size, it might be a good idea to pick the group that reveals fewer letters to the guesser. That is completely optional in this assignment. Implement that additional bit of devilry only if you want an additional challenge. Otherwise, just pick any of the equally sized groups.
Instructions and hints
You’ll need to edit only
GameState.scala
.It’s a good idea to implement the private method
reveal
and use it inguessLetter
.When you write literals, remember that whereas
String
literals go in double quotation marks as in"myString"
,Char
literals such as'c'
use single quotes.groupBy
(Chapter 10.1)
A+ presents the exercise submission form here.
In case you are wondering about this chapter’s total score
You might have noticed that according to your points page in A+, this chapter is worth one more optional point that you can actually score on this page.
That is because there’s a completely optional assignment in the Finnish translation of the ebook here, which is worth 1 nominal point (that does not count towards the course grade). That assignment is fundamentally untranslatable as its topic deeply involves the Finnish language. A+ is unable to handle such "single-language" assignments gracefully and displays that point even in the English edition, where the assignment does not exist as it would make little sense.
It’s the only Finnish-only assignment in the ebook, and totally optional. You’re not missing out on anything crucial at all, so don’t worry.
(If you do know Finnish, you can switch languages and do the assignment.)
Assignment unavailable in English
A+ presents the exercise submission form here.
Feedback
Please note that this section must be completed individually. Even if you worked on this chapter with a pair, each of you should submit the form separately.
Credits
Thousands of students have given feedback and so contributed to this ebook’s design. Thank you!
The ebook’s chapters, programming assignments, and weekly bulletins have been written in Finnish and translated into English by Juha Sorva.
The appendices (glossary, Scala reference, FAQ, etc.) are by Juha Sorva unless otherwise specified on the page.
The automatic assessment of the assignments has been developed by: (in alphabetical order) Riku Autio, Nikolas Drosdek, Kaisa Ek, Joonatan Honkamaa, Antti Immonen, Jaakko Kantojärvi, Onni Komulainen, Niklas Kröger, Kalle Laitinen, Teemu Lehtinen, Mikael Lenander, Ilona Ma, Jaakko Nakaza, Strasdosky Otewa, Timi Seppälä, Teemu Sirkiä, Joel Toppinen, Anna Valldeoriola Cardó, and Aleksi Vartiainen.
The illustrations at the top of each chapter, and the similar drawings elsewhere in the ebook, are the work of Christina Lassheikki.
The animations that detail the execution Scala programs have been designed by Juha Sorva and Teemu Sirkiä. Teemu Sirkiä and Riku Autio did the technical implementation, relying on Teemu’s Jsvee and Kelmu toolkits.
The other diagrams and interactive presentations in the ebook are by Juha Sorva.
The O1Library software has been developed by Aleksi Lukkarinen, Juha Sorva, and Jaakko Nakaza. Several of its key components are built upon Aleksi’s SMCL library.
The pedagogy of using O1Library for simple graphical programming (such as Pic
) is
inspired by the textbooks How to Design Programs by Flatt, Felleisen, Findler, and
Krishnamurthi and Picturing Programs by Stephen Bloch.
The course platform A+ was originally created at Aalto’s LeTech research group as a student project. The open-source project is now shepherded by the Computer Science department’s edu-tech team and hosted by the department’s IT services; dozens of Aalto students and others have also contributed.
The A+ Courses plugin, which supports A+ and O1 in IntelliJ IDEA, is another open-source project. It has been designed and implemented by various students in collaboration with O1’s teachers.
For O1’s current teaching staff, please see Chapter 1.1.
Additional credits for this page
Peeveli is a derivative of a similar programming assignment designed by Keith Schwarz.
In Unicode, the upper-case alphabet comes before the lower-case one.