CS253 HW5: Game Class                
Changes                
One of the Requirements states “Calling .add_dict()
before .set_length()
calling results in undefined behavior.” This is poor grammar (extra “calling”) and
silly, since the description for .set_length()
says that the default length is 5,
so there should be no problem calling .add_dict()
without ever calling .set_length()
.
However, the Requirement stands: it’s undefined behavior, so we won’t test it, and your code
may do anything for this case, including complaining, failing, or working as expected.
                
Description                
Delighted at your work in HW3, management has asked you to
convert it to a reusable class called Game
that does the hard
work of the word-guessing game.
This is a library, not a complete program.
                
Methods                
Game
must have the following public methods:                
- default constructor
-
The default ctor creates an empty
Game
.
- Copy constructor
-
- Assignment operator
-
Copy all information from another object of the same class.
- Destructor
-
Destroy.
-
.set_length(size_t)
-
Set the length of the desired target. The default is 5.
-
.add_dict(string path)
-
Add the words in the given dictionary file to this object. You may
assume that the file contains one word per line, all lower case. The
words in the file may be of any length. Throw a descriptive
invalid_argument containing the path if the file cannot be opened
for reading.
-
.set_good(string)
-
Set the “good” string, to be shown when a character is in the right
place. Default value is “
=
”.
-
.set_wrong(string)
-
Set the “wrong” string, to be shown when a character is not in the
right place, but occurs somewhere else in the target. Default value
is “
-
”.
-
.set_bad(string)
-
Set the “bad” string, to be shown when a character doesn’t appear
anywhere in the target. Default value is a space.
-
.select_target()
-
Choose & return a random word, from the accumulated dictionaries,
of the selected length, to serve as a goal.
Throw a descriptive length_error, with the desired length in the
message, if no words of the desired length are present in the
accumulated dictionaries.
To select a random word from a vector of words,
#include <random>
, and do this:
random_device rd;
return words[rd() % words.size()];
-
.contains(string word)
-
Return true iff the accumulated dictionaries
contain the given word.
-
.feedback(string guess)
-
Return the feedback string for the given guess. For example, if the
target word is “sigma”, the guess is “omega“, and none of
.set_good()
, .set_wrong()
, or .set_bad()
, have been
called, then the value " - -="
is returned.
The types and names in the method descriptions, above, do not
determine the C++ declarations of those methods. They only serve to
informally describe what sort of arguments a method might take.
You might pass certain arguments by reference, use const, declare
return types, etc.
                
Const-correctness, for arguments, methods, and operators, is your job.
For example, it must be possible to call .contains()
on a const
object, or to copy a const object to a non-const object.
                
You may define other methods or data, public or private, as you see fit.
You may define other classes, as you see fit. However, to use the
Game
class, the user need only #include "Game.h"
, not
any other header files.
                
Debugging                
If you encounter “STACK FRAME LINK OVERFLOW”, then try this:
export STACK_FRAME_LINK_OVERRIDE=ffff-ad921d60486366258809553a3db49a4a
Libraries                
libhw5.a
is a library file. It contains a number of
*.o
(object) files. It must contain Game.o
, but it may also
contain whatever other *.o
files you need. The CMakeLists.txt
shown creates libhw5.a
. It does not contain main().
                
To be explicit, the provided CMakeLists.txt
does:
- creates
Game.o
by compiling Game.cc
- creates a library
libhw5.a
from Game.o
- creates
test.o
by compiling test.cc
- creates an executable called
test
by linking test.o
with libhw5.a
.
The tar file must contain at least all the files required to do this.
                
Testing                
You will have to write a main() function to test your code. Put it in a
separate file, and do not make it part of libhw5.a
.
Particularly, do not put main() in Game.h
or Game.cc
. You
will also have to create Game.h
, and put it into hw5.tar
.
We will test your program by doing something like this:
                
mkdir a-new-directory
cd the-new-directory
tar -x </some/where/else/hw5.tar
cmake . && make
cp /some/other/place/test-program.cc .
g++ -Wall -std=c++17 test-program.cc libhw5.a
./a.out
We will supply a main program to do the testing that we want. You
should do something similar. It’s your choice whether to include your
test program in your hw5.tar
file.
However, cmake . && make
must work. If it fails because you
didn’t package test.cc
, but your CMakeLists.txt
requires
test.cc
, then your build failed, and you get no points.
Test your tar file, not just your code.
                
This is the Colorado State University CS253 web page
https://cs.colostate.edu/~cs253/Fall22/HW5
fetched by unknown <unknown> with Linux UID 65535
at 2024-08-30T16:18:17 from IP address 18.117.184.133.
Registered CSU students are permitted to copy this web page for personal
use, but it is forbidden to repost the information from this web page to the
internet. Doing so is a violation of the rules in the CS253 syllabus,
will be considered cheating, and will get you an F in CS253.
Sample Run                
Here is a sample run, where %
is my shell prompt:
                
