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

C++ TicTacToe

Assigned: 2020-03-04
Due Date: 2020-03-10 by 11:59PM U.S. Central Time

There are only two kinds of languages: the ones people complain about and the ones nobody uses.

— Bjarne Stroustrup, creator of C++

Goals

Getting Started

Get your copy of the assignment here: https://classroom.github.com/a/XH6IX_3a

The rubric can be found here.

Gradescope

You will need to submit your GitHub repository to Gradescope. There is a linter which is run on each submission; the results of the linter will be viewable by your code moderator when grading.

Assignment Spec

IDE

For the C++ assignments this semester, we will be using the JetBrains C++ IDE: CLion. Unlike IntelliJ, there is no free version of CLion; however, you can apply for a student pack and download it free of charge. This application typically resolves in no more than a few minutes. Visit this link and use your Illinois email address. Once you verify by email, you should be able to log in to your JetBrains account, and download CLion. Make a private post on Piazza if you need help with this.

Windows Users

You'll need to install MSBuild Tools. Then, follow the guide here.

Design and Style

You should be able to incorporate style feedback points from the feedback you got on the first week's assignment. However, since we're on a new language, there are some new style guidelines to follow. We follow the Google C++ Style Guide, which we encourage you to skim through before writing your code. We will be rigorously following this style guide. This includes an 80 character line limit and 2 space indents.

Also, set up IDE formatting before starting the assignment. You can find instructions here: https://www.jetbrains.com/help/clion/clangformat-as-alternative-formatter.html#enable-manually. We will be using cpplint to lint submissions on Gradescope. Most of the warnings outputted are correct, though due to different environments (local vs Gradescope), some of the warnings may not apply to your code when submitting to Gradescope.

C++

C++ is a semi-object oriented language, and is somewhat similar to Java, except that it derives from C and has different memory management and compilation processes, amongst other things. We teach C++ for the latter half of this class because you will soon be taking CS 225, a class taught entirely in C++.

This assignment focuses on strings, so learning a bit about the C++ std::string object will be useful.

Another important thing to note: C++ does not have a concept of null references/objects like Java does. The only thing that can be "null" in C++ is a pointer, which we have not yet covered in depth. For example, this Java code compiles just fine:

String moderatorName = null;

The above code compiles just fine. The following C++ code will not:

std::string moderator_name = NULL; // Error!
std::string moderator_name = nullptr; // Equally bad!

It is up to you to figure out how to design your code around this restriction.

C++ Header Files

A "header" in C++ is a file that contains a list of variable/method declarations. It provides a single place for the pre-processor to remember what signature a method should have, so when it's defined, it can ensure that it matches. Here's an example header file:

// File name: moderator.h

#ifndef MODERATOR_H_
#define MODERATOR_H_

#include <string>

namespace cs126 {

std::string[] students;

int GradeStudent(std::string studentNetId);
void EncourageStudents();
bool AttendPizzaParty(int requestedSlices);

}  // namespace cs126

#endif // MODERATOR_H_

And an example implementation of it:

// File name: moderator.cc

#include <iostream>

#include "moderator.h"


using std::cout;
using std::endl;

const int kMaxPizzaSlices = 3;

namespace cs126 {

int GradeStudent(string studentNetId) {
  return 100;
}

void EncourageStudents() {
  cout << "You can do it!" << endl;
}

bool AttendPizzaParty(int requestedSlices) {
  return requested_slices <= kMaxPizzaSlices;
}

}  // namespace cs126

Some important things to note:

  1. The source file (moderator.cc) includes the header file, not the other way around.
  2. The header file has inclusion guards (the #ifndef, #define, and #endif lines -- you may also see #pragma once). These prevent the header file from being preprocessed more than once, which would lead to compiler errors.

This is the intuition you should remember regarding header files:

  1. You must tell the compiler that a thing exists with a header file. In the above example, we tell the compiler about a function called GradeStudent that takes in a string and returns an int.
  2. Then, you must tell the compiler how that thing works with an implementation in a .cc file. In this case, we provide the compiler with the definition of the function we declared earlier, so that when other parts of the codebase try to use the function declared in the .h file, the compiler knows how that function actually works.

Repeated again, but even more simply:

  1. .h/.hpp files say "this thing exists, and this is what I say it looks like" to the compiler
  2. .cc/.cpp files say "here's how this thing that I said exists actually functions" to the compiler

You must have both in order for your code to compile!

Specification

The provided function signature expects a description of the state of a tic-tac-toe board in the form of a std::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 bottom horizontals, as shown below:


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

The string is case-insensitive. Squares marked by player X are specified with an x or X, and squares marked by player O are marked with an o or O. Any other character is considered to be an empty square. For example, "o-XxxoO.z" describes this board:

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

Your implementation of EvaluateBoard should analyze the state of the specified board and return one of five Evaluation values. The values should be defined as a c++ enum. If you aren't familiar with C++ enums, here is a good reference to get started.

If the argument passed to the function doesn't correctly describe a board, your code should return InvalidInput. 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.

Testing

Much like in the original assignment, this assignment has an emphasis on writing unit tests. Again, you should commit your tests first before implementing any code.

Your tests should be written using the Catch2 testing framework, in the tests/test-tictactoe.cc file. For this assignment, each assert should be in a separate test, since they are all independent test cases.

To run your tests, select the test-tictactoe configuration from the dropdown next to the run button.

To learn more about Catch2, check out this tutorial.