Info Assignments Office Hours Hall of Fame Notes
Info Assignments Office Hours Hall of Fame Notes

TicTacToe Testing

Assigned: 2020-08-25
Due Date: 2020-09-01 by 11:59PM U.S. Central Time

Assignment

Summary

Write Java code to determine the state of a tic-tac-toe board and write tests that validate the correctness of your code. We will provide the interface for your code, but the design of the implementation is up to you. Try to design and write your code to be as clean and readable as possible.

Background

Tic-tac-toe (https://en.wikipedia.org/wiki/Tic-tac-toe) is a paper-and-pencil game for two players, X and O, who take turns marking the spaces in a 3x3 grid with their mark. Player X is the first to make a mark. Once a space has been marked, it cannot be marked again. The player who succeeds in placing three of their marks in a horizontal, vertical, or diagonal row wins the game, and the game is over (i.e., no further actions occur).

Specification

The provided TicTacToeBoard class interface has a constructor that expects a description of the state of a tic-tac-toe board in the form of a Java String. This String should consist of 9 characters, one for each position of the board. The characters are ordered in groups of three characters (left-to-right) specifying top, middle, and then bottom horizontals, as shown in Figure 1. The String is case-insensitive. Squares marked by player X are specified with an ‘x’ or ‘X’ and squares marked by player O are specified with an ‘o’ or ‘O’. Any other character is considered to be an empty square. Figure 2 shows what a board specified as “o-XxxoO.z” would look like.


                   0 | 1 | 2
                   ---------
 "012345678"  ->   3 | 4 | 5
                   ---------
                   6 | 7 | 8

Figure 1. The mapping from Strings to positions in the Tic Tac Toe board.

 O |   | X
 ---------
 X | X | O
 ---------
 O |   |

Figure 2. The above Tic Tac Toe board could be described as: o-XxxoO.z

Your implementation of evaluate should analyze the state of the specified board and return one of four Evaluation values. The values are defined as a Java enum type in Evaluation.java. If you aren’t familiar with enums in Java, there are a lot of good references on the Internet; it isn’t that difficult of a concept.

If the argument describes a board state, but one that is not reachable by playing a game of tic-tac-toe, then your code should return UnreachableState. If the function’s argument describes a valid, reachable board state, then it should return Xwins, Owins, or NoWinner if the board is in a state where X has won, where O has won, or where no one has won, respectively.

If the argument passed in the constructor doesn’t correctly describe a board, you should throw an IllegalArgumentException.

Your repository

Use the following link to create your own copy of the TicTacToe repository on GitHub:

https://classroom.github.com/a/DpSFSOJ7

In IntelliJ, create a new project using the following menu command:

File -> New -> Project From Version Control -> GitHub

A dialog should pop up. Select the appropriate repo from the list labeled “Git Repository URL”. Click the “clone” button. Since the version of Java you are using might be different than the one I used to create the project, you might need change the Project SDK using the menu command below. Select a Project SDK that you have installed that is Java 1.8 or greater. For some of you a pop-up might appear asking you to choose a different Project SDK. Regardless, the update your file structure navigate to:

File -> Project Structure

To commit your work, use the following command. Write a useful commit message, and be sure to push your work to GitHub.

VCS -> Commit

Be sure to frequently commit your changes. When writing code, you should break your work into lots of little pieces (15-60 minutes of effort). Your work cycle should be to: 1) pick the next piece that you can implement, 2) implement it, 3) debug it until you are confident that it works, and 4) commit and push it. That way, if anything happens, you never lose more than a small amount of work. Part of your grade on code review assignments will be based on progressively committing your code. Note: if your code is broken and not compiling, you probably want to get it working before committing.

Flexibility

You should design your code in a way that is extensible to different board sizes. In other words, try to minimize the amount of code that would need to be changed if we wanted to evaluate boards for some other than 3.

Testing

The primary motivation for this assignment is to give you a moderately complicated function for which to write black box tests. Following a test-first philosophy, we’re going to ask you to write your tests before writing your code. More precisely, you should have tests checked in to the repository before you have code.

Your tests should be implemented in the provided TicTacToeTest class using Junit4. Each assert should be in a separate test. Name your tests with meaningful names. For most tests, no comments are necessary, because the name of the test is sufficiently explanatory. Write enough tests to give yourself confidence that your implementation will be correct if it passes all of the tests. Exhaustive testing is untenable, as each of the nine positions of the board can be X, O, or blank, leading to 39 (over 19,000) board configurations.

While testing is a key concept in this course and we expect tests where possible in all assignments, in this particular assignment it is the focus. This means that in this assignment, we consider your tests to be the same as your code. That is, you should not share them with each other before code review.

Design and Style

We are using the Google Java Style Guide for the Java code that we write in CS 126. For this assignment, the most important sections to read are for Formatting, Naming, and Javadoc (see the URL below). However, you should at least skim through the entire style guide to get a good grasp of other style conventions for later assignments.