% cat CMakeLists.txt
cmake_minimum_required(VERSION 3.11)
project(hw5)
# Are we in the wrong directory?
if (CMAKE_SOURCE_DIR MATCHES "[Hh][Ww]([0-9])$")
if (NOT PROJECT_NAME MATCHES "${CMAKE_MATCH_1}$")
message(FATAL_ERROR "Building ${PROJECT_NAME} in ${CMAKE_SOURCE_DIR}")
endif()
endif()
# Using -Wall is required:
add_compile_options(-Wall)
# These compile flags are highly recommended, but not required:
add_compile_options(-Wextra -Wpedantic)
# Optional super-strict mode:
add_compile_options(-fmessage-length=80 -fno-diagnostics-show-option
-fstack-protector-all -g -O3 -std=c++17 -Walloc-zero -Walloca
-Wconversion -Wctor-dtor-privacy -Wduplicated-cond
-Wduplicated-branches -Werror -Wextra-semi -Wfatal-errors
-Winit-self -Wlogical-op -Wold-style-cast -Wshadow
-Wunused-const-variable=1 -Wzero-as-null-pointer-constant)
# add_compile_options must be BEFORE add_executable.
# Create the executable from the source file main.cc:
add_library(${PROJECT_NAME} Game.cc)
add_executable(test test.cc)
target_link_libraries(test ${PROJECT_NAME})
# Create a tar file every time:
add_custom_target(${PROJECT_NAME}.tar ALL COMMAND
tar -cf ${PROJECT_NAME}.tar *.cc *.h CMakeLists.txt)
% cmake . && make
… cmake output appears here …
… make output appears here …
% cat test.cc
#include "Game.h"
#include <iostream>
using namespace std;
int main(/* int argc, char *argv[] */) {
//
// Instead of hard-coding all the values here, you could
// adapt your main() from HW3, with all the getopt() processing.
// That way, you can easily test with 177777 different values,
// different files, etc.
//
Game g;
g.set_good("✓"); g.set_wrong("~"); g.set_bad(".");
g.set_length(5);
g.add_dict("/dev/null");
g.add_dict("words.txt");
g.add_dict("/dev/null");
const auto &target = g.select_target();
cout << "Guess the " << target.size() << "-letter word.\n";
for (int count=1; count<=6; ++count) {
cout << "Guess #" << count << ": ";
if (string guess; !getline(cin, guess)) // end game on end-of-file
break;
else if (guess.size() != target.size())
cout << "“" << guess << "” isn’t length " << target.size() << ".\n";
else if (!g.contains(guess))
cout << "“" << guess << "” isn’t in any dictionary.\n";
else {
cout << " " << g.feedback(guess) << "\n";
if (guess == target) {
cout << "You won!\n";
return 0;
}
}
}
cout << "You lost, the word was “" << target << "”.\n";
return 1;
}
% ./test
./test
Guess the 5-letter word.
Guess #1: arose
~✓...
Guess #2: until
.....
Guess #3: hyped
.~...
Guess #4: crazy
✓✓✓✓✓
You won!
Requirements                
- You must use random_device, as shown above, to select the
target word.
- Calling
.add_dict()
before .set_length()
calling results
in undefined behavior.
- Calling
.feedback()
before calling .select_target()
results
in undefined behavior.
- It must be an compile-time error or warning to ignore the return value
of
.contains()
or feedback()
.
- You may not have any
using namespace
declarations in your
header (*.h
) files.
- All header files must contain #include guards.
- All copies (copy ctor, assignment operator) are “deep”.
Do not share data between copies—that’s not making a copy.
- You may not use any external programs. You may not use system(),
fork(), popen(), execl(), execvp(), etc.
- You may not use C-style I/O, such as printf(), scanf(), fopen(),
and getchar().
- You may not use endl. Use flush if needed.
- You may not use dynamic memory via new, delete, malloc(),
calloc(), realloc(), free(), strdup(), etc.
- It’s ok to implicitly use dynamic memory via containers such as
string or vector.
- You may not use the .eof() method.
- No global variables.
- For readability, don’t use ASCII int constants (
65
) instead of
char constants ('A'
) for printable characters.
- We will compile your code like this:
cmake . && make
- If that generates warnings, you will lose a point.
- If that generates errors, you will lose all points.
- There is no automated testing/pre-grading/re-grading.
- Test your code yourself. It’s your job.
- Even if you only change it a little bit.
- Even if all you do is add a comment.
- Test with the CSU compilers, not just your laptop’s compiler.
If you have any questions about the requirements, ask.
In the real world, your programming tasks will almost always be
vague and incompletely specified. Same here.
                
Tar file                
- The tar file for this assignment must be called:
hw5.tar
- It must contain:
- source files (
*.cc
), including Game.cc
- header files (
*.h
), including Game.h
CMakeLists.txt
, which will create the library file
libhw5.a
.
- These commands must produce the library lib
hw5.a
:
cmake . && make
- Your
CMakeLists.txt
must use at least -Wall
when compiling.
How to submit your work:                
In Canvas, check in the
file
hw5.tar
to the assignment “HW5”.
It’s due 11:59ᴘᴍ MT Saturday, with a 24-hour late period for a 25% penalty.
                
How to receive negative points:                
Turn in someone else’s work.