8.3

#### Assignment 5: Building a game; Visitors

Goals: To build a non-trivial Big-bang game from scratch, and practice with visitors

##### Instructions

Be very, very careful with naming! Again, the solution files expect your submissions to be named a certain way, so that they can define their own Examples class with which to test your code. Therefore, whenever the assignment specifies:
• the names of classes,

• the names and types of the fields within classes,

• the names, types and order of the arguments to the constructor,

• the names, types and order of arguments to methods, or

• filenames,

...be sure that your submission uses exactly those names.

Make sure you follow the style guidelines that Bottlenose enforces. For now the most important ones are: using spaces instead of tabs, indenting by 2 characters, following the naming conventions (data type names start with a capital letter, names of fields and methods start with a lower case letter), and having spaces before curly braces.

You will submit this assignment by the deadline using the Bottlenose submission system. You may submit as many times as you wish. Be aware of the fact that close to the deadline the Bottlenose system may slow down to handle many submissions - so try to finish early.

There will be a separate submission for each problem - it makes it easier to grade each problem, and to provide you with the feedback for each problem you work on.

The submissions will be organized as follows:

• Homework 5 Problem 1 review: Your review of other students’ examples

• Homework 5 Problem 2: Your final version of the game

• Homework 5 Problem 3: The Arith.java file

Due Dates:
• Problem 1, initial examples: Friday, Feb 18th, at 9:00pm

• Problem 1 peer review: Saturday, Feb 19th, at 9:00pm

• Problem 2, final game implementation: Friday Feb 25th, at 9:00pm

• Problem 3, arithmetic visitors: Friday Feb 25th, at 9:00pm

### Problem 1:Wordle

Related files:
Starter.java

Note: Read through this whole problem to see which parts are due when. You will submit this project in three stages over two weeks, so you should work steadily at it, but there’s no need to rush.

Implement the game Wordle. Wordle is a logic puzzle, where the player’s task is to guess a secret word that’s been generated by the game, using only words in an allowed dictionary of words. You are given two forms of feedback on your guess: the letters that are correct and in the correct place, and the letters that are correct but in the incorrect place.

For example, suppose the secret code is

• A guess of indicates two letters are correct and in correct places, and two letters are correct and in incorrect places, while one letter is simply wrong.

• A guess of would have three correct letters in the wrong positions.

• A guess of has one correct letter in the correct place, and two correct letters in the wrong places. Note that even though S appears twice in the guess, it only appears once in the code, and is shown with its most-correct color.

Some design suggestions:
• You are encouraged to use generic types in this assignment, if you feel comfortable with them. They are not required, but they may be helpful. You will likely find it very helpful to implement a bunch of the common list-abstraction functions from Fundies 1 as methods on your lists here. You may find it convenient to use the following helper class (you may access its fields directly, like we do with Posns):

 class Pair { L left; R right; Pair(L left, R right) { this.left = left; this.right = right; } }
• Use the starter file given above for dictionaries of 4- and 5-letter words. Complete the design of the helper method in that file that takes in a String containing a bunch of words, an int indicating the word length, and an int indicating the separation length, and splits the string into a list of individual strings. For example, given the string "HELLO,WORLD/SPACE", a word length of 5 and a separation length of 1, it should produce a list containing "HELLO", "WORLD" and "SPACE" the separators themselves don’t matter, so long as they’re all the same length. You will likely want to use the two .substring methods on String for this.

• Your game should be parameterized by the dictionary of words available, and by the number of guesses allowed before the game is over. That is, your game should at least have a constructor (assuming you’re using generic lists)

 import javalib.funworld.*; class YourWorld extends World { YourWorld(IList dictionary, int numGuesses) { ... } }

Your constructor should ensure that the dictionary is not empty, and that every word in the list has the same length.

This implies that you cannot hardcode a guess as a class with five fields (letter1 through letter5, say), because you cannot know in advance how many letters there will be. You can assume that every word in the dictionary uses only the letters A through Z.