You should follow the style guide as closely as possible to write readable, professional-looking code. Remember - you are writing code not just for yourself, but for others!

https://google.github.io/styleguide/javaguide.html

Submitting the assignment

After pushing your code to GitHub, you will need to submit your code to Gradescope. Please see the course info page for signing up for Gradescope.

Remember that committing your code is different from pushing your code. Committing your code saves the changes you made, and ideally you will be committing frequently based on small units of progress (e.g. implementing a function). However, those commits will only be on your local computer and not on GitHub until you push them - then, the changes you made on your local computer will show up in GitHub.

To actually submit the code to be graded, you must submit to Gradescope after pushing to GitHub. Double check that the code submitted to Gradescope is the code you actually want to submit - even if you make changes on your computer, they won't show up in Gradescope if you didn't commit and push to GitHub first.

Assignment Rubric

Note that this rubric is not a comprehensive checklist; it’d be impossible to list out every single thing that you should be considering while writing your code.

Click here to view

Readability and flexibility of code

  • Modularity: each method should perform one distinct task
  • It should be easy to read through each method, follow its control flow, and verify its correctness
  • The code should be flexible/ready for change (no magic numbers, no violations of DRY)

Object decomposition

  • Member variables stored by each class
    • Classes should store their data using the most intuitive data structure
    • No "missing" member variables
    • No member variables which should be local variables
    • No redundancy / storing multiple copies of the same data in different formats
  • Encapsulation
    • Appropriate access modifiers
    • Member variables should generally only modified by member functions in the same class
    • The interface of a class should be intuitive/abstract, and external code should only interact with the class via the interface
      • By intuitive, we mean that it should be easy to understand and use the class, and there shouldn’t be any hidden assumptions about how the class should be used
      • By abstract, we mean that an external client shouldn’t need to worry about the internal details of the class
    • No unnecessary getters/setters
    • In Java, getters should not return a mutable member variable

Documentation

  • Specifications
    • Specifications are required for all functions which are part of the public interface of a class
    • Specifications should precisely describe the inputs and outputs of a function, and should also describe what the function does (e.g. mutating state of object)
    • Specifications should also be formatted properly (e.g. follow Javadoc style for Java assignments)
  • Inline comments should not describe things which are obvious from the code, and should describe things which need clarification

Naming

  • Semantics: names should effectively describe the entities they represent; they should be unambiguous and leave no potential for misinterpretation. However, they should not be too verbose.
  • Style: names should follow the Google Java/C++ Style Guide

Layout

  • Spacing should be readable and consistent; your code should look professional
    • Vertical whitespace should be meaningful
      • Vertical whitespace can help create paragraphs
      • Having 2+ empty lines in a row, or empty lines at the beginning or end of files, is usually a waste of space and looks inconsistent
    • Horizontal whitespace should be present where required by the Google Style Guide
  • Lines should all be under 100 characters; no horizontal scrolling should be necessary

Testing

  • You should make sure all types of inputs and outputs are tested.
    • If category A of inputs is likely to cause different behavior than category B, then you should test inputs from both categories
  • Boundary/edge cases often cause different/unexpected behavior, and thus, they should be tested
  • Your tests should cover all of the functionality that you’ve implemented. In other words, every line of code should be exercised by some test case, unless the assignment documentation says otherwise
  • Each individual test case should only serve one coherent purpose. Individual test cases should not have assertions testing unrelated things
  • Your tests, like your code, should be organized and easy to understand. This includes:
    • Easy to verify thoroughness / all possibilities covered
    • Easy to verify the correctness of each test case
    • Clear categories of test cases, where similar tests are grouped together
      • In Java, this can be accomplished by inserting comments to separate groups
    • Test case names make the purpose of each test case clear
      • Here is one possible way to name test methods in JUnit

Process

  • Commit modularity
    • Code should be checked-in periodically/progressively in logical chunks
    • Unrelated changes should not be bundled in the same commit
  • Commit messages
    • Should concisely and accurately describe the changes made
    • Should have a consistent style and look professional
      • First word of the message should be a verb, and it should be capitalized

Presentation

  • Arrived on time with all necessary materials and ready to go
  • Good selection of topics to focus on
  • Logical order of presentation
  • Appropriate pacing and engagement of the fellow students
  • Speaking loud enough and enunciating clearly

Participation

  • Each student should contribute at least one meaningful comment or question for every other student who presents in his/her code review
  • Students must behave respectfully to moderator and other students

Weightings

Your grades for each section of the rubric will be weighted as follows:

  • Readability and flexibility of code (15%)
  • Object decomposition (5%)
  • Documentation (5%)
  • Naming (12.5%)
  • Layout (12.5%)
  • Testing (30%)
  • Process (10%)
  • Presentation (5%)
  • Participation (5%)