• Therefore, you should represent the secret code, and each guess, as an IList<String>, where each string in the list is one letter long. How you choose to represent the set of guesses is up to you.

• You will need to check whether two lists of strings are the same, meaning they have the same strings in the same order.

• You will need to compute which items in a IList<String> are the same (and in the same position) as items in a second IList<String>, and somehow produce a list of results.

• (Tricky!) You will also need to compute which letters are correct but in the wrong place. Note that as phrased here, this is not quite detailed enough a purpose statement for use in your game. (Why?) Test this one thoroughly...

• (Hint) You may want to produce a modified list of letters, such that all the exactly-correct ones have been replaced by "_" (which is deliberately not a valid letter). You may also want to design a method that removes the first time a value appears in a list from a list of values.

• I strongly recommend you try to solve the methods above using double-dispatch rather than via casting or via getter methods like getFirst or getRest. It’s a puzzle, but it’s worth the practice – if you completed all of Lab 4, you should have a big head-start on this problem.

• Your graphics do not need to worry about pinholes in this assignment at all. You also do not need to render the on-screen keyboard the way Wordle does (since we’re not playing this game on smartphones).

• I strongly recommend that you design your makeScene method to call a helper that returns a WorldImage, and do most of the interesting image composition in that helper.

• You should let the user guess a word by typing in letters, using the onKey handler of Big Bang. You should let them backspace to delete the last-entered letter, press enter to commit to a guess, and prevent them from entering invalid words (i.e. that aren’t in the dictionary) as guesses. Note that the arguments you receive in onKey are always lowercase.

##### 5.1Dordle

Once you’ve implemented Wordle, you should implement Dordle. Dordle is like Wordle, but doubled: there are two secret words to guess, and entering a guess will guess it in both games simultaneously.

For what it’s worth: my implementation of Dordle is only about 20 extra lines of code, after my implementation of Wordle is complete.

There are two ways to generate random numbers in Java. The easiest is to use Math.random(), which generates a double between 0 (inclusive) and 1 (exclusive). You can multiply this number by some integer to make it bigger, then coerce to an int to produce a random integer in the range you wish. However, this is not easily testable: you’ll get different random values every time.

The better way to generate random numbers is: First, import java.util.Random at the top of your file. Next, create a new Random() object, and use its nextInt(int maxVal) method, which will give you a random integer between zero (inclusive) and maxVal (exclusive).

This is known as a "pseudorandom number generator", since the numbers aren’t really random if they can be reliably repeated...

The reason this is better is because there is a second constructor, new Random(int initialSeed), which has the property that every time you create a Random with the same initial seed, it will generate the same "random" numbers in the same order every time your program runs. You should therefore design your world classes with two constructors:

• One of them, to be used for testing, should take in a Random object whose seed value you specify. This way your game will be utterly predictable every single time you test it.

• The second constructor should not take in a Random object, but should call the other constructor, and pass along a really random object:

 import java.util.Random; class YourWorld { Random rand // The constructor for use in "real" games YourWorld() { this(new Random()); } // The constructor for use in testing, with a specified Random object YourWorld(Random rand) { this.rand = rand; ... } }

Now, your tests can be predictable while your game can still be random, and the rest of your code doesn’t need to change at all.

##### Submission Instructions
• For Friday, Feb 18th: Examples class

This game is a bit difficult to split up into multiple submissions. However, to ensure that everyone begins the assignment early, please submit your examples class on Friday, along with the complete templates of the classes or interfaces that you need for your design. Your code does not need to compile (and it can’t, since you won’t be submitting your implementations of your classes...), but you should supply enough information that someone reading your examples can understand what they are doing.

You should be sure to include sufficient tests for checking the score of a given guess against a given secret. You should be sure to include sufficient tests for winning or losing the game. You should be sure to include tests for any exceptional cases, invalid data, etc. that are worth explaining.

This submission will be graded for code style and for general accuracy, but you can (and probably should) improve your test cases after this submission deadline.

• For Saturday, Feb 19th: Peer-reviewing each other’s examples As soon as the examples submission is due, the handin server will allow you to start reviewing your classmates’ code. (You will be randomly allocated two submissions to review — and obviously, you can only review submissions that have already been turned in! So it’s in your interest to make sure not to submit your examples late, or else you likely won’t receive any reviews from your classmates...) You will be given a short set of questions to answer about their correctness, completeness, usefulness, etc., which you can fill out on the server: see the handin guide documentation for more information.

Your reviews will be graded as well, for accuracy, usefulness, and politeness: no one wants a coworker trolling them in their codereviews.

• For Friday, Feb 25th: Final submission

Don’t make the game overly elaborate; we are more interested in your program’s design than your graphic design! Include two additional files in your submission:
• UserGuide.txt should be a short file describing how to play the game.

• Design.txt should describe each of the classes in your design, and what they all do. If you think it’s helpful, include an ASCII-art class diagram to show the relationships between the classes.

Be sure to include all your source files you used in your submission, or else we won’t be able to run your game. You should submit the files as a single .zip file. Only zip your src/ directory – do not include the build/ or target/ directories with the compiled .class files, and do not include the javalib or tester libraries themselves.

### Problem 2:Visitors

In a new file Visitors.java, implement the following class diagram:
      +-------------------+
| IArith            |
+-------------------+
+-------------------+
/_\      /_\
|        |--------------------------------------------------------------
|        |                                                             |
+-------------+  +------------------------------+           +-----------------------------------------+
| Const       |  | UnaryFormula                 |           |              BinaryFormula              |
+-------------+  +------------------------------+           +-----------------------------------------+
| double num  |  | Function<Double,Double> func |           | BiFunction<Double, Double, Double> func |
+-------------+  | String name                  |           | String name                             |
| IArith child                 |           | IArith left                             |
+------------------------------+           | IArith right                            |
+-----------------------------------------+

Specifically, the above represents an arithmetic expression. The Function and BiFunction in UnaryFormula and BinaryFormula respectively denote the arithmetic operation to be applied to their respective operands (child and left,right). In class, we defined these interfaces as IFunc and IFunc2, but they’re actually predefined for you in Java. To use them, you will need to write import java.util.function.*; at the top of your file among the other import statements. As in class, these interfaces require that you implement a method named apply, whose parameters are (in this problem) all Doubles.

You must support 4 binary formulas (named "plus", "minus", "mul" and "div" representing addition, subtraction, multiplication and division respectively), and 2 unary formulas (named "neg" and "sqr" representing negation and squaring respectively).

• Design an interface IArithVisitor<R> representing a visitor that visits an IArith and produces a result of type R. The visitor must be usable as a Function object on IArith producing a result of type R. For example, given an IArith object named iObj, and a SomeVisitor class, we should be able to write new SomeVisitor().apply(iObj).

• Design an accept(IArithVisitor<R>) method for the IArith interface and implement it on Const, UnaryFormula and BinaryFormula.

• Design an EvalVisitor that visits an IArith and evaluates the tree to a Double answer.

• Design a PrintVisitor that visits an IArith and produces a String showing the fully-parenthesized expression in Racket-like prefix notation (i.e. "(div (plus 1.0 2.0) (neg 1.5))"), using the name for Formulas and using Double.toString(num) on Consts.

• Design a DoublerVisitor that visits an IArith and produces another IArith, where every Const in the tree has been doubled.

• Design an AllSmallVisitor that visits an IArith and produces a Boolean that is true if every constant in the tree is less than 10.

• Tricky! Design a NoDivBy0 visitor that visits an IArith and produces a Boolean that is true if anywhere there is a Formula named "div", the right argument does not evaluate to roughly zero. Since all values here are double, define “roughly zero” as “absolute value less than 0.0001”.

• When evaluating the result, the computer on which this program will run has no support for negative numbers. Design a NoNegativeResults visitor that visits an IArith and produces a Boolean that is true, if a negative number is never encountered at any point during its evaluation.