This commit is contained in:
Love 2024-09-11 17:32:59 +02:00
commit b9b11d401e
33 changed files with 5935 additions and 0 deletions

12
.gitignore vendored Executable file
View File

@ -0,0 +1,12 @@
*~
.DS_Store
*.pro.user.*
*.pro.user
build-*/
*.app
*.exe
build

60
Boggle.pro Executable file
View File

@ -0,0 +1,60 @@
TEMPLATE = app
CONFIG += console
# Make sure we do not accidentally #include files placed in 'resources'
CONFIG += no_include_pwd
# Do not create an app bundle when running on OS X
#CONFIG -= app_bundle
SOURCES = $$PWD/src/*.cpp
SOURCES += $$PWD/lib/StanfordCPPLib/*.cpp
HEADERS = $$PWD/src/*.h
HEADERS += $$PWD/lib/StanfordCPPLib/*.h
# GCC defaults to not warning about failing to return from a non-void function
# We enable this warning manually, since Clang warns by default
QMAKE_CXXFLAGS += -std=c++11 -Wreturn-type
INCLUDEPATH += $$PWD/lib/StanfordCPPLib/
# Copies the given files to the destination directory
# The rest of this file defines how to copy the resources folder
defineTest(copyToDestdir) {
files = $$1
for(FILE, files) {
DDIR = $$OUT_PWD
# Replace slashes in paths with backslashes for Windows
win32:FILE ~= s,/,\\,g
win32:DDIR ~= s,/,\\,g
!win32 {
copyResources.commands += cp -r '"'$$FILE'"' '"'$$DDIR'"' $$escape_expand(\\n\\t)
}
win32 {
copyResources.commands += xcopy '"'$$FILE'"' '"'$$DDIR'"' /e /y $$escape_expand(\\n\\t)
}
}
export(copyResources.commands)
}
!win32 {
copyToDestdir($$files($$PWD/res/*))
copyToDestdir($$files($$PWD/lib/*.jar))
}
win32 {
copyToDestdir($$PWD/res)
copyToDestdir($$PWD/lib/*.jar)
}
copyResources.input = $$files($$PWD/res/*)
OTHER_FILES = $$files(res/*)
QMAKE_EXTRA_TARGETS += copyResources
POST_TARGETDEPS += copyResources
macx {
cache()
}

42
lib/StanfordCPPLib/error.cpp Executable file
View File

@ -0,0 +1,42 @@
/*
* File: error.cpp
* ---------------
* Implementation of the error function.
*/
#include <exception>
#include <string>
#include <iostream>
#include "error.h"
using namespace std;
/* Definitions for the ErrorException class */
ErrorException::ErrorException(string msg) {
this->msg = msg;
}
ErrorException::~ErrorException() throw () {
/* Empty */
}
string ErrorException::getMessage() const {
return msg;
}
const char *ErrorException::what() const throw () {
return msg.c_str();
}
/*
* Implementation notes: error
* ---------------------------
* Earlier implementations of error made it possible, at least on the
* Macintosh, to help the debugger generate a backtrace at the point
* of the error. Unfortunately, doing so is no longer possible if
* the errors are catchable.
*/
void error(string msg) {
throw ErrorException(msg);
}

56
lib/StanfordCPPLib/error.h Executable file
View File

@ -0,0 +1,56 @@
/*
* File: error.h
* -------------
* This file defines the <code>ErrorException</code> class and the
* <code>error</code> function.
*/
#ifndef _error_h
#define _error_h
#include <string>
#include <exception>
/*
* Class: ErrorException
* ---------------------
* This exception is thrown by calls to the <code>error</code>
* function. Typical code for catching errors looks like this:
*
*<pre>
* try {
* ... code in which an error might occur ...
* } catch (ErrorException & ex) {
* ... code to handle the error condition ...
* }
*</pre>
*
* If an <code>ErrorException</code> is thrown at any point in the
* range of the <code>try</code> (including in functions called from
* that code), control will jump immediately to the error handler.
*/
class ErrorException : public std::exception {
public:
ErrorException(std::string msg);
virtual ~ErrorException() throw ();
virtual std::string getMessage() const;
virtual const char *what() const throw ();
private:
std::string msg;
};
/*
* Function: error
* Usage: error(msg);
* ------------------
* Signals an error condition in a program by throwing an
* <code>ErrorException</code> with the specified message.
*/
void error(std::string msg);
#include "private/main.h"
#endif

217
lib/StanfordCPPLib/foreach.h Executable file
View File

@ -0,0 +1,217 @@
/*
* File: foreach.h
* ---------------
* This file defines the <code>foreach</code> keyword, which implements
* a substitute for the range-based <code>for</code> loop from C++11.
* All iterable classes in the Stanford libraries import this file, so
* clients don't ordinarily need to do so explicitly. This version of
* <code>foreach</code> also supports C++ strings and arrays.
*/
#ifndef _foreach_h
#define _foreach_h
/*
* Statement: foreach
* Usage: foreach (type var in collection) { ... }
* -----------------------------------------------
* The <code>foreach</code> statement steps through the elements in
* a collection. It works correctly with the collection classes in
* both the Standard Template Library and the Stanford C++ libraries,
* but can also be used with C++ strings and statically initialized
* arrays.
*
* <p>The following code, for example, prints every element in the
* string vector <code>lines</code>:
*
*<pre>
* foreach (string str in lines) {
* cout &lt;&lt; str &lt;&lt; endl;
* }
*</pre>
*
* Similarly, the following function calculates the sum of the character
* codes in a string:
*
*<pre>
* int sumCharacterCodes(string str) {
* int sum = 0;
* foreach (char ch in str) sum += ch;
* return sum;
* }
*</pre>
*
* As a simplification when iterating over maps, the <code>foreach</code>
* macro iterates through the keys rather than the key/value pairs.
*/
/* Private section */
/**********************************************************************/
/* Note: Everything below this point in the file is logically part */
/* of the implementation and should not be of interest to clients. */
/**********************************************************************/
#include <iterator>
#include <map>
#include <cstddef>
#include <cstring>
/* These #includes are for files that contain "in" as a token */
#include <ios>
#include <fstream>
#include <sstream>
using namespace std;
/* Redefine the ios constants (one of which is "in") */
static const ios::openmode IOS_APP = ios::app;
static const ios::openmode IOS_ATE = ios::ate;
static const ios::openmode IOS_BINARY = ios::binary;
static const ios::openmode IOS_IN = ios::in;
static const ios::openmode IOS_OUT = ios::out;
static const ios::openmode IOS_TRUNC = ios::trunc;
/* Private implementation namespace */
namespace _fe {
struct Range {
virtual ~Range() { };
};
template <typename T>
struct ArrayRange : Range {
ArrayRange(const T *begin, const T *end) : iter(begin), end(end) { }
const T *iter;
const T *end;
};
template <typename CType>
struct CRange : Range {
CRange(const CType& c) :
cont(c), iter(cont.begin()), end(cont.end()) { }
CType cont;
typename CType::iterator iter, end;
};
template <typename KT, typename VT, typename CT, typename AT>
struct MapRange : Range {
MapRange(const map<KT,VT,CT,AT> & c) :
cont(c), iter(cont.begin()), end(cont.end()) { }
map<KT,VT,CT,AT> cont;
typename map<KT,VT,CT,AT>::iterator iter, end;
};
/*
* The State struct glues together all of these pieces and
* stores all of the information throughout the loops.
*/
struct State {
State() : state(0), itr(NULL) { }
~State() { delete itr; }
int state;
Range *itr;
};
/* General hook function */
template <typename DowncastType, typename ValueType>
ValueType HookImpl(State& fe) {
DowncastType *ip = (DowncastType *) fe.itr;
if (ip->iter == ip->end) {
fe.state = 2;
return ValueType();
}
fe.state = 1;
ValueType vp = *ip->iter; /* Subtle implementation note: */
++ip->iter; /* Using *ip->iter++ here would */
return vp; /* require copying the iterator. */
}
/* Foreach implementation for containers */
template <typename CType>
CRange<CType> *Init(State & fe, const CType & collection) {
fe.itr = new CRange<CType>(collection);
return (CRange<CType>*) fe.itr;
}
template <typename CType>
typename iterator_traits<typename CType::iterator>::value_type
Hook(State & fe, CRange<CType> *) {
return HookImpl<CRange<CType>,
typename iterator_traits<typename CType::iterator>::value_type>(fe);
}
/* For maps */
template <typename K, typename V, typename C, typename A>
MapRange<K,V,C,A> *Init(State & fe, const map<K,V,C,A> & collection) {
fe.itr = new MapRange<K,V,C,A>(collection);
return (MapRange<K,V,C,A>*) fe.itr;
}
template <typename DowncastType, typename ValueType>
ValueType MapHookImpl(State & fe) {
DowncastType *ip = (DowncastType *) fe.itr;
if (ip->iter == ip->end) {
fe.state = 2;
return ValueType();
}
fe.state = 1;
ValueType key = ip->iter->first;
++ip->iter;
return key;
}
template <typename K, typename V, typename C, typename A>
K Hook(State & fe, MapRange<K,V,C,A> *) {
return MapHookImpl<MapRange<K,V,C,A>,K>(fe);
}
/* For C strings */
template <size_t n>
ArrayRange<char> *Init(State & fe, char (&str)[n]) {
fe.itr = new ArrayRange<char>(str, str + strlen(str));
return (ArrayRange<char>*) fe.itr;
}
template <size_t n>
ArrayRange<char> *Init(State & fe, const char (&str)[n]) {
fe.itr = new ArrayRange<char>(str, str + strlen(str));
return (ArrayRange<char>*) fe.itr;
}
/* For arrays */
template <typename T, size_t n>
ArrayRange<T> *Init(State & fe, T (&arr)[n]) {
fe.itr = new ArrayRange<T>(arr, arr + n);
return (ArrayRange<T>*) fe.itr;
}
template <typename T, size_t n>
ArrayRange<T> *Init(State & fe, const T (&arr)[n]) {
fe.itr = new ArrayRange<T>(arr, arr + n);
return (ArrayRange<T>*) fe.itr;
}
template <typename T>
T Hook(State& fe, ArrayRange<T>*) {
return HookImpl<ArrayRange<T>, T>(fe);
}
}
/* The actual foreach and in macros */
#define foreach(arg) \
for (_fe::State _fe; _fe.state < 2; ) \
for (arg)); _fe.state++ == 1; _fe.state = 0)
#define in = _fe::Hook(_fe, _fe.state != 0 ? NULL : _fe::Init(_fe,
#endif

549
lib/StanfordCPPLib/grid.h Executable file
View File

@ -0,0 +1,549 @@
/*
* File: grid.h
* ------------
* This file exports the <code>Grid</code> class, which offers a
* convenient abstraction for representing a two-dimensional array.
*/
#ifndef _grid_h
#define _grid_h
#include <string>
#include <sstream>
#include <vector>
#include <stdexcept>
//#include "strlib.h"
/*
* Class: Grid<ValueType>
* ----------------------
* This class stores an indexed, two-dimensional array. The following code,
* for example, creates an identity matrix of size <code>n</code>, in which
* the elements are 1.0 along the main diagonal and 0.0 everywhere else:
*
*<pre>
* Grid&lt;double&gt; createIdentityMatrix(int n) {
* Grid&lt;double&gt; matrix(n, n);
* for (int i = 0; i &lt; n; i++) {
* matrix[i][i] = 1.0;
* }
* return matrix;
* }
*</pre>
*/
template <typename ValueType>
class Grid {
public:
/* Forward reference */
class GridRow;
class ConstGridRow;
/*
* Constructor: Grid
* Usage: Grid<ValueType> grid;
* Grid<ValueType> grid(nRows, nCols);
* ------------------------------------------
* Initializes a new grid. The second form of the constructor is
* more common and creates a grid with the specified number of rows
* and columns. Each element of the grid is initialized to the
* default value for the type. The default constructor creates an
* empty grid for which the client must call <code>resize</code> to
* set the dimensions.
*/
Grid();
Grid(int nRows, int nCols);
/*
* Destructor: ~Grid
* -----------------
* Frees any heap storage associated with this grid.
*/
virtual ~Grid();
/*
* Method: numRows
* Usage: int nRows = grid.numRows();
* ----------------------------------
* Returns the number of rows in the grid.
*/
int numRows() const;
/*
* Method: numCols
* Usage: int nCols = grid.numCols();
* ----------------------------------
* Returns the number of columns in the grid.
*/
int numCols() const;
/*
* Method: resize
* Usage: grid.resize(nRows, nCols);
* ---------------------------------
* Reinitializes the grid to have the specified number of rows
* and columns. Any previous grid contents are discarded.
*/
void resize(int nRows, int nCols);
/*
* Method: inBounds
* Usage: if (grid.inBounds(row, col)) ...
* ---------------------------------------
* Returns <code>true</code> if the specified row and column position
* is inside the bounds of the grid.
*/
bool inBounds(int row, int col) const;
/*
* Method: get
* Usage: ValueType value = grid.get(row, col);
* --------------------------------------------
* Returns the element at the specified <code>row</code>/<code>col</code>
* position in this grid. This method signals an error if the
* <code>row</code> and <code>col</code> arguments are outside
* the grid boundaries.
*/
ValueType get(int row, int col);
const ValueType & get(int row, int col) const;
/*
* Method: set
* Usage: grid.set(row, col, value);
* ---------------------------------
* Replaces the element at the specified <code>row</code>/<code>col</code>
* location in this grid with a new value. This method signals an error
* if the <code>row</code> and <code>col</code> arguments are outside
* the grid boundaries.
*/
void set(int row, int col, ValueType value);
/*
* Operator: []
* Usage: grid[row][col]
* ----------------------
* Overloads <code>[]</code> to select elements from this grid.
* This extension enables the use of traditional array notation to
* get or set individual elements. This method signals an error if
* the <code>row</code> and <code>col</code> arguments are outside
* the grid boundaries.
*/
GridRow operator[](int row);
const ConstGridRow operator[](int row) const;
/*
* Method: toString
* Usage: string str = grid.toString();
* ------------------------------------
* Converts the grid to a printable string representation.
*/
std::string toString();
/*
* Method: mapAll
* Usage: grid.mapAll(fn);
* -----------------------
* Calls the specified function on each element of the grid. The
* elements are processed in <b><i>row-major order,</i></b> in which
* all the elements of row 0 are processed, followed by the elements
* in row 1, and so on.
*/
void mapAll(void (*fn)(ValueType value)) const;
void mapAll(void (*fn)(const ValueType & value)) const;
template <typename FunctorType>
void mapAll(FunctorType fn) const;
/*
* Additional Grid operations
* --------------------------
* In addition to the methods listed in this interface, the Grid
* class supports the following operations:
*
* - Stream I/O using the << and >> operators
* - Deep copying for the copy constructor and assignment operator
* - Iteration using the range-based for statement and STL iterators
*
* The iteration forms process the grid in row-major order.
*/
/* Private section */
/**********************************************************************/
/* Note: Everything below this point in the file is logically part */
/* of the implementation and should not be of interest to clients. */
/**********************************************************************/
/*
* Implementation notes: Grid data structure
* -----------------------------------------
* The Grid is internally managed as a dynamic array of elements.
* The array itself is one-dimensional, the logical separation into
* rows and columns is done by arithmetic computation. The layout
* is in row-major order, which is to say that the entire first row
* is laid out contiguously, followed by the entire second row,
* and so on.
*/
/* Instance variables */
ValueType *elements; /* A dynamic array of the elements */
int nRows; /* The number of rows in the grid */
int nCols; /* The number of columns in the grid */
/* Private method prototypes */
void checkRange(int row, int col);
/*
* Hidden features
* ---------------
* The remainder of this file consists of the code required to
* support deep copying and iteration. Including these methods
* in the public interface would make that interface more
* difficult to understand for the average client.
*/
/*
* Deep copying support
* --------------------
* This copy constructor and operator= are defined to make a
* deep copy, making it possible to pass/return grids by value
* and assign from one grid to another. The entire contents of
* the grid, including all elements, are copied. Each grid
* element is copied from the original grid to the copy using
* assignment (operator=). Making copies is generally avoided
* because of the expense and thus, grids are typically passed
* by reference, however, when a copy is needed, these operations
* are supported.
*/
void deepCopy(const Grid & grid) {
int n = grid.nRows * grid.nCols;
elements = new ValueType[n];
for (int i = 0; i < n; i++) {
elements[i] = grid.elements[i];
}
nRows = grid.nRows;
nCols = grid.nCols;
}
public:
Grid & operator=(const Grid & src) {
if (this != &src) {
delete[] elements;
deepCopy(src);
}
return *this;
}
Grid(const Grid & src) {
deepCopy(src);
}
/*
* Iterator support
* ----------------
* The classes in the StanfordCPPLib collection implement input
* iterators so that they work symmetrically with respect to the
* corresponding STL classes.
*/
class iterator : public std::iterator<std::input_iterator_tag, ValueType> {
public:
iterator(const Grid *gp, int index) {
this->gp = gp;
this->index = index;
}
iterator(const iterator & it) {
this->gp = it.gp;
this->index = it.index;
}
iterator & operator++() {
index++;
return *this;
}
iterator operator++(int) {
iterator copy(*this);
operator++();
return copy;
}
bool operator==(const iterator & rhs) {
return gp == rhs.gp && index == rhs.index;
}
bool operator!=(const iterator & rhs) {
return !(*this == rhs);
}
ValueType & operator*() {
return gp->elements[index];
}
ValueType *operator->() {
return &gp->elements[index];
}
private:
const Grid *gp;
int index;
};
iterator begin() const {
return iterator(this, 0);
}
iterator end() const {
return iterator(this, nRows * nCols);
}
/*
* Private class: Grid<ValType>::GridRow
* -------------------------------------
* This section of the code defines a nested class within the Grid template
* that makes it possible to use traditional subscripting on Grid values.
*/
class GridRow {
public:
GridRow() {
/* Empty */
}
ValueType & operator[](int col) {
if (!gp->inBounds(row, col)) {
throw std::out_of_range("Grid index values out of range");
}
return gp->elements[(row * gp->nCols) + col];
}
ValueType operator[](int col) const {
if (!gp->inBounds(row, col)) {
throw std::out_of_range("Grid index values out of range");
}
return gp->elements[(row * gp->nCols) + col];
}
private:
GridRow(Grid *gridRef, int index) {
gp = gridRef;
row = index;
}
Grid *gp;
int row;
friend class Grid;
};
friend class ConstGridRow;
/*
* Private class: Grid<ValType>::ConstGridRow
* -------------------------------------
* This section of the code defines a nested class within the Grid template
* that makes it possible to use traditional subscripting on Grid values for
* const versions of the Grid.
*/
class ConstGridRow {
public:
ConstGridRow() {
/* Empty */
}
ValueType operator[](int col) const {
if (!gp->inBounds(row, col)) {
throw std::out_of_range("Grid index values out of range");
}
return gp->elements[(row * gp->nCols) + col];
}
private:
ConstGridRow(const Grid *gridRef, int index) {
gp = gridRef;
row = index;
}
const Grid *gp;
int row;
friend class Grid;
};
friend class GridRow;
};
template <typename ValueType>
Grid<ValueType>::Grid() {
elements = NULL;
nRows = 0;
nCols = 0;
}
template <typename ValueType>
Grid<ValueType>::Grid(int nRows, int nCols) {
elements = NULL;
resize(nRows, nCols);
}
template <typename ValueType>
Grid<ValueType>::~Grid() {
if (elements != NULL) delete[] elements;
}
template <typename ValueType>
int Grid<ValueType>::numRows() const {
return nRows;
}
template <typename ValueType>
int Grid<ValueType>::numCols() const {
return nCols;
}
template <typename ValueType>
void Grid<ValueType>::resize(int nRows, int nCols) {
if (nRows < 0 || nCols < 0) {
throw std::invalid_argument("Attempt to resize grid to invalid size ("
+ std::to_string(nRows) + ", "
+ std::to_string(nCols) + ")");
}
if (elements != NULL) delete[] elements;
this->nRows = nRows;
this->nCols = nCols;
elements = new ValueType[nRows * nCols];
ValueType value = ValueType();
for (int i = 0; i < nRows * nCols; i++) {
elements[i] = value;
}
}
template <typename ValueType>
bool Grid<ValueType>::inBounds(int row, int col) const {
return row >= 0 && col >= 0 && row < nRows && col < nCols;
}
template <typename ValueType>
ValueType Grid<ValueType>::get(int row, int col) {
if (!inBounds(row, col)) throw std::out_of_range("get: Grid indices out of bounds");
return elements[(row * nCols) + col];
}
template <typename ValueType>
const ValueType & Grid<ValueType>::get(int row, int col) const {
if (!inBounds(row, col)) throw std::out_of_range("get: Grid indices out of bounds");
return elements[(row * nCols) + col];
}
template <typename ValueType>
void Grid<ValueType>::set(int row, int col, ValueType value) {
if (!inBounds(row, col)) throw std::out_of_range("set: Grid indices out of bounds");
elements[(row * nCols) + col] = value;
}
template <typename ValueType>
typename Grid<ValueType>::GridRow Grid<ValueType>::operator[](int row) {
return GridRow(this, row);
}
template <typename ValueType>
const typename Grid<ValueType>::ConstGridRow
Grid<ValueType>::operator[](int row) const {
return ConstGridRow(this, row);
}
template <typename ValueType>
void Grid<ValueType>::mapAll(void (*fn)(ValueType value)) const {
for (int i = 0; i < nRows; i++) {
for (int j = 0; j < nCols; j++) {
fn(get(i, j));
}
}
}
template <typename ValueType>
void Grid<ValueType>::mapAll(void (*fn)(const ValueType & value)) const {
for (int i = 0; i < nRows; i++) {
for (int j = 0; j < nCols; j++) {
fn(get(i, j));
}
}
}
template <typename ValueType>
template <typename FunctorType>
void Grid<ValueType>::mapAll(FunctorType fn) const {
for (int i = 0; i < nRows; i++) {
for (int j = 0; j < nCols; j++) {
fn(get(i, j));
}
}
}
template <typename ValueType>
std::string Grid<ValueType>::toString() {
std::ostringstream os;
os << *this;
return os.str();
}
/*
* Implementation notes: << and >>
* -------------------------------
* The insertion and extraction operators use the template facilities in
* strlib.h to read and write generic values in a way that treats strings
* specially.
*/
template <typename ValueType>
std::ostream & operator<<(std::ostream & os, const Grid<ValueType> & grid) {
os << "{";
int nRows = grid.numRows();
int nCols = grid.numCols();
for (int i = 0; i < nRows; i++) {
if (i > 0) os << ", ";
os << "{";
for (int j = 0; j < nCols; j++) {
if (j > 0) os << ", ";
os << grid.get(i, j);
}
os << "}";
}
return os << "}";
}
template <typename ValueType>
std::istream & operator>>(std::istream & is, Grid<ValueType> & grid) {
std::vector<std::vector<ValueType>> vec2d;
is >> vec2d;
int nRows = vec2d.size();
int nCols = (nRows == 0) ? 0 : vec2d[0].size();
grid.resize(nRows, nCols);
for (int i = 0; i < nRows; i++) {
for (int j = 0; j < nCols; j++) {
grid[i][j] = vec2d[i][j];
}
}
return is;
}
#endif

316
lib/StanfordCPPLib/lexicon.cpp Executable file
View File

@ -0,0 +1,316 @@
/*
* File: lexicon.cpp
* -----------------
* A lexicon is a word list. This lexicon is backed by two separate data
* structures for storing the words in the list:
*
* 1) a DAWG (directed acyclic word graph)
* 2) a Set<string> of other words.
*
* Typically the DAWG is used for a large list read from a file in binary
* format. The STL set is for words added piecemeal at runtime.
*
* The DAWG idea comes from an article by Appel & Jacobson, CACM May 1988.
* This lexicon implementation only has the code to load/search the DAWG.
* The DAWG builder code is quite a bit more intricate, see me (Julie)
* if you need it.
*/
#include <fstream>
#include <string>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <stdint.h>
#include "error.h"
#include "lexicon.h"
#include "strlib.h"
using namespace std;
static void toLowerCaseInPlace(string & str);
/*
* The DAWG is stored as an array of edges. Each edge is represented by
* one 32-bit struct. The 5 "letter" bits indicate the character on this
* transition (expressed as integer from 1 to 26), the "accept" bit indicates
* if you accept after appending that char (current path forms word), and the
* "lastEdge" bit marks this as the last edge in a sequence of childeren.
* The bulk of the bits (24) are used for the index within the edge array for
* the children of this node. The children are laid out contiguously in
* alphabetical order. Since we read edges as binary bits from a file in
* a big-endian format, we have to swap the struct order for little-endian
* machines.
*/
Lexicon::Lexicon() {
edges = start = NULL;
numEdges = numDawgWords = 0;
}
Lexicon::Lexicon(string filename) {
edges = start = NULL;
numEdges = numDawgWords = 0;
addWordsFromFile(filename);
}
Lexicon::~Lexicon() {
if (edges) delete[] edges;
}
/*
* Swaps a 4-byte long from big to little endian byte order
*/
static uint32_t my_ntohl(uint32_t arg) {
uint32_t result = ((arg & 0xff000000) >> 24) |
((arg & 0x00ff0000) >> 8) |
((arg & 0x0000ff00) << 8) |
((arg & 0x000000ff) << 24);
return result;
}
/*
* Implementation notes: readBinaryFile
* ------------------------------------
* The binary lexicon file format must follow this pattern:
* DAWG:<startnode index>:<num bytes>:<num bytes block of edge data>
*/
void Lexicon::readBinaryFile(string filename) {
long startIndex, numBytes;
char firstFour[4], expected[] = "DAWG";
ifstream istr(filename.c_str(), IOS_IN | IOS_BINARY);
if (false) my_ntohl(0);
if (istr.fail()) {
error("Couldn't open lexicon file " + filename);
}
istr.read(firstFour, 4);
istr.get();
istr >> startIndex;
istr.get();
istr >> numBytes;
istr.get();
if (istr.fail() || strncmp(firstFour, expected, 4) != 0
|| startIndex < 0 || numBytes < 0) {
error("Improperly formed lexicon file " + filename);
}
numEdges = numBytes/sizeof(Edge);
edges = new Edge[numEdges];
start = &edges[startIndex];
istr.read((char *)edges, numBytes);
if (istr.fail() && !istr.eof()) {
error("Improperly formed lexicon file " + filename);
}
#if defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN
uint32_t *cur = (uint32_t *) edges;
for (int i = 0; i < numEdges; i++, cur++) {
*cur = my_ntohl(*cur);
}
#endif
istr.close();
numDawgWords = countDawgWords(start);
}
int Lexicon::countDawgWords(Edge *ep) const {
int count = 0;
while (true) {
if (ep->accept) count++;
if (ep->children != 0) {
count += countDawgWords(&edges[ep->children]);
}
if (ep->lastEdge) break;
ep++;
}
return count;
}
/*
* Check for DAWG in first 4 to identify as special binary format,
* otherwise assume ASCII, one word per line
*/
void Lexicon::addWordsFromFile(string filename) {
char firstFour[4], expected[] = "DAWG";
ifstream istr(filename.c_str());
if (istr.fail()) {
error("Couldn't open lexicon file " + filename);
}
istr.read(firstFour, 4);
if (strncmp(firstFour, expected, 4) == 0) {
if (otherWords.size() != 0) {
error("Binary files require an empty lexicon");
}
readBinaryFile(filename);
return;
}
istr.seekg(0);
string line;
while (getline(istr, line)) {
add(line);
}
istr.close();
}
int Lexicon::size() const {
return numDawgWords + otherWords.size();
}
bool Lexicon::isEmpty() const {
return size() == 0;
}
void Lexicon::clear() {
if (edges) delete[] edges;
edges = start = NULL;
numEdges = numDawgWords = 0;
otherWords.clear();
}
/*
* Implementation notes: findEdgeForChar
* -------------------------------------
* Iterate over sequence of children to find one that
* matches the given char. Returns NULL if we get to
* last child without finding a match (thus no such
* child edge exists).
*/
Lexicon::Edge *Lexicon::findEdgeForChar(Edge *children, char ch) const {
Edge *curEdge = children;
while (true) {
if (curEdge->letter == charToOrd(ch)) return curEdge;
if (curEdge->lastEdge) return NULL;
curEdge++;
}
}
/*
* Implementation notes: traceToLastEdge
* -------------------------------------
* Given a string, trace out path through the DAWG edge-by-edge.
* If a path exists, return last edge; otherwise return NULL.
*/
Lexicon::Edge *Lexicon::traceToLastEdge(const string & s) const {
if (!start) return NULL;
Edge *curEdge = findEdgeForChar(start, s[0]);
int len = (int) s.length();
for (int i = 1; i < len; i++) {
if (!curEdge || !curEdge->children) return NULL;
curEdge = findEdgeForChar(&edges[curEdge->children], s[i]);
}
return curEdge;
}
bool Lexicon::containsPrefix(string prefix) const {
if (prefix.empty()) return true;
toLowerCaseInPlace(prefix);
if (traceToLastEdge(prefix)) return true;
foreach (string word in otherWords) {
if (startsWith(word, prefix)) return true;
if (prefix < word) return false;
}
return false;
}
bool Lexicon::contains(string word) const {
toLowerCaseInPlace(word);
Edge *lastEdge = traceToLastEdge(word);
if (lastEdge && lastEdge->accept) return true;
return otherWords.contains(word);
}
void Lexicon::add(string word) {
toLowerCaseInPlace(word);
if (!contains(word)) {
otherWords.add(word);
}
}
Lexicon::Lexicon(const Lexicon & src) {
deepCopy(src);
}
Lexicon & Lexicon::operator=(const Lexicon & src) {
if (this != &src) {
if (edges != NULL) delete[] edges;
deepCopy(src);
}
return *this;
}
void Lexicon::deepCopy(const Lexicon & src) {
if (src.edges == NULL) {
edges = NULL;
start = NULL;
} else {
numEdges = src.numEdges;
edges = new Edge[src.numEdges];
memcpy(edges, src.edges, sizeof(Edge)*src.numEdges);
start = edges + (src.start - src.edges);
}
numDawgWords = src.numDawgWords;
otherWords = src.otherWords;
}
void Lexicon::mapAll(void (*fn)(string)) const {
foreach (string word in *this) {
fn(word);
}
}
void Lexicon::mapAll(void (*fn)(const string &)) const {
foreach (string word in *this) {
fn(word);
}
}
void Lexicon::iterator::advanceToNextWordInSet() {
if (setIterator == setEnd) {
currentSetWord = "";
} else {
currentSetWord = *setIterator;
++setIterator;
}
}
void Lexicon::iterator::advanceToNextWordInDawg() {
if (edgePtr == NULL) {
edgePtr = lp->start;
} else {
advanceToNextEdge();
}
while (edgePtr != NULL && !edgePtr->accept) {
advanceToNextEdge();
}
}
void Lexicon::iterator::advanceToNextEdge() {
Edge *ep = edgePtr;
if (ep->children == 0) {
while (ep != NULL && ep->lastEdge) {
if (stack.isEmpty()) {
edgePtr = NULL;
return;
} else {
ep = stack.pop();
currentDawgPrefix.resize(currentDawgPrefix.length() - 1);
}
}
edgePtr = ep + 1;
} else {
stack.push(ep);
currentDawgPrefix.push_back(lp->ordToChar(ep->letter));
edgePtr = &lp->edges[ep->children];
}
};
static void toLowerCaseInPlace(string & str) {
int nChars = str.length();
for (int i = 0; i < nChars; i++) {
str[i] = tolower(str[i]);
}
}

366
lib/StanfordCPPLib/lexicon.h Executable file
View File

@ -0,0 +1,366 @@
/*
* File: lexicon.h
* ---------------
* This file exports the <code>Lexicon</code> class, which is a
* compact structure for storing a list of words.
*/
#ifndef _lexicon_h
#define _lexicon_h
#include <string>
#include "foreach.h"
#include "set.h"
#include "stack.h"
/*
* Class: Lexicon
* --------------
* This class is used to represent a <b><i>lexicon,</i></b> or word list.
* The main difference between a lexicon and a dictionary is that
* a lexicon does not provide any mechanism for storing definitions;
* the lexicon contains only words, with no associated information.
* It is therefore similar to a set of strings, but with a more
* space-efficient internal representation. The <code>Lexicon</code>
* class supports efficient lookup operations for words and prefixes.
*
* <p>As an example of the use of the <code>Lexicon</code> class, the
* following program lists all the two-letter words in the lexicon
* stored in <code>EnglishWords.dat</code>:
*
*<pre>
* int main() {
* Lexicon english("EnglishWords.dat");
* foreach (string word in english) {
* if (word.length() == 2) {
* cout << word << endl;
* }
* }
* return 0;
* }
*</pre>
*/
#include <cctype>
class Lexicon {
public:
/*
* Constructor: Lexicon
* Usage: Lexicon lex;
* Lexicon lex(filename);
* -----------------------------
* Initializes a new lexicon. The default constructor creates an empty
* lexicon. The second form reads in the contents of the lexicon from
* the specified data file. The data file must be in one of two formats:
* (1) a space-efficient precompiled binary format or (2) a text file
* containing one word per line. The Stanford library distribution
* includes a binary lexicon file named <code>English.dat</code>
* containing a list of words in English. The standard code pattern
* to initialize that lexicon looks like this:
*
*<pre>
* Lexicon english("English.dat");
*</pre>
*/
Lexicon();
Lexicon(std::string filename);
/*
* Destructor: ~Lexicon
* --------------------
* The destructor deallocates any storage associated with the lexicon.
*/
virtual ~Lexicon();
/*
* Method: size
* Usage: int n = lex.size();
* --------------------------
* Returns the number of words contained in the lexicon.
*/
int size() const;
/*
* Method: isEmpty
* Usage: if (lex.isEmpty()) ...
* -----------------------------
* Returns <code>true</code> if the lexicon contains no words.
*/
bool isEmpty() const;
/*
* Method: clear
* Usage: lex.clear();
* -------------------
* Removes all words from the lexicon.
*/
void clear();
/*
* Method: add
* Usage: lex.add(word);
* ---------------------
* Adds the specified word to the lexicon.
*/
void add(std::string word);
/*
* Method: addWordsFromFile
* Usage: lex.addWordsFromFile(filename);
* --------------------------------------
* Reads the file and adds all of its words to the lexicon.
*/
void addWordsFromFile(std::string filename);
/*
* Method: contains
* Usage: if (lex.contains(word)) ...
* ----------------------------------
* Returns <code>true</code> if <code>word</code> is contained in the
* lexicon. In the <code>Lexicon</code> class, the case of letters is
* ignored, so "Zoo" is the same as "ZOO" or "zoo".
*/
bool contains(std::string word) const;
/*
* Method: containsPrefix
* Usage: if (lex.containsPrefix(prefix)) ...
* ------------------------------------------
* Returns true if any words in the lexicon begin with <code>prefix</code>.
* Like <code>containsWord</code>, this method ignores the case of letters
* so that "MO" is a prefix of "monkey" or "Monday".
*/
bool containsPrefix(std::string prefix) const;
/*
* Method: mapAll
* Usage: lexicon.mapAll(fn);
* --------------------------
* Calls the specified function on each word in the lexicon.
*/
void mapAll(void (*fn)(std::string)) const;
void mapAll(void (*fn)(const std::string &)) const;
template <typename FunctorType>
void mapAll(FunctorType fn) const;
/*
* Additional Lexicon operations
* -----------------------------
* In addition to the methods listed in this interface, the Lexicon
* class supports the following operations:
*
* - Deep copying for the copy constructor and assignment operator
* - Iteration using the range-based for statement and STL iterators
*
* All iteration is guaranteed to proceed in alphabetical order. All
* words in the lexicon are stored in lowercase.
*/
/* Private section */
/**********************************************************************/
/* Note: Everything below this point in the file is logically part */
/* of the implementation and should not be of interest to clients. */
/**********************************************************************/
private:
#ifdef _WIN32
#define LITTLE_ENDIAN 1
#define BYTE_ORDER LITTLE_ENDIAN
#endif
#pragma pack(1)
struct Edge {
#if defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN
unsigned long letter:5;
unsigned long lastEdge:1;
unsigned long accept:1;
unsigned long unused:1;
unsigned long children:24;
#else
unsigned long children:24;
unsigned long unused:1;
unsigned long accept:1;
unsigned long lastEdge:1;
unsigned long letter:5;
#endif
};
#pragma pack()
Edge *edges, *start;
int numEdges, numDawgWords;
Set<std::string> otherWords;
public:
/*
* Deep copying support
* --------------------
* This copy constructor and operator= are defined to make a
* deep copy, making it possible to pass/return lexicons by value
* and assign from one lexicon to another. The entire contents of
* the lexicon, including all words, are copied. Making copies is
* generally avoided because of the expense and thus, lexicons are
* typically passed by reference. When a copy is needed, these
* operations are supported.
*/
Lexicon(const Lexicon & src);
Lexicon & operator=(const Lexicon & src);
/*
* Iterator support
* ----------------
* The classes in the StanfordCPPLib collection implement input
* iterators so that they work symmetrically with respect to the
* corresponding STL classes.
*/
class iterator : public std::iterator<std::input_iterator_tag,std::string> {
private:
const Lexicon *lp;
int index;
std::string currentDawgPrefix;
std::string currentSetWord;
std::string tmpWord;
Edge *edgePtr;
Stack<Edge *> stack;
Set<std::string>::iterator setIterator;
Set<std::string>::iterator setEnd;
void advanceToNextWordInDawg();
void advanceToNextWordInSet();
void advanceToNextEdge();
public:
iterator() {
this->lp = NULL;
}
iterator(const Lexicon *lp, bool endFlag) {
this->lp = lp;
if (endFlag) {
index = lp->size();
} else {
index = 0;
edgePtr = NULL;
setIterator = lp->otherWords.begin();
setEnd = lp->otherWords.end();
currentDawgPrefix = "";
currentSetWord = "";
advanceToNextWordInDawg();
advanceToNextWordInSet();
}
}
iterator(const iterator & it) {
lp = it.lp;
index = it.index;
currentDawgPrefix = it.currentDawgPrefix;
currentSetWord = it.currentSetWord;
edgePtr = it.edgePtr;
stack = it.stack;
setIterator = it.setIterator;
}
iterator & operator++() {
if (edgePtr == NULL) {
advanceToNextWordInSet();
} else {
if (currentSetWord == "" || currentDawgPrefix < currentSetWord) {
advanceToNextWordInDawg();
} else {
advanceToNextWordInSet();
}
}
index++;
return *this;
}
iterator operator++(int) {
iterator copy(*this);
operator++();
return copy;
}
bool operator==(const iterator & rhs) {
return lp == rhs.lp && index == rhs.index;
}
bool operator!=(const iterator & rhs) {
return !(*this == rhs);
}
std::string operator*() {
if (edgePtr == NULL) return currentSetWord;
if (currentSetWord == "" || currentDawgPrefix < currentSetWord) {
return currentDawgPrefix + lp->ordToChar(edgePtr->letter);
} else {
return currentSetWord;
}
}
std::string *operator->() {
if (edgePtr == NULL) return &currentSetWord;
if (currentSetWord == "" || currentDawgPrefix < currentSetWord) {
tmpWord = currentDawgPrefix + lp->ordToChar(edgePtr->letter);
return &tmpWord;
} else {
return &currentSetWord;
}
}
};
iterator begin() const {
return iterator(this, false);
}
iterator end() const {
return iterator(this, true);
}
private:
Edge *findEdgeForChar(Edge *children, char ch) const;
Edge *traceToLastEdge(const std::string & s) const;
void readBinaryFile(std::string filename);
void deepCopy(const Lexicon & src);
int countDawgWords(Edge *start) const;
unsigned int charToOrd(char ch) const {
return ((unsigned int)(tolower(ch) - 'a' + 1));
}
char ordToChar(unsigned int ord) const {
return ((char)(ord - 1 + 'a'));
}
};
template <typename FunctorType>
void Lexicon::mapAll(FunctorType fn) const {
foreach (std::string word in *this) {
fn(word);
}
}
// hashing functions for lexicons; defined in hashmap.cpp
int hashCode(const Lexicon& l);
#endif

919
lib/StanfordCPPLib/map.h Executable file
View File

@ -0,0 +1,919 @@
/*
* File: map.h
* -----------
* This file exports the template class <code>Map</code>, which
* maintains a collection of <i>key</i>-<i>value</i> pairs.
*/
#ifndef _map_h
#define _map_h
#include <cstdlib>
#include "foreach.h"
#include "stack.h"
#include "vector.h"
/*
* Class: Map<KeyType,ValueType>
* -----------------------------
* This class maintains an association between <b><i>keys</i></b> and
* <b><i>values</i></b>. The types used for keys and values are
* specified using templates, which makes it possible to use
* this structure with any data type.
*/
template <typename KeyType, typename ValueType>
class Map {
public:
/*
* Constructor: Map
* Usage: Map<KeyType,ValueType> map;
* ----------------------------------
* Initializes a new empty map that associates keys and values of the
* specified types.
*/
Map();
/*
* Destructor: ~Map
* ----------------
* Frees any heap storage associated with this map.
*/
virtual ~Map();
/*
* Method: size
* Usage: int nEntries = map.size();
* ---------------------------------
* Returns the number of entries in this map.
*/
int size() const;
/*
* Method: isEmpty
* Usage: if (map.isEmpty()) ...
* -----------------------------
* Returns <code>true</code> if this map contains no entries.
*/
bool isEmpty() const;
/*
* Method: put
* Usage: map.put(key, value);
* ---------------------------
* Associates <code>key</code> with <code>value</code> in this map.
* Any previous value associated with <code>key</code> is replaced
* by the new value.
*/
void put(const KeyType & key, const ValueType & value);
/*
* Method: get
* Usage: ValueType value = map.get(key);
* --------------------------------------
* Returns the value associated with <code>key</code> in this map.
* If <code>key</code> is not found, <code>get</code> returns the
* default value for <code>ValueType</code>.
*/
ValueType get(const KeyType & key) const;
/*
* Method: containsKey
* Usage: if (map.containsKey(key)) ...
* ------------------------------------
* Returns <code>true</code> if there is an entry for <code>key</code>
* in this map.
*/
bool containsKey(const KeyType & key) const;
/*
* Method: remove
* Usage: map.remove(key);
* -----------------------
* Removes any entry for <code>key</code> from this map.
*/
void remove(const KeyType & key);
/*
* Method: clear
* Usage: map.clear();
* -------------------
* Removes all entries from this map.
*/
void clear();
/*
* Method: keys
* Usage: Vector<KeyType> keys = map.keys();
* -------------------------------------------
* Returns a collection containing all keys in this map.
*/
Vector<KeyType> keys() const;
/*
* Method: values
* Usage: Vector<ValueType> values = map.values();
* -------------------------------------------
* Returns a collection containing all values in this map.
*/
Vector<ValueType> values() const;
/*
* Operator: []
* Usage: map[key]
* ---------------
* Selects the value associated with <code>key</code>. This syntax
* makes it easy to think of a map as an "associative array"
* indexed by the key type. If <code>key</code> is already present
* in the map, this function returns a reference to its associated
* value. If key is not present in the map, a new entry is created
* whose value is set to the default for the value type.
*/
ValueType & operator[](const KeyType & key);
ValueType operator[](const KeyType & key) const;
/*
* Method: toString
* Usage: string str = map.toString();
* -----------------------------------
* Converts the map to a printable string representation.
*/
std::string toString();
/*
* Method: mapAll
* Usage: map.mapAll(fn);
* ----------------------
* Iterates through the map entries and calls <code>fn(key, value)</code>
* for each one. The keys are processed in ascending order, as defined
* by the comparison function.
*/
void mapAll(void (*fn)(KeyType, ValueType)) const;
void mapAll(void (*fn)(const KeyType &, const ValueType &)) const;
template <typename FunctorType>
void mapAll(FunctorType fn) const;
/*
* Additional Map operations
* -------------------------
* In addition to the methods listed in this interface, the Map
* class supports the following operations:
*
* - Stream I/O using the << and >> operators
* - Deep copying for the copy constructor and assignment operator
* - Iteration using the range-based for statement and STL iterators
*
* All iteration is guaranteed to proceed in the order established by
* the comparison function passed to the constructor, which ordinarily
* matches the order of the key type.
*/
/* Private section */
/**********************************************************************/
/* Note: Everything below this point in the file is logically part */
/* of the implementation and should not be of interest to clients. */
/**********************************************************************/
/*
* Implementation notes:
* ---------------------
* The map class is represented using a binary search tree. The
* specific implementation used here is the classic AVL algorithm
* developed by Georgii Adel'son-Vel'skii and Evgenii Landis in 1962.
*/
private:
/* Constant definitions */
static const int BST_LEFT_HEAVY = -1;
static const int BST_IN_BALANCE = 0;
static const int BST_RIGHT_HEAVY = +1;
/* Type definition for nodes in the binary search tree */
struct BSTNode {
KeyType key; /* The key stored in this node */
ValueType value; /* The corresponding value */
BSTNode *left; /* Subtree containing all smaller keys */
BSTNode *right; /* Subtree containing all larger keys */
int bf; /* AVL balance factor */
};
/*
* Implementation notes: Comparator
* --------------------------------
* The Comparator class encapsulates a functor that compares two values
* of KeyType. In contrast to the classes in the STL, all of which embed
* the comparator in the type, the Map class and its derivatives pass an
* optional Comparator value. While this strategy results in a more
* complex implementation, it has the advantage of allowing maps and sets
* to carry their own comparators without forcing the client to include
* the comparator in the template declaration. This simplification is
* particularly important for the Graph class.
*
* The allocation is required in the TemplateComparator class because
* the type std::binary_function has subclasses but does not define a
* virtual destructor.
*/
class Comparator {
public:
virtual ~Comparator() { }
virtual bool lessThan(const KeyType & k1, const KeyType & k2) = 0;
virtual Comparator *clone() = 0;
};
template <typename CompareType>
class TemplateComparator : public Comparator {
public:
TemplateComparator(CompareType cmp) {
this->cmp = new CompareType(cmp);
}
virtual bool lessThan(const KeyType & k1, const KeyType & k2) {
return (*cmp)(k1, k2);
}
virtual Comparator *clone() {
return new TemplateComparator<CompareType>(*cmp);
}
private:
CompareType *cmp;
};
Comparator & getComparator() const {
return *cmpp;
}
/* Instance variables */
BSTNode *root; /* Pointer to the root of the tree */
int nodeCount; /* Number of entries in the map */
Comparator *cmpp; /* Pointer to the comparator */
int (*cmpFn)(const KeyType &, const KeyType &);
/* Private methods */
/*
* Implementation notes: findNode(t, key)
* --------------------------------------
* Searches the tree rooted at t to find the specified key, searching
* in the left or right subtree, as approriate. If a matching node
* is found, findNode returns a pointer to the value cell in that node.
* If no matching node exists in the tree, findNode returns NULL.
*/
ValueType *findNode(BSTNode *t, const KeyType & key) const {
if (t == NULL) return NULL;
int sign = compareKeys(key, t->key);
if (sign == 0) return &t->value;
if (sign < 0) {
return findNode(t->left, key);
} else {
return findNode(t->right, key);
}
}
/*
* Implementation notes: addNode(t, key, heightFlag)
* -------------------------------------------------
* Searches the tree rooted at t to find the specified key, searching
* in the left or right subtree, as approriate. If a matching node
* is found, addNode returns a pointer to the value cell in that node,
* just like findNode. If no matching node exists in the tree, addNode
* creates a new node with a default value. The heightFlag reference
* parameter returns a bool indicating whether the height of the tree
* was changed by this operation.
*/
ValueType *addNode(BSTNode * & t, const KeyType & key, bool & heightFlag) {
heightFlag = false;
if (t == NULL) {
t = new BSTNode();
t->key = key;
t->value = ValueType();
t->bf = BST_IN_BALANCE;
t->left = t->right = NULL;
heightFlag = true;
nodeCount++;
return &t->value;
}
int sign = compareKeys(key, t->key);
if (sign == 0) return &t->value;
ValueType *vp = NULL;
int bfDelta = BST_IN_BALANCE;
if (sign < 0) {
vp = addNode(t->left, key, heightFlag);
if (heightFlag) bfDelta = BST_LEFT_HEAVY;
} else {
vp = addNode(t->right, key, heightFlag);
if (heightFlag) bfDelta = BST_RIGHT_HEAVY;
}
updateBF(t, bfDelta);
heightFlag = (bfDelta != 0 && t->bf != BST_IN_BALANCE);
return vp;
}
/*
* Implementation notes: removeNode(t, key)
* ----------------------------------------
* Removes the node containing the specified key from the tree rooted
* at t. The return value is true if the height of this subtree
* changes. The removeTargetNode method does the actual deletion.
*/
bool removeNode(BSTNode * & t, const KeyType & key) {
if (t == NULL) return false;
int sign = compareKeys(key, t->key);
if (sign == 0) return removeTargetNode(t);
int bfDelta = BST_IN_BALANCE;
if (sign < 0) {
if (removeNode(t->left, key)) bfDelta = BST_RIGHT_HEAVY;
} else {
if (removeNode(t->right, key)) bfDelta = BST_LEFT_HEAVY;
}
updateBF(t, bfDelta);
return bfDelta != 0 && t->bf == BST_IN_BALANCE;
}
/*
* Implementation notes: removeTargetNode(t)
* -----------------------------------------
* Removes the node which is passed by reference as t. The easy case
* occurs when either (or both) of the children is NULL; all you need
* to do is replace the node with its non-NULL child, if any. If both
* children are non-NULL, this code finds the rightmost descendent of
* the left child; this node may not be a leaf, but will have no right
* child. Its left child replaces it in the tree, after which the
* replacement data is moved to the position occupied by the target node.
*/
bool removeTargetNode(BSTNode * & t) {
BSTNode *toDelete = t;
if (t->left == NULL) {
t = t->right;
delete toDelete;
nodeCount--;
return true;
} else if (t->right == NULL) {
t = t->left;
delete toDelete;
nodeCount--;
return true;
} else {
BSTNode *successor = t->left;
while (successor->right != NULL) {
successor = successor->right;
}
t->key = successor->key;
t->value = successor->value;
if (removeNode(t->left, successor->key)) {
updateBF(t, BST_RIGHT_HEAVY);
return (t->bf == BST_IN_BALANCE);
}
return false;
}
}
/*
* Implementation notes: updateBF(t, bfDelta)
* ------------------------------------------
* Updates the balance factor in the node and rebalances the tree
* if necessary.
*/
void updateBF(BSTNode * & t, int bfDelta) {
t->bf += bfDelta;
if (t->bf < BST_LEFT_HEAVY) {
fixLeftImbalance(t);
} else if (t->bf > BST_RIGHT_HEAVY) {
fixRightImbalance(t);
}
}
/*
* Implementation notes: fixLeftImbalance(t)
* -----------------------------------------
* This function is called when a node has been found that is out
* of balance with the longer subtree on the left. Depending on
* the balance factor of the left child, the code performs a
* single or double rotation.
*/
void fixLeftImbalance(BSTNode * & t) {
BSTNode *child = t->left;
if (child->bf == BST_RIGHT_HEAVY) {
int oldBF = child->right->bf;
rotateLeft(t->left);
rotateRight(t);
t->bf = BST_IN_BALANCE;
switch (oldBF) {
case BST_LEFT_HEAVY:
t->left->bf = BST_IN_BALANCE;
t->right->bf = BST_RIGHT_HEAVY;
break;
case BST_IN_BALANCE:
t->left->bf = t->right->bf = BST_IN_BALANCE;
break;
case BST_RIGHT_HEAVY:
t->left->bf = BST_LEFT_HEAVY;
t->right->bf = BST_IN_BALANCE;
break;
}
} else if (child->bf == BST_IN_BALANCE) {
rotateRight(t);
t->bf = BST_RIGHT_HEAVY;
t->right->bf = BST_LEFT_HEAVY;
} else {
rotateRight(t);
t->right->bf = t->bf = BST_IN_BALANCE;
}
}
/*
* Implementation notes: rotateLeft(t)
* -----------------------------------
* This function performs a single left rotation of the tree
* that is passed by reference. The balance factors
* are unchanged by this function and must be corrected at a
* higher level of the algorithm.
*/
void rotateLeft(BSTNode * & t) {
BSTNode *child = t->right;
t->right = child->left;
child->left = t;
t = child;
}
/*
* Implementation notes: fixRightImbalance(t)
* ------------------------------------------
* This function is called when a node has been found that
* is out of balance with the longer subtree on the right.
* Depending on the balance factor of the right child, the
* code performs a single or double rotation.
*/
void fixRightImbalance(BSTNode * & t) {
BSTNode *child = t->right;
if (child->bf == BST_LEFT_HEAVY) {
int oldBF = child->left->bf;
rotateRight(t->right);
rotateLeft(t);
t->bf = BST_IN_BALANCE;
switch (oldBF) {
case BST_LEFT_HEAVY:
t->left->bf = BST_IN_BALANCE;
t->right->bf = BST_RIGHT_HEAVY;
break;
case BST_IN_BALANCE:
t->left->bf = t->right->bf = BST_IN_BALANCE;
break;
case BST_RIGHT_HEAVY:
t->left->bf = BST_LEFT_HEAVY;
t->right->bf = BST_IN_BALANCE;
break;
}
} else if (child->bf == BST_IN_BALANCE) {
rotateLeft(t);
t->bf = BST_LEFT_HEAVY;
t->left->bf = BST_RIGHT_HEAVY;
} else {
rotateLeft(t);
t->left->bf = t->bf = BST_IN_BALANCE;
}
}
/*
* Implementation notes: rotateRight(t)
* ------------------------------------
* This function performs a single right rotation of the tree
* that is passed by reference. The balance factors
* are unchanged by this function and must be corrected at a
* higher level of the algorithm.
*/
void rotateRight(BSTNode * & t) {
BSTNode *child = t->left;
t->left = child->right;
child->right = t;
t = child;
}
/*
* Implementation notes: deleteTree(t)
* -----------------------------------
* Deletes all the nodes in the tree.
*/
void deleteTree(BSTNode *t) {
if (t != NULL) {
deleteTree(t->left);
deleteTree(t->right);
delete t;
}
}
/*
* Implementation notes: mapAll
* ----------------------------
* Calls fn(key, value) for every key-value pair in the tree.
*/
void mapAll(BSTNode *t, void (*fn)(KeyType, ValueType)) const {
if (t != NULL) {
mapAll(t->left, fn);
fn(t->key, t->value);
mapAll(t->right, fn);
}
}
void mapAll(BSTNode *t,
void (*fn)(const KeyType &, const ValueType &)) const {
if (t != NULL) {
mapAll(t->left, fn);
fn(t->key, t->value);
mapAll(t->right, fn);
}
}
template <typename FunctorType>
void mapAll(BSTNode *t, FunctorType fn) const {
if (t != NULL) {
mapAll(t->left, fn);
fn(t->key, t->value);
mapAll(t->right, fn);
}
}
void deepCopy(const Map & other) {
root = copyTree(other.root);
nodeCount = other.nodeCount;
cmpp = (other.cmpp == NULL) ? NULL : other.cmpp->clone();
}
BSTNode *copyTree(BSTNode * const t) {
if (t == NULL) return NULL;
BSTNode *np = new BSTNode();
np->key = t->key;
np->value = t->value;
np->bf = t->bf;
np->left = copyTree(t->left);
np->right = copyTree(t->right);
return np;
}
public:
/*
* Hidden features
* ---------------
* The remainder of this file consists of the code required to
* support deep copying and iteration. Including these methods in
* the public portion of the interface would make that interface more
* difficult to understand for the average client.
*/
/* Extended constructors */
template <typename CompareType>
explicit Map(CompareType cmp) {
root = NULL;
nodeCount = 0;
cmpp = new TemplateComparator<CompareType>(cmp);
}
/*
* Implementation notes: compareKeys(k1, k2)
* -----------------------------------------
* Compares the keys k1 and k2 and returns an integer (-1, 0, or +1)
* depending on whether k1 < k2, k1 == k2, or k1 > k2, respectively.
*/
int compareKeys(const KeyType & k1, const KeyType & k2) const {
if (cmpp->lessThan(k1, k2)) return -1;
if (cmpp->lessThan(k2, k1)) return +1;
return 0;
}
/*
* Deep copying support
* --------------------
* This copy constructor and operator= are defined to make a
* deep copy, making it possible to pass/return maps by value
* and assign from one map to another.
*/
Map & operator=(const Map & src) {
if (this != &src) {
clear();
deepCopy(src);
}
return *this;
}
Map(const Map & src) {
deepCopy(src);
}
/*
* Iterator support
* ----------------
* The classes in the StanfordCPPLib collection implement input
* iterators so that they work symmetrically with respect to the
* corresponding STL classes.
*/
class iterator : public std::iterator<std::input_iterator_tag,KeyType> {
private:
struct NodeMarker {
BSTNode *np;
bool processed;
};
const Map *mp; /* Pointer to the map */
int index; /* Index of current element */
Stack<NodeMarker> stack; /* Stack of unprocessed nodes */
void findLeftmostChild() {
BSTNode *np = stack.peek().np;
if (np == NULL) return;
while (np->left != NULL) {
NodeMarker marker = { np->left, false };
stack.push(marker);
np = np->left;
}
}
public:
iterator() {
/* Empty */
}
iterator(const Map *mp, bool end) {
this->mp = mp;
if (end || mp->nodeCount == 0) {
index = mp->nodeCount;
} else {
index = 0;
NodeMarker marker = { mp->root, false };
stack.push(marker);
findLeftmostChild();
}
}
iterator(const iterator & it) {
mp = it.mp;
index = it.index;
stack = it.stack;
}
iterator& operator=(const iterator & it) {
if(*this != it){
mp = it.mp;
index = it.index;
stack = it.stack;
}
return *this;
}
iterator & operator++() {
NodeMarker marker = stack.pop();
BSTNode *np = marker.np;
if (np->right == NULL) {
while (!stack.isEmpty() && stack.peek().processed) {
stack.pop();
}
} else {
marker.processed = true;
stack.push(marker);
marker.np = np->right;
marker.processed = false;
stack.push(marker);
findLeftmostChild();
}
index++;
return *this;
}
iterator operator++(int) {
iterator copy(*this);
operator++();
return copy;
}
bool operator==(const iterator & rhs) {
return mp == rhs.mp && index == rhs.index;
}
bool operator!=(const iterator & rhs) {
return !(*this == rhs);
}
KeyType operator*() {
return stack.peek().np->key;
}
KeyType *operator->() {
return &stack.peek().np->key;
}
friend class Map;
};
iterator begin() const {
return iterator(this, false);
}
iterator end() const {
return iterator(this, true);
}
};
template <typename KeyType, typename ValueType>
Map<KeyType,ValueType>::Map() {
root = NULL;
nodeCount = 0;
cmpp = new TemplateComparator< less<KeyType> >(less<KeyType>());
}
template <typename KeyType, typename ValueType>
Map<KeyType,ValueType>::~Map() {
if (cmpp != NULL) delete cmpp;
deleteTree(root);
}
template <typename KeyType, typename ValueType>
int Map<KeyType,ValueType>::size() const {
return nodeCount;
}
template <typename KeyType, typename ValueType>
bool Map<KeyType,ValueType>::isEmpty() const {
return nodeCount == 0;
}
template <typename KeyType, typename ValueType>
void Map<KeyType,ValueType>::put(const KeyType & key,
const ValueType & value) {
bool dummy;
*addNode(root, key, dummy) = value;
}
template <typename KeyType, typename ValueType>
ValueType Map<KeyType,ValueType>::get(const KeyType & key) const {
ValueType *vp = findNode(root, key);
if (vp == NULL) return ValueType();
return *vp;
}
template <typename KeyType, typename ValueType>
void Map<KeyType,ValueType>::remove(const KeyType & key) {
removeNode(root, key);
}
template <typename KeyType, typename ValueType>
void Map<KeyType,ValueType>::clear() {
deleteTree(root);
root = NULL;
nodeCount = 0;
}
template <typename KeyType, typename ValueType>
bool Map<KeyType,ValueType>::containsKey(const KeyType & key) const {
return findNode(root, key) != NULL;
}
template <typename KeyType, typename ValueType>
ValueType & Map<KeyType,ValueType>::operator[](const KeyType & key) {
bool dummy;
return *addNode(root, key, dummy);
}
template <typename KeyType, typename ValueType>
ValueType Map<KeyType,ValueType>::operator[](const KeyType & key) const {
return get(key);
}
template <typename KeyType, typename ValueType>
void Map<KeyType,ValueType>::mapAll(void (*fn)(KeyType, ValueType)) const {
mapAll(root, fn);
}
template <typename KeyType, typename ValueType>
void Map<KeyType,ValueType>::mapAll(void (*fn)(const KeyType &,
const ValueType &)) const {
mapAll(root, fn);
}
template <typename KeyType, typename ValueType>
template <typename FunctorType>
void Map<KeyType,ValueType>::mapAll(FunctorType fn) const {
mapAll(root, fn);
}
template <typename KeyType, typename ValueType>
std::string Map<KeyType,ValueType>::toString() {
ostringstream os;
os << *this;
return os.str();
}
template <typename KeyType,typename ValueType>
Vector<KeyType> Map<KeyType,ValueType>::keys() const {
Vector<KeyType> keyset;
foreach (KeyType key in *this) {
keyset.add(key);
}
return keyset;
}
template <typename KeyType,typename ValueType>
Vector<ValueType> Map<KeyType,ValueType>::values() const {
Vector<ValueType> values;
foreach (KeyType key in *this) {
values.add(this->get(key));
}
return values;
}
/*
* Implementation notes: << and >>
* -------------------------------
* The insertion and extraction operators use the template facilities in
* strlib.h to read and write generic values in a way that treats strings
* specially.
*/
template <typename KeyType, typename ValueType>
std::ostream & operator<<(std::ostream & os,
const Map<KeyType,ValueType> & map) {
os << "{";
typename Map<KeyType,ValueType>::iterator begin = map.begin();
typename Map<KeyType,ValueType>::iterator end = map.end();
typename Map<KeyType,ValueType>::iterator it = begin;
while (it != end) {
if (it != begin) os << ", ";
writeGenericValue(os, *it, false);
os << ":";
writeGenericValue(os, map[*it], false);
++it;
}
return os << "}";
}
template <typename KeyType, typename ValueType>
std::istream & operator>>(std::istream & is, Map<KeyType,ValueType> & map) {
char ch;
is >> ch;
if (ch != '{') error("operator >>: Missing {");
map.clear();
is >> ch;
if (ch != '}') {
is.unget();
while (true) {
KeyType key;
readGenericValue(is, key);
is >> ch;
if (ch != ':') error("operator >>: Missing colon after key");
ValueType value;
readGenericValue(is, value);
map[key] = value;
is >> ch;
if (ch == '}') break;
if (ch != ',') {
error(std::string("operator >>: Unexpected character ") + ch);
}
}
}
return is;
}
#endif

View File

@ -0,0 +1,218 @@
/*
* File: main.h
* ------------
* This file renames the <code>main</code> method in the client's
* program to <code>Main</code>, thereby allowing a custom
* <code>main</code> method in the libraries to take control
* before passing control back to the client program. The main macro
* also defines a function getMainFlags that returns an int whose bits
* indicate which of the various interfaces have been loaded by this
* definition of main.
*
* Note: This file can be loaded more than once and must therefore
* check to see what has already been defined.
*/
#ifdef main
# undef main
# undef CONSOLE_FLAG
# undef GRAPHICS_FLAG
#else
# define MAIN_USES_CONSOLE (1<<0)
# define MAIN_USES_GRAPHICS (1<<1)
#endif
#ifdef _console_h
# define CONSOLE_FLAG MAIN_USES_CONSOLE
#else
# define CONSOLE_FLAG 0
#endif
#ifdef _gwindow_h
# define GRAPHICS_FLAG MAIN_USES_GRAPHICS
#else
# define GRAPHICS_FLAG 0
#endif
#if CONSOLE_FLAG | GRAPHICS_FLAG
#define main main(int argc, char **argv) { \
extern int _mainFlags; \
_mainFlags = GRAPHICS_FLAG + CONSOLE_FLAG; \
try { \
return startupMain(argc, argv); \
} catch (const std::exception& ex) { \
string msg = "\n ***\n"; \
msg += " *** STANFORD C++ LIBRARY \n"; \
msg += " *** An exception occurred during program execution: \n"; \
msg += " *** "; \
msg += ex.what(); \
msg += "\n ***\n\n"; \
std::cerr << msg; \
throw ex; \
} catch (std::string str) { \
string msg = "\n ***\n"; \
msg += " *** STANFORD C++ LIBRARY \n"; \
msg += " *** A string exception occurred during program execution: \n"; \
msg += " *** \""; \
msg += str; \
msg += "\"\n ***\n"; \
std::cerr << msg; \
throw str; \
} catch (char const* str) { \
string msg = "\n ***\n"; \
msg += " *** STANFORD C++ LIBRARY \n"; \
msg += " *** A string exception occurred during program execution: \n"; \
msg += " *** \""; \
msg += str; \
msg += "\"\n ***\n"; \
std::cerr << msg; \
throw str; \
} catch (int n) { \
char buf[128]; \
snprintf(buf, 128, "%d", n); \
string msg = "\n ***\n"; \
msg += " *** STANFORD C++ LIBRARY \n"; \
msg += " *** An int exception occurred during program execution: \n"; \
msg += " *** "; \
msg += buf; \
msg += "\n ***\n\n"; \
std::cerr << msg; \
throw n; \
} catch (long l) { \
char buf[128]; \
snprintf(buf, 128, "%ld", l); \
string msg = "\n ***\n"; \
msg += " *** STANFORD C++ LIBRARY \n"; \
msg += " *** A long exception occurred during program execution: \n"; \
msg += " *** "; \
msg += buf; \
msg += "\n ***\n\n"; \
std::cerr << msg; \
throw l; \
} catch (char c) { \
string msg = "\n ***\n"; \
msg += " *** STANFORD C++ LIBRARY \n"; \
msg += " *** A char exception occurred during program execution: \n"; \
msg += " *** '"; \
msg += c; \
msg += "'\n ***\n"; \
std::cerr << msg; \
throw c; \
} catch (bool b) { \
string msg = "\n ***\n"; \
msg += " *** STANFORD C++ LIBRARY \n"; \
msg += " *** A bool exception occurred during program execution: \n"; \
msg += " *** "; \
msg += (b ? "true" : "false"); \
msg += "\n ***\n\n"; \
std::cerr << msg; \
throw b; \
} catch (double d) { \
char buf[128]; \
snprintf(buf, 128, "%lf", d); \
string msg = "\n ***\n"; \
msg += " *** STANFORD C++ LIBRARY \n"; \
msg += " *** A double exception occurred during program execution: \n"; \
msg += " *** "; \
msg += buf; \
msg += "\n ***\n\n"; \
std::cerr << msg; \
throw d; \
} \
} \
int Main
extern int startupMain(int argc, char **argv);
#else
#define main main(int argc, char **argv) { \
extern int _mainFlags; \
_mainFlags = GRAPHICS_FLAG + CONSOLE_FLAG; \
try { \
return mainWrapper(argc, argv); } \
} catch (const std::exception& ex) { \
string msg = "\n ***\n"; \
msg += " *** STANFORD C++ LIBRARY \n"; \
msg += " *** An exception occurred during program execution: \n"; \
msg += " *** "; \
msg += ex.what(); \
msg += "\n ***\n\n"; \
std::cerr << msg; \
throw ex; \
} catch (std::string str) { \
string msg = "\n ***\n"; \
msg += " *** STANFORD C++ LIBRARY \n"; \
msg += " *** A string exception occurred during program execution: \n"; \
msg += " *** \""; \
msg += str; \
msg += "\"\n ***\n"; \
std::cerr << msg; \
throw str; \
} catch (char const* str) { \
string msg = "\n ***\n"; \
msg += " *** STANFORD C++ LIBRARY \n"; \
msg += " *** A string exception occurred during program execution: \n"; \
msg += " *** \""; \
msg += str; \
msg += "\"\n ***\n"; \
std::cerr << msg; \
throw str; \
} catch (int n) { \
char buf[128]; \
snprintf(buf, 128, "%d", n); \
string msg = "\n ***\n"; \
msg += " *** STANFORD C++ LIBRARY \n"; \
msg += " *** An int exception occurred during program execution: \n"; \
msg += " *** "; \
msg += buf; \
msg += "\n ***\n\n"; \
std::cerr << msg; \
throw n; \
} catch (long l) { \
char buf[128]; \
snprintf(buf, 128, "%ld", l); \
string msg = "\n ***\n"; \
msg += " *** STANFORD C++ LIBRARY \n"; \
msg += " *** A long exception occurred during program execution: \n"; \
msg += " *** "; \
msg += buf; \
msg += "\n ***\n\n"; \
std::cerr << msg; \
throw l; \
} catch (char c) { \
string msg = "\n ***\n"; \
msg += " *** STANFORD C++ LIBRARY \n"; \
msg += " *** A char exception occurred during program execution: \n"; \
msg += " *** '"; \
msg += c; \
msg += "'\n ***\n"; \
std::cerr << msg; \
throw c; \
} catch (bool b) { \
string msg = "\n ***\n"; \
msg += " *** STANFORD C++ LIBRARY \n"; \
msg += " *** A bool exception occurred during program execution: \n"; \
msg += " *** "; \
msg += (b ? "true" : "false"); \
msg += "\n ***\n\n"; \
std::cerr << msg; \
throw b; \
} catch (double d) { \
char buf[128]; \
snprintf(buf, 128, "%lf", d); \
string msg = "\n ***\n"; \
msg += " *** STANFORD C++ LIBRARY \n"; \
msg += " *** A double exception occurred during program execution: \n"; \
msg += " *** "; \
msg += buf; \
msg += "\n ***\n\n"; \
std::cerr << msg; \
throw d; \
} \
int Main
extern int mainWrapper(int argc, char **argv);
#endif

View File

@ -0,0 +1,62 @@
/*
* File: main.h
* ------------
* This file renames the <code>main</code> method in the client's
* program to <code>Main</code>, thereby allowing a custom
* <code>main</code> method in the libraries to take control
* before passing control back to the client program. The main macro
* also defines a function getMainFlags that returns an int whose bits
* indicate which of the various interfaces have been loaded by this
* definition of main.
*
* Note: This file can be loaded more than once and must therefore
* check to see what has already been defined.
*/
#ifdef main
# undef main
# undef CONSOLE_FLAG
# undef GRAPHICS_FLAG
#else
# define MAIN_USES_CONSOLE (1<<0)
# define MAIN_USES_GRAPHICS (1<<1)
#endif
#ifdef _console_h
# define CONSOLE_FLAG MAIN_USES_CONSOLE
#else
# define CONSOLE_FLAG 0
#endif
#ifdef _gwindow_h
# define GRAPHICS_FLAG MAIN_USES_GRAPHICS
#else
# define GRAPHICS_FLAG 0
#endif
void __StanfordCPPLib_terminate_handler();
void __StanfordCPPLib_set_terminate();
#if CONSOLE_FLAG | GRAPHICS_FLAG
#define main main(int argc, char **argv) { \
extern int _mainFlags; \
_mainFlags = GRAPHICS_FLAG + CONSOLE_FLAG; \
return startupMain(argc, argv); \
} \
int Main
extern int startupMain(int argc, char **argv);
#else
#define main main(int argc, char **argv) { \
extern int _mainFlags; \
_mainFlags = GRAPHICS_FLAG + CONSOLE_FLAG; \
return mainWrapper(argc, argv); } \
} \
int Main
extern int mainWrapper(int argc, char **argv);
#endif

View File

@ -0,0 +1,63 @@
/*
* File: private/randompatch.h
* ---------------------------
* This file patches the implementation of the random number library
* to avoid some serious bugs in standard implementations of rand,
* particularly on Mac OS X. It also includes a hack to set the
* seed from the RANDOM_SEED environment variable, which makes it
* possible to produce repeatable figures.
*/
/*
* Implementation notes: rand, srand
* ---------------------------------
* To ensure that this package works the same way on all platforms,
* this file completely reimplements the rand and srand methods. The
* algorithm is a conventional linear congruential generator with the
* parameters used in GNU's gclib. RAND_MAX for this implementation
* is 2147483647 (2^31 - 1).
*/
#define MULTIPLIER 1103515245
#define OFFSET 12345
static int _seed = 1;
#undef rand
#define rand() ((_seed = MULTIPLIER * _seed + OFFSET) & 0x7FFFFFFF)
#undef srand
#define srand(seed) (_seed = int(seed), _seed = (_seed <= 0) ? 1 : _seed)
#undef RAND_MAX
#define RAND_MAX 2147483647
/*
* Implementation notes: Windows patch
* -----------------------------------
* On some versions of Windows, the time function is too coarse to use
* as a random seed. On those versions, this definition substitutes the
* GetTickCount function.
*/
#if defined (_MSC_VER) && (_MSC_VER >= 1200)
# include <windows.h>
# define time(dummy) (GetTickCount())
#endif
#ifdef __APPLE__
# include <cstdlib>
static time_t patchedTime(time_t *) {
char *str = getenv("RANDOM_SEED");
if (str == NULL) {
return time(NULL);
} else {
return atoi(str);
}
}
# define time(dummy) patchedTime(dummy)
#endif

View File

@ -0,0 +1,11 @@
/*
* File: tokenpatch.h
* ------------------
* This file renames TokenType and WORD to avoid conflict with the
* <windows.h> header.
*/
#ifdef _MSC_VER
# define TokenType TokenTypeT
# define WORD WORD_TC
#endif

View File

@ -0,0 +1,25 @@
/*
* File: tplatform.h
* -----------------
* This interface defines the platform-specific methods on threads
* and locks.
*/
/* Methods for threads */
int forkForPlatform(void (*fn)(void *), void *arg);
void incThreadRefCountForPlatform(int id);
void decThreadRefCountForPlatform(int id);
void joinForPlatform(int id);
int getCurrentThreadForPlatform();
void yieldForPlatform();
/* Methods for locks */
int initLockForPlatform();
void incLockRefCountForPlatform(int id);
void decLockRefCountForPlatform(int id);
void lockForPlatform(int id);
void unlockForPlatform(int id);
void waitForPlatform(int id);
void signalForPlatform(int id);

99
lib/StanfordCPPLib/random.cpp Executable file
View File

@ -0,0 +1,99 @@
/*
* File: random.cpp
* ----------------
* This file implements the random.h interface.
*/
#include <cstdlib>
#include <cmath>
#include <ctime>
#include "random.h"
#include "private/randompatch.h"
using namespace std;
/* Private function prototype */
static void initRandomSeed();
/*
* Implementation notes: randomInteger
* -----------------------------------
* The code for randomInteger produces the number in four steps:
*
* 1. Generate a random real number d in the range [0 .. 1).
* 2. Scale the number to the range [0 .. N) where N is the number of values.
* 3. Translate the number so that the range starts at the appropriate value.
* 4. Convert the result to the next lower integer.
*
* The implementation is complicated by the fact that both the expression
*
* RAND_MAX + 1
*
* and the expression for the number of values
*
* high - low + 1
*
* can overflow the integer range. These calculations must therefore be
* performed using doubles instead of ints.
*/
int randomInteger(int low, int high) {
initRandomSeed();
double d = rand() / (double(RAND_MAX) + 1);
double s = d * (double(high) - low + 1);
return int(floor(low + s));
}
/*
* Implementation notes: randomReal
* --------------------------------
* The code for randomReal is similar to that for randomInteger,
* without the final conversion step.
*/
double randomReal(double low, double high) {
initRandomSeed();
double d = rand() / (double(RAND_MAX) + 1);
double s = d * (high - low);
return low + s;
}
/*
* Implementation notes: randomChance
* ----------------------------------
* The code for randomChance calls randomReal(0, 1) and then checks
* whether the result is less than the requested probability.
*/
bool randomChance(double p) {
initRandomSeed();
return randomReal(0, 1) < p;
}
/*
* Implementation notes: setRandomSeed
* -----------------------------------
* The setRandomSeed function simply forwards its argument to srand.
* The call to initRandomSeed is required to set the initialized flag.
*/
void setRandomSeed(int seed) {
initRandomSeed();
srand(seed);
}
/*
* Implementation notes: initRandomSeed
* ------------------------------------
* The initRandomSeed function declares a static variable that keeps track
* of whether the seed has been initialized. The first time initRandomSeed
* is called, initialized is false, so the seed is set to the current time.
*/
static void initRandomSeed() {
static bool initialized = false;
if (!initialized) {
srand(int(time(NULL)));
initialized = true;
}
}

58
lib/StanfordCPPLib/random.h Executable file
View File

@ -0,0 +1,58 @@
/*
* File: random.h
* --------------
* This file exports functions for generating pseudorandom numbers.
*/
#ifndef _random_h
#define _random_h
/*
* Function: randomInteger
* Usage: int n = randomInteger(low, high);
* ----------------------------------------
* Returns a random integer in the range <code>low</code> to
* <code>high</code>, inclusive.
*/
int randomInteger(int low, int high);
/*
* Function: randomReal
* Usage: double d = randomReal(low, high);
* ----------------------------------------
* Returns a random real number in the half-open interval
* [<code>low</code>&nbsp;..&nbsp;<code>high</code>). A half-open
* interval includes the first endpoint but not the second, which
* means that the result is always greater than or equal to
* <code>low</code> but strictly less than <code>high</code>.
*/
double randomReal(double low, double high);
/*
* Function: randomChance
* Usage: if (randomChance(p)) ...
* -------------------------------
* Returns <code>true</code> with the probability indicated by <code>p</code>.
* The argument <code>p</code> must be a floating-point number between
* 0 (never) and 1 (always). For example, calling
* <code>randomChance(.30)</code> returns <code>true</code> 30 percent
* of the time.
*/
bool randomChance(double p);
/*
* Function: setRandomSeed
* Usage: setRandomSeed(seed);
* ---------------------------
* Sets the internal random number seed to the specified value. You
* can use this function to set a specific starting point for the
* pseudorandom sequence or to ensure that program behavior is
* repeatable during the debugging phase.
*/
void setRandomSeed(int seed);
#endif

628
lib/StanfordCPPLib/set.h Executable file
View File

@ -0,0 +1,628 @@
/*
* File: set.h
* -----------
* This file exports the <code>Set</code> class, which implements a
* collection for storing a set of distinct elements.
*/
#ifndef _set_h
#define _set_h
#include <iostream>
#include "foreach.h"
#include "map.h"
#include "vector.h"
/*
* Class: Set<ValueType>
* ---------------------
* This class stores a collection of distinct elements.
*/
template <typename ValueType>
class Set {
public:
/*
* Constructor: Set
* Usage: Set<ValueType> set;
* --------------------------
* Creates an empty set of the specified element type.
*/
Set();
/*
* Destructor: ~Set
* ----------------
* Frees any heap storage associated with this set.
*/
virtual ~Set();
/*
* Method: size
* Usage: count = set.size();
* --------------------------
* Returns the number of elements in this set.
*/
int size() const;
/*
* Method: isEmpty
* Usage: if (set.isEmpty()) ...
* -----------------------------
* Returns <code>true</code> if this set contains no elements.
*/
bool isEmpty() const;
/*
* Method: add
* Usage: set.add(value);
* ----------------------
* Adds an element to this set, if it was not already there. For
* compatibility with the STL <code>set</code> class, this method
* is also exported as <code>insert</code>.
*/
void add(const ValueType & value);
void insert(const ValueType & value);
/*
* Method: remove
* Usage: set.remove(value);
* -------------------------
* Removes an element from this set. If the value was not
* contained in the set, no error is generated and the set
* remains unchanged.
*/
void remove(const ValueType & value);
/*
* Method: contains
* Usage: if (set.contains(value)) ...
* -----------------------------------
* Returns <code>true</code> if the specified value is in this set.
*/
bool contains(const ValueType & value) const;
/*
* Method: isSubsetOf
* Usage: if (set.isSubsetOf(set2)) ...
* ------------------------------------
* Implements the subset relation on sets. It returns
* <code>true</code> if every element of this set is
* contained in <code>set2</code>.
*/
bool isSubsetOf(const Set & set2) const;
/*
* Method: clear
* Usage: set.clear();
* -------------------
* Removes all elements from this set.
*/
void clear();
/*
* Operator: ==
* Usage: set1 == set2
* -------------------
* Returns <code>true</code> if <code>set1</code> and <code>set2</code>
* contain the same elements.
*/
bool operator==(const Set & set2) const;
/*
* Operator: !=
* Usage: set1 != set2
* -------------------
* Returns <code>true</code> if <code>set1</code> and <code>set2</code>
* are different.
*/
bool operator!=(const Set & set2) const;
/*
* Operator: +
* Usage: set1 + set2
* set1 + element
* ---------------------
* Returns the union of sets <code>set1</code> and <code>set2</code>, which
* is the set of elements that appear in at least one of the two sets. The
* right hand set can be replaced by an element of the value type, in which
* case the operator returns a new set formed by adding that element.
*/
Set operator+(const Set & set2) const;
Set operator+(const ValueType & element) const;
/*
* Operator: *
* Usage: set1 * set2
* ------------------
* Returns the intersection of sets <code>set1</code> and <code>set2</code>,
* which is the set of all elements that appear in both.
*/
Set operator*(const Set & set2) const;
/*
* Operator: -
* Usage: set1 - set2
* set1 - element
* ---------------------
* Returns the difference of sets <code>set1</code> and <code>set2</code>,
* which is all of the elements that appear in <code>set1</code> but
* not <code>set2</code>. The right hand set can be replaced by an
* element of the value type, in which case the operator returns a new
* set formed by removing that element.
*/
Set operator-(const Set & set2) const;
Set operator-(const ValueType & element) const;
/*
* Operator: +=
* Usage: set1 += set2;
* set1 += value;
* ---------------------
* Adds all of the elements from <code>set2</code> (or the single
* specified value) to <code>set1</code>. As a convenience, the
* <code>Set</code> package also overloads the comma operator so
* that it is possible to initialize a set like this:
*
*<pre>
* Set<int> digits;
* digits += 0, 1, 2, 3, 4, 5, 6, 7, 8, 9;
*</pre>
*/
Set & operator+=(const Set & set2);
Set & operator+=(const ValueType & value);
/*
* Operator: *=
* Usage: set1 *= set2;
* --------------------
* Removes any elements from <code>set1</code> that are not present in
* <code>set2</code>.
*/
Set & operator*=(const Set & set2);
/*
* Operator: -=
* Usage: set1 -= set2;
* set1 -= value;
* ---------------------
* Removes the elements from <code>set2</code> (or the single
* specified value) from <code>set1</code>. As a convenience, the
* <code>Set</code> package also overloads the comma operator so
* that it is possible to remove multiple elements from a set
* like this:
*
*<pre>
* digits -= 0, 2, 4, 6, 8;
*</pre>
*
* which removes the values 0, 2, 4, 6, and 8 from the set
* <code>digits</code>.
*/
Set & operator-=(const Set & set2);
Set & operator-=(const ValueType & value);
/*
* Method: first
* Usage: ValueType value = set.first();
* -------------------------------------
* Returns the first value in the set in the order established by the
* <code>foreach</code> macro. If the set is empty, <code>first</code>
* generates an error.
*/
ValueType first() const;
/*
* Method: toString
* Usage: string str = set.toString();
* -----------------------------------
* Converts the set to a printable string representation.
*/
std::string toString();
/*
* Method: mapAll
* Usage: set.mapAll(fn);
* ----------------------
* Iterates through the elements of the set and calls <code>fn(value)</code>
* for each one. The values are processed in ascending order, as defined
* by the comparison function.
*/
void mapAll(void (*fn)(ValueType)) const;
void mapAll(void (*fn)(const ValueType &)) const;
template <typename FunctorType>
void mapAll(FunctorType fn) const;
/*
* Additional Set operations
* -------------------------
* In addition to the methods listed in this interface, the Set class
* supports the following operations:
*
* - Stream I/O using the << and >> operators
* - Deep copying for the copy constructor and assignment operator
* - Iteration using the range-based for statement and STL iterators
*
* The iteration forms process the Set in ascending order.
*/
/* Private section */
/**********************************************************************/
/* Note: Everything below this point in the file is logically part */
/* of the implementation and should not be of interest to clients. */
/**********************************************************************/
private:
Map<ValueType,bool> map; /* Map used to store the element */
bool removeFlag; /* Flag to differentiate += and -= */
public:
/*
* Hidden features
* ---------------
* The remainder of this file consists of the code required to
* support the comma operator, deep copying, and iteration.
* Including these methods in the public interface would make
* that interface more difficult to understand for the average client.
*/
/* Extended constructors */
template <typename CompareType>
explicit Set(CompareType cmp) : map(Map<ValueType,bool>(cmp)) {
/* Empty */
}
Set & operator,(const ValueType & value) {
if (this->removeFlag) {
this->remove(value);
} else {
this->add(value);
}
return *this;
}
/*
* Iterator support
* ----------------
* The classes in the StanfordCPPLib collection implement input
* iterators so that they work symmetrically with respect to the
* corresponding STL classes.
*/
class iterator : public std::iterator<std::input_iterator_tag,ValueType> {
private:
typename Map<ValueType,bool>::iterator mapit; /* Iterator for the map */
public:
iterator() {
/* Empty */
}
iterator(typename Map<ValueType,bool>::iterator it) : mapit(it) {
/* Empty */
}
iterator(const iterator & it) {
mapit = it.mapit;
}
iterator & operator=(const iterator & it) {
if(*this != it){
mapit = it.mapit;
}
return *this;
}
iterator & operator++() {
++mapit;
return *this;
}
iterator operator++(int) {
iterator copy(*this);
operator++();
return copy;
}
bool operator==(const iterator & rhs) {
return mapit == rhs.mapit;
}
bool operator!=(const iterator & rhs) {
return !(*this == rhs);
}
ValueType operator*() {
return *mapit;
}
ValueType *operator->() {
return mapit;
}
};
iterator begin() const {
return iterator(map.begin());
}
iterator end() const {
return iterator(map.end());
}
};
extern void error(std::string msg);
template <typename ValueType>
Set<ValueType>::Set() {
/* Empty */
}
template <typename ValueType>
Set<ValueType>::~Set() {
/* Empty */
}
template <typename ValueType>
int Set<ValueType>::size() const {
return map.size();
}
template <typename ValueType>
bool Set<ValueType>::isEmpty() const {
return map.isEmpty();
}
template <typename ValueType>
void Set<ValueType>::add(const ValueType & value) {
map.put(value, true);
}
template <typename ValueType>
void Set<ValueType>::insert(const ValueType & value) {
map.put(value, true);
}
template <typename ValueType>
void Set<ValueType>::remove(const ValueType & value) {
map.remove(value);
}
template <typename ValueType>
bool Set<ValueType>::contains(const ValueType & value) const {
return map.containsKey(value);
}
template <typename ValueType>
void Set<ValueType>::clear() {
map.clear();
}
template <typename ValueType>
bool Set<ValueType>::isSubsetOf(const Set & set2) const {
iterator it = begin();
iterator end = this->end();
while (it != end) {
if (!set2.map.containsKey(*it)) return false;
++it;
}
return true;
}
/*
* Implementation notes: set operators
* -----------------------------------
* The implementations for the set operators use iteration to walk
* over the elements in one or both sets.
*/
template <typename ValueType>
bool Set<ValueType>::operator==(const Set & set2) const {
if (size() != set2.map.size()) return false;
iterator it1 = begin();
iterator it2 = set2.map.begin();
iterator end = this->end();
while (it1 != end) {
if (map.compareKeys(*it1, *it2) != 0) return false;
++it1;
++it2;
}
return true;
}
template <typename ValueType>
bool Set<ValueType>::operator!=(const Set & set2) const {
return !(*this == set2);
}
template <typename ValueType>
Set<ValueType> Set<ValueType>::operator+(const Set & set2) const {
Set<ValueType> set = *this;
foreach (ValueType value in set2) {
set.add(value);
}
return set;
}
template <typename ValueType>
Set<ValueType> Set<ValueType>::operator+(const ValueType & element) const {
Set<ValueType> set = *this;
set.add(element);
return set;
}
template <typename ValueType>
Set<ValueType> Set<ValueType>::operator*(const Set & set2) const {
Set<ValueType> set = *this;
set.clear();
foreach (ValueType value in *this) {
if (set2.contains(value)) set.add(value);
}
return set;
}
template <typename ValueType>
Set<ValueType> Set<ValueType>::operator-(const Set & set2) const {
Set<ValueType> set = *this;
foreach (ValueType value in set2) {
set.remove(value);
}
return set;
}
template <typename ValueType>
Set<ValueType> Set<ValueType>::operator-(const ValueType & element) const {
Set<ValueType> set = *this;
set.remove(element);
return set;
}
template <typename ValueType>
Set<ValueType> & Set<ValueType>::operator+=(const Set & set2) {
foreach (ValueType value in set2) {
this->add(value);
}
return *this;
}
template <typename ValueType>
Set<ValueType> & Set<ValueType>::operator+=(const ValueType & value) {
this->add(value);
this->removeFlag = false;
return *this;
}
template <typename ValueType>
Set<ValueType> & Set<ValueType>::operator*=(const Set & set2) {
Vector<ValueType> toRemove;
foreach (ValueType value in *this) {
if (!set2.map.containsKey(value)) toRemove.add(value);
}
foreach (ValueType value in toRemove) {
this->remove(value);
}
return *this;
}
template <typename ValueType>
Set<ValueType> & Set<ValueType>::operator-=(const Set & set2) {
Vector<ValueType> toRemove;
foreach (ValueType value in *this) {
if (set2.map.containsKey(value)) toRemove.add(value);
}
foreach (ValueType value in toRemove) {
this->remove(value);
}
return *this;
}
template <typename ValueType>
Set<ValueType> & Set<ValueType>::operator-=(const ValueType & value) {
this->remove(value);
this->removeFlag = true;
return *this;
}
template <typename ValueType>
ValueType Set<ValueType>::first() const {
if (isEmpty()) error("first: set is empty");
return *begin();
}
template <typename ValueType>
std::string Set<ValueType>::toString() {
ostringstream os;
os << *this;
return os.str();
}
template <typename ValueType>
void Set<ValueType>::mapAll(void (*fn)(ValueType)) const {
map.mapAll(fn);
}
template <typename ValueType>
void Set<ValueType>::mapAll(void (*fn)(const ValueType &)) const {
map.mapAll(fn);
}
template <typename ValueType>
template <typename FunctorType>
void Set<ValueType>::mapAll(FunctorType fn) const {
map.mapAll(fn);
}
template <typename ValueType>
std::ostream & operator<<(std::ostream & os, const Set<ValueType> & set) {
os << "{";
bool started = false;
foreach (ValueType value in set) {
if (started) os << ", ";
writeGenericValue(os, value, true);
started = true;
}
os << "}";
return os;
}
template <typename ValueType>
std::istream & operator>>(std::istream & is, Set<ValueType> & set) {
char ch;
is >> ch;
if (ch != '{') error("operator >>: Missing {");
set.clear();
is >> ch;
if (ch != '}') {
is.unget();
while (true) {
ValueType value;
readGenericValue(is, value);
set += value;
is >> ch;
if (ch == '}') break;
if (ch != ',') {
error(std::string("operator >>: Unexpected character ") + ch);
}
}
}
return is;
}
// hashing functions for sets; defined in hashmap.cpp
int hashCode(const Set<std::string>& s);
int hashCode(const Set<int>& s);
int hashCode(const Set<char>& s);
int hashCode(const Set<long>& s);
int hashCode(const Set<double>& s);
#endif

67
lib/StanfordCPPLib/simpio.cpp Executable file
View File

@ -0,0 +1,67 @@
/*
* File: simpio.cpp
* ----------------
* This file implements the simpio.h interface.
*/
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
#include "simpio.h"
using namespace std;
/*
* Implementation notes: getInteger, getReal
* -----------------------------------------
* Each of these functions reads a complete input line and then uses the
* <sstream> library to parse that line into a value of the desired type.
* If that fails, the implementation asks the user for a new value.
*/
int getInteger(string prompt) {
int value;
string line;
while (true) {
cout << prompt;
getline(cin, line);
istringstream stream(line);
stream >> value >> ws;
if (!stream.fail() && stream.eof()) break;
cout << "Illegal integer format. Try again." << endl;
if (prompt == "") prompt = "Enter an integer: ";
}
return value;
}
double getReal(string prompt) {
double value;
string line;
while (true) {
cout << prompt;
getline(cin, line);
istringstream stream(line);
stream >> value >> ws;
if (!stream.fail() && stream.eof()) break;
cout << "Illegal numeric format. Try again." << endl;
if (prompt == "") prompt = "Enter a number: ";
}
return value;
}
/*
* Implementation notes: getLine
* -----------------------------
* The getLine function simply combines the process of displaying a
* prompt and reading an input line into a single call. The primary
* reason for including this function in the library is to ensure
* that the process of reading integers, floating-point numbers, and
* strings remains as consistent as possible.
*/
string getLine(string prompt) {
string line;
cout << prompt;
getline(cin, line);
return line;
}

53
lib/StanfordCPPLib/simpio.h Executable file
View File

@ -0,0 +1,53 @@
/*
* File: simpio.h
* --------------
* This file exports a set of functions that simplify input/output
* operations in C++ and provide some error-checking on console input.
*/
#ifndef _simpio_h
#define _simpio_h
#include <string>
/*
* Function: getInteger
* Usage: int n = getInteger(prompt);
* ----------------------------------
* Reads a complete line from <code>cin</code> and scans it as an
* integer. If the scan succeeds, the integer value is returned. If
* the argument is not a legal integer or if extraneous characters
* (other than whitespace) appear in the string, the user is given
* a chance to reenter the value. If supplied, the optional
* <code>prompt</code> string is printed before reading the value.
*/
int getInteger(std::string prompt = "");
/*
* Function: getReal
* Usage: double x = getReal(prompt);
* ----------------------------------
* Reads a complete line from <code>cin</code> and scans it as a
* floating-point number. If the scan succeeds, the floating-point
* value is returned. If the input is not a legal number or if
* extraneous characters (other than whitespace) appear in the string,
* the user is given a chance to reenter the value. If supplied, the
* optional <code>prompt</code> string is printed before reading the value.
*/
double getReal(std::string prompt = "");
/*
* Function: getLine
* Usage: string line = getLine(prompt);
* -------------------------------------
* Reads a line of text from <code>cin</code> and returns that line
* as a string. The newline character that terminates the input is
* not stored as part of the return value. If supplied, the optional
* <code>prompt</code> string is printed before reading the value.
*/
std::string getLine(std::string prompt = "");
#endif

285
lib/StanfordCPPLib/stack.h Executable file
View File

@ -0,0 +1,285 @@
/*
* File: stack.h
* -------------
* This file exports the <code>Stack</code> class, which implements
* a collection that processes values in a last-in/first-out (LIFO) order.
*/
#ifndef _stack_h
#define _stack_h
#include "vector.h"
/*
* Class: Stack<ValueType>
* -----------------------
* This class models a linear structure called a <b><i>stack</i></b>
* in which values are added and removed only from one end.
* This discipline gives rise to a last-in/first-out behavior (LIFO)
* that is the defining feature of stacks. The fundamental stack
* operations are <code>push</code> (add to top) and <code>pop</code>
* (remove from top).
*/
template <typename ValueType>
class Stack {
public:
/*
* Constructor: Stack
* Usage: Stack<ValueType> stack;
* ------------------------------
* Initializes a new empty stack.
*/
Stack();
/*
* Destructor: ~Stack
* ------------------
* Frees any heap storage associated with this stack.
*/
virtual ~Stack();
/*
* Method: size
* Usage: int n = stack.size();
* ----------------------------
* Returns the number of values in this stack.
*/
int size() const;
/*
* Method: isEmpty
* Usage: if (stack.isEmpty()) ...
* -------------------------------
* Returns <code>true</code> if this stack contains no elements.
*/
bool isEmpty() const;
/*
* Method: clear
* Usage: stack.clear();
* ---------------------
* Removes all elements from this stack.
*/
void clear();
/*
* Method: push
* Usage: stack.push(value);
* -------------------------
* Pushes the specified value onto this stack.
*/
void push(ValueType value);
/*
* Method: pop
* Usage: ValueType top = stack.pop();
* -----------------------------------
* Removes the top element from this stack and returns it. This
* method signals an error if called on an empty stack.
*/
ValueType pop();
/*
* Method: peek
* Usage: ValueType top = stack.peek();
* ------------------------------------
* Returns the value of top element from this stack, without removing
* it. This method signals an error if called on an empty stack. For
* compatibility with the STL classes, this method is also exported
* under the name <code>top</code>, in which case it returns the value
* by reference.
*/
ValueType peek() const;
ValueType & top();
/*
* Method: toString
* Usage: string str = stack.toString();
* -------------------------------------
* Converts the stack to a printable string representation.
*/
std::string toString();
/*
* Operator: ==
* Usage: stack1 == stack2
* -------------------
* Returns <code>true</code> if <code>stack1</code> and <code>stack2</code>
* contain the same elements.
*/
bool operator==(const Stack & stack2) const;
/*
* Operator: !=
* Usage: stack1 != stack2
* -------------------
* Returns <code>true</code> if <code>stack1</code> and <code>stack2</code>
* do not contain the same elements.
*/
bool operator!=(const Stack & stack2) const;
/* Private section */
/**********************************************************************/
/* Note: Everything below this point in the file is logically part */
/* of the implementation and should not be of interest to clients. */
/**********************************************************************/
/*
* Implementation notes: Stack data structure
* ------------------------------------------
* The easiest way to implement a stack is to store the elements in a
* Vector. Doing so means that the problems of dynamic memory allocation
* and copy assignment are already solved by the implementation of the
* underlying Vector class.
*/
private:
Vector<ValueType> elements;
};
extern void error(std::string msg);
/*
* Stack class implementation
* --------------------------
* The Stack is internally managed using a Vector. This layered design
* makes the implementation extremely simple, to the point that most
* methods can be implemented in as single line.
*/
template <typename ValueType>
Stack<ValueType>::Stack() {
/* Empty */
}
template <typename ValueType>
Stack<ValueType>::~Stack() {
/* Empty */
}
template <typename ValueType>
int Stack<ValueType>::size() const {
return elements.size();
}
template <typename ValueType>
bool Stack<ValueType>::isEmpty() const {
return size() == 0;
}
template <typename ValueType>
void Stack<ValueType>::push(ValueType value) {
elements.add(value);
}
template <typename ValueType>
ValueType Stack<ValueType>::pop() {
if (isEmpty()) error("pop: Attempting to pop an empty stack");
ValueType top = elements[elements.size() - 1];
elements.remove(elements.size() - 1);
return top;
}
template <typename ValueType>
ValueType Stack<ValueType>::peek() const {
if (isEmpty()) error("peek: Attempting to peek at an empty stack");
return elements.get(elements.size() - 1);
}
template <typename ValueType>
ValueType & Stack<ValueType>::top() {
if (isEmpty()) error("top: Attempting to read top of an empty stack");
return elements[elements.size() - 1];
}
template <typename ValueType>
void Stack<ValueType>::clear() {
elements.clear();
}
template <typename ValueType>
std::string Stack<ValueType>::toString() {
ostringstream os;
os << *this;
return os.str();
}
template <typename ValueType>
bool Stack<ValueType>::operator==(const Stack & stack2) const {
if (size() != stack2.size()) return false;
for (int i = 0; i < size(); i++) {
if (this->elements[i] != stack2.elements[i]) {
return false;
}
}
return true;
}
template <typename ValueType>
bool Stack<ValueType>::operator!=(const Stack & stack2) const {
return !(*this == stack2);
}
template <typename ValueType>
std::ostream & operator<<(std::ostream & os, const Stack<ValueType> & stack) {
os << "{";
Stack<ValueType> copy = stack;
Stack<ValueType> reversed;
while (!copy.isEmpty()) {
reversed.push(copy.pop());
}
int len = stack.size();
for (int i = 0; i < len; i++) {
if (i > 0) os << ", ";
writeGenericValue(os, reversed.pop(), true);
}
return os << "}";
}
template <typename ValueType>
std::istream & operator>>(std::istream & is, Stack<ValueType> & stack) {
char ch;
is >> ch;
if (ch != '{') error("operator >>: Missing {");
stack.clear();
is >> ch;
if (ch != '}') {
is.unget();
while (true) {
ValueType value;
readGenericValue(is, value);
stack.push(value);
is >> ch;
if (ch == '}') break;
if (ch != ',') {
error(std::string("operator >>: Unexpected character ") + ch);
}
}
}
return is;
}
// hashing functions for stacks; defined in hashmap.cpp
int hashCode(const Stack<std::string>& s);
int hashCode(const Stack<int>& s);
int hashCode(const Stack<char>& s);
int hashCode(const Stack<long>& s);
int hashCode(const Stack<double>& s);
#endif

240
lib/StanfordCPPLib/strlib.cpp Executable file
View File

@ -0,0 +1,240 @@
/*
* File: strlib.cpp
* ----------------
* This file implements the strlib.h interface.
*/
#include <cctype>
#include <iomanip>
#include <iostream>
#include <sstream>
#include "error.h"
#include "strlib.h"
using namespace std;
/* Function prototypes */
/*
* Implementation notes: numeric conversion
* ----------------------------------------
* These functions use the <sstream> library to perform the conversion.
*/
string integerToString(int n) {
ostringstream stream;
stream << n;
return stream.str();
}
int stringToInteger(string str) {
return stoi(str);
}
string realToString(double d) {
ostringstream stream;
stream << uppercase << d;
return stream.str();
}
double stringToReal(string str) {
return stod(str);
}
/*
* Implementation notes: case conversion
* -------------------------------------
* The functions toUpperCase and toLowerCase return a new string whose
* characters appear in the desired case. These implementations rely on
* the fact that the characters in the string are copied when the
* argument is passed to the function, which makes it possible to change
* the case of the copy without affecting the original.
*/
string toUpperCase(string str) {
int nChars = str.length();
for (int i = 0; i < nChars; i++) {
str[i] = toupper(str[i]);
}
return str;
}
string toLowerCase(string str) {
int nChars = str.length();
for (int i = 0; i < nChars; i++) {
str[i] = tolower(str[i]);
}
return str;
}
/*
* Implementation notes: equalsIgnoreCase
* --------------------------------------
* This implementation uses a for loop to cycle through the characters in
* each string. Converting each string to uppercase and then comparing
* the results makes for a shorter but less efficient implementation.
*/
bool equalsIgnoreCase(string s1, string s2) {
if (s1.length() != s2.length()) return false;
int nChars = s1.length();
for (int i = 0; i < nChars; i++) {
if (tolower(s1[i]) != tolower(s2[i])) return false;
}
return true;
}
/*
* Implementation notes: startsWith, endsWith
* ------------------------------------------
* These implementations are overloaded to allow the second argument to
* be either a string or a character.
*/
bool startsWith(string str, string prefix) {
if (str.length() < prefix.length()) return false;
int nChars = prefix.length();
for (int i = 0; i < nChars; i++) {
if (str[i] != prefix[i]) return false;
}
return true;
}
bool startsWith(string str, char prefix) {
return str.length() > 0 && str[0] == prefix;
}
bool endsWith(string str, string suffix) {
int nChars = suffix.length();
int start = str.length() - nChars;
if (start < 0) return false;
for (int i = 0; i < nChars; i++) {
if (str[start + i] != suffix[i]) return false;
}
return true;
}
bool endsWith(string str, char suffix) {
return str.length() > 0 && str[str.length() - 1] == suffix;
}
string trim(string str) {
int finish = str.length() - 1;
while (finish >= 0 && isspace(str[finish])) {
finish--;
}
int start = 0;
while (start <= finish && isspace(str[start])) {
start++;
}
return str.substr(start, finish - start + 1);
}
/*
* Implementation notes: readQuotedString and writeQuotedString
* ------------------------------------------------------------
* Most of the work in these functions has to do with escape sequences.
*/
static const string STRING_DELIMITERS = ",:)}]\n";
bool stringNeedsQuoting(const string & str) {
int n = str.length();
for (int i = 0; i < n; i++) {
char ch = str[i];
if (isspace(ch)) return false;
if (STRING_DELIMITERS.find(ch) != string::npos) return true;
}
return false;
}
void readQuotedString(istream & is, string & str) {
str = "";
char ch;
while (is.get(ch) && isspace(ch)) {
/* Empty */
}
if (is.fail()) return;
if (ch == '\'' || ch == '"') {
char delim = ch;
while (is.get(ch) && ch != delim) {
if (is.fail()) error("Unterminated string");
if (ch == '\\') {
if (!is.get(ch)) error("Unterminated string");
if (isdigit(ch) || ch == 'x') {
int maxDigits = 3;
int base = 8;
if (ch == 'x') {
base = 16;
maxDigits = 2;
}
int result = 0;
int digit = 0;
for (int i = 0; i < maxDigits && ch != delim; i++) {
if (isdigit(ch)) {
digit = ch - '0';
} else if (base == 16 && isxdigit(ch)) {
digit = toupper(ch) - 'A' + 10;
} else {
break;
}
result = base * result + digit;
if (!is.get(ch)) error("Unterminated string");
}
ch = char(result);
is.unget();
} else {
switch (ch) {
case 'a': ch = '\a'; break;
case 'b': ch = '\b'; break;
case 'f': ch = '\f'; break;
case 'n': ch = '\n'; break;
case 'r': ch = '\r'; break;
case 't': ch = '\t'; break;
case 'v': ch = '\v'; break;
case '"': ch = '"'; break;
case '\'': ch = '\''; break;
case '\\': ch = '\\'; break;
}
}
}
str += ch;
}
} else {
str += ch;
int endTrim = 0;
while (is.get(ch) && STRING_DELIMITERS.find(ch) == string::npos) {
str += ch;
if (!isspace(ch)) endTrim = str.length();
}
if (is) is.unget();
str = str.substr(0, endTrim);
}
}
void writeQuotedString(ostream & os, const string & str, bool forceQuotes) {
if (!forceQuotes && stringNeedsQuoting(str)) forceQuotes = true;
if (forceQuotes) os << '"';
int len = str.length();
for (int i = 0; i < len; i++) {
char ch = str.at(i);
switch (ch) {
case '\a': os << "\\a"; break;
case '\b': os << "\\b"; break;
case '\f': os << "\\f"; break;
case '\n': os << "\\n"; break;
case '\r': os << "\\r"; break;
case '\t': os << "\\t"; break;
case '\v': os << "\\v"; break;
case '\\': os << "\\\\"; break;
default:
if (isprint(ch) && ch != '"') {
os << ch;
} else {
ostringstream oss;
oss << oct << setw(3) << setfill('0') << (int(ch) & 0xFF);
os << "\\" << oss.str();
}
}
}
if (forceQuotes) os << '"';
}

222
lib/StanfordCPPLib/strlib.h Executable file
View File

@ -0,0 +1,222 @@
/*
* File: strlib.h
* --------------
* This file exports several useful string functions that are not
* included in the C++ string library.
*/
#ifndef _strlib_h
#define _strlib_h
#include <iostream>
#include <sstream>
#include <string>
/*
* Function: integerToString
* Usage: string s = integerToString(n);
* -------------------------------------
* Converts an integer into the corresponding string of digits.
* For example, calling <code>integerToString(123)</code> returns
* the string <code>"123"</code>.
*/
std::string integerToString(int n);
/*
* Function: stringToInteger
* Usage: int n = stringToInteger(str);
* ------------------------------------
* Converts a string of digits into an integer. If the string is not a
* legal integer or contains extraneous characters other than whitespace,
* <code>stringToInteger</code> calls <code>error</code> with an
* appropriate message.
*/
int stringToInteger(std::string str);
/*
* Function: realToString
* Usage: string s = realToString(d);
* ----------------------------------
* Converts a floating-point number into the corresponding string form.
* For example, calling <code>realToString(23.45)</code> returns
* the string <code>"23.45"</code>.
*/
std::string realToString(double d);
/*
* Function: stringToReal
* Usage: double d = stringToReal(str);
* ------------------------------------
* Converts a string representing a real number into its corresponding
* value. If the string is not a legal floating-point number or contains
* extraneous characters other than whitespace, <code>stringToReal</code>
* calls <code>error</code> with an appropriate message.
*/
double stringToReal(std::string str);
/*
* Function: toUpperCase
* Usage: string s = toUpperCase(str);
* -----------------------------------
* Returns a new string in which all lowercase characters have been converted
* into their uppercase equivalents.
*/
std::string toUpperCase(std::string str);
/*
* Function: toLowerCase
* Usage: string s = toLowerCase(str);
* -----------------------------------
* Returns a new string in which all uppercase characters have been converted
* into their lowercase equivalents.
*/
std::string toLowerCase(std::string str);
/*
* Function: equalsIgnoreCase
* Usage: if (equalsIgnoreCase(s1, s2)) ...
* ----------------------------------------
* Returns <code>true</code> if <code>s1</code> and <code>s2</code> are
* equal discounting differences in case.
*/
bool equalsIgnoreCase(std::string s1, std::string s2);
/*
* Function: startsWith
* Usage: if (startsWith(str, prefix)) ...
* ---------------------------------------
* Returns <code>true</code> if the string <code>str</code> starts with
* the specified prefix, which may be either a string or a character.
*/
bool startsWith(std::string str, std::string prefix);
bool startsWith(std::string str, char prefix);
/*
* Function: endsWith
* Usage: if (endsWith(str, suffix)) ...
* -------------------------------------
* Returns <code>true</code> if the string <code>str</code> ends with
* the specified suffix, which may be either a string or a character.
*/
bool endsWith(std::string str, std::string suffix);
bool endsWith(std::string str, char suffix);
/*
* Function: trim
* Usage: string trimmed = trim(str);
* ----------------------------------
* Returns a new string after removing any whitespace characters
* from the beginning and end of the argument.
*/
std::string trim(std::string str);
/* Private section */
/**********************************************************************/
/* Note: Everything below this point in the file is logically part */
/* of the implementation and should not be of interest to clients. */
/**********************************************************************/
/*
* Friend function: writeQuotedString
* Usage: writeQuotedString(outfile, str, forceQuotes);
* ----------------------------------------------------
* Writes the string str to outfile surrounded by double quotes, converting
* special characters to escape sequences, as necessary. If the optional
* parameter forceQuotes is explicitly set to false, quotes are included
* in the output only if necessary.
*/
void writeQuotedString(std::ostream & os, const std::string & str,
bool forceQuotes = true);
/*
* Friend function: readQuotedString
* Usage: readQuotedString(infile, str);
* -------------------------------------
* Reads the next string from infile into the reference parameter str.
* If the first character (other than whitespace) is either a single
* or a double quote, this function reads characters up to the
* matching quote, processing standard escape sequences as it goes.
* If not, readString reads characters up to any of the characters
* in the string STRING_DELIMITERS in the implementation file.
*/
void readQuotedString(std::istream & is, std::string & str);
/*
* Friend function: stringNeedsQuoting
* Usage: if (stringNeedsQuoting(str)) ...
* ---------------------------------------
* Checks whether the string needs quoting in order to be read correctly.
*/
bool stringNeedsQuoting(const std::string & str);
/*
* Friend function: writeGenericValue
* Usage: writeGenericValue(os, value, forceQuotes);
* -------------------------------------------------
* Writes a generic value to the output stream. If that value is a string,
* this function uses writeQuotedString to write the value.
*/
template <typename ValueType>
void writeGenericValue(std::ostream & os, const ValueType & value,
bool) {
os << value;
}
template <>
inline void writeGenericValue(std::ostream & os, const std::string & value,
bool forceQuotes) {
writeQuotedString(os, value, forceQuotes);
}
template <typename ValueType>
inline std::string genericValueToString(const ValueType & value,
bool forceQuotes = false) {
std::ostringstream os;
writeGenericValue(os, value, forceQuotes);
return os.str();
}
template <>
inline std::string genericValueToString(const std::string & value,
bool forceQuotes) {
std::ostringstream os;
writeQuotedString(os, value, forceQuotes);
return os.str();
}
/*
* Friend function: readGenericValue
* Usage: readGenericValue(is, value);
* -----------------------------------
* Reads a generic value from the input stream. If that value is a string,
* this function uses readQuotedString to read the value.
*/
template <typename ValueType>
void readGenericValue(std::istream & is, ValueType & value) {
is >> value;
}
template <>
inline void readGenericValue(std::istream & is, std::string & value) {
readQuotedString(is, value);
}
#endif

727
lib/StanfordCPPLib/vector.h Executable file
View File

@ -0,0 +1,727 @@
/*
* File: vector.h
* --------------
* This file exports the <code>Vector</code> class, which provides an
* efficient, safe, convenient replacement for the array type in C++.
*/
#ifndef _vector_h
#define _vector_h
#include <iterator>
#include <iostream>
#include <sstream>
#include <string>
#include "foreach.h"
#include "strlib.h"
/*
* Class: Vector<ValueType>
* ------------------------
* This class stores an ordered list of values similar to an array.
* It supports traditional array selection using square brackets, but
* also supports inserting and deleting elements. It is similar in
* function to the STL <code>vector</code> type, but is simpler both
* to use and to implement.
*/
template <typename ValueType>
class Vector {
public:
/*
* Constructor: Vector
* Usage: Vector<ValueType> vec;
* Vector<ValueType> vec(n, value);
* ---------------------------------------
* Initializes a new vector. The default constructor creates an
* empty vector. The second form creates an array with <code>n</code>
* elements, each of which is initialized to <code>value</code>;
* if <code>value</code> is missing, the elements are initialized
* to the default value for the type.
*/
Vector();
explicit Vector(int n, ValueType value = ValueType());
/*
* Destructor: ~Vector
* -------------------
* Frees any heap storage allocated by this vector.
*/
virtual ~Vector();
/*
* Method: size
* Usage: int nElems = vec.size();
* -------------------------------
* Returns the number of elements in this vector.
*/
int size() const;
/*
* Method: isEmpty
* Usage: if (vec.isEmpty()) ...
* -----------------------------
* Returns <code>true</code> if this vector contains no elements.
*/
bool isEmpty() const;
/*
* Method: clear
* Usage: vec.clear();
* -------------------
* Removes all elements from this vector.
*/
void clear();
/*
* Method: get
* Usage: ValueType val = vec.get(index);
* --------------------------------------
* Returns the element at the specified index in this vector. This
* method signals an error if the index is not in the array range.
*/
const ValueType & get(int index) const;
/*
* Method: set
* Usage: vec.set(index, value);
* -----------------------------
* Replaces the element at the specified index in this vector with
* a new value. The previous value at that index is overwritten.
* This method signals an error if the index is not in the array range.
*/
void set(int index, const ValueType & value);
/*
* Method: insert
* Usage: vec.insert(0, value);
* ----------------------------
* Inserts the element into this vector before the specified index.
* All subsequent elements are shifted one position to the right. This
* method signals an error if the index is outside the range from 0
* up to and including the length of the vector.
*/
void insert(int index, ValueType value);
/*
* Method: remove
* Usage: vec.remove(index);
* -------------------------
* Removes the element at the specified index from this vector.
* All subsequent elements are shifted one position to the left. This
* method signals an error if the index is outside the array range.
*/
void remove(int index);
/*
* Method: add
* Usage: vec.add(value);
* ----------------------
* Adds a new value to the end of this vector. To ensure compatibility
* with the <code>vector</code> class in the Standard Template Library,
* this method is also called <code>push_back</code>.
*/
void add(ValueType value);
void push_back(ValueType value);
/*
* Operator: []
* Usage: vec[index]
* -----------------
* Overloads <code>[]</code> to select elements from this vector.
* This extension enables the use of traditional array notation to
* get or set individual elements. This method signals an error if
* the index is outside the array range. The file supports two
* versions of this operator, one for <code>const</code> vectors and
* one for mutable vectors.
*/
ValueType & operator[](int index);
const ValueType & operator[](int index) const;
/*
* Operator: +
* Usage: v1 + v2
* --------------
* Concatenates two vectors.
*/
Vector operator+(const Vector & v2) const;
/*
* Operator: +=
* Usage: v1 += v2;
* v1 += value;
* -------------------
* Adds all of the elements from <code>v2</code> (or the single
* specified value) to <code>v1</code>. As a convenience, the
* <code>Vector</code> package also overloads the comma operator so
* that it is possible to initialize a vector like this:
*
*<pre>
* Vector&lt;int&gt; digits;
* digits += 0, 1, 2, 3, 4, 5, 6, 7, 8, 9;
*</pre>
*/
Vector & operator+=(const Vector & v2);
Vector & operator+=(const ValueType & value);
bool operator==(const Vector & v2);
bool operator!=(const Vector & v2);
/*
* Method: toString
* Usage: string str = vec.toString();
* -----------------------------------
* Converts the vector to a printable string representation.
*/
std::string toString();
/*
* Method: mapAll
* Usage: vec.mapAll(fn);
* ----------------------
* Calls the specified function on each element of the vector in
* ascending index order.
*/
void mapAll(void (*fn)(ValueType)) const;
void mapAll(void (*fn)(const ValueType &)) const;
template <typename FunctorType>
void mapAll(FunctorType fn) const;
/*
* Additional Vector operations
* ----------------------------
* In addition to the methods listed in this interface, the Vector
* class supports the following operations:
*
* - Stream I/O using the << and >> operators
* - Deep copying for the copy constructor and assignment operator
* - Iteration using the range-based for statement or STL iterators
*
* The iteration forms process the Vector in index order.
*/
/* Private section */
/**********************************************************************/
/* Note: Everything below this point in the file is logically part */
/* of the implementation and should not be of interest to clients. */
/**********************************************************************/
private:
/*
* Implementation notes: Vector data structure
* -------------------------------------------
* The elements of the Vector are stored in a dynamic array of
* the specified element type. If the space in the array is ever
* exhausted, the implementation doubles the array capacity.
*/
/* Instance variables */
ValueType *elements; /* A dynamic array of the elements */
int capacity; /* The allocated size of the array */
int count; /* The number of elements in use */
/* Private methods */
void expandCapacity();
void deepCopy(const Vector & src);
/*
* Hidden features
* ---------------
* The remainder of this file consists of the code required to
* support deep copying and iteration. Including these methods
* in the public interface would make that interface more
* difficult to understand for the average client.
*/
public:
/*
* Deep copying support
* --------------------
* This copy constructor and operator= are defined to make a deep copy,
* making it possible to pass or return vectors by value and assign
* from one vector to another.
*/
Vector(const Vector & src);
Vector & operator=(const Vector & src);
/*
* Operator: ,
* -----------
* Adds an element to the vector passed as the left-hand operatand.
* This form makes it easier to initialize vectors in old versions of C++.
*/
Vector & operator,(const ValueType & value);
/*
* Iterator support
* ----------------
* The classes in the StanfordCPPLib collection implement input
* iterators so that they work symmetrically with respect to the
* corresponding STL classes.
*/
class iterator :
public std::iterator<std::random_access_iterator_tag, ValueType> {
private:
const Vector *vp;
int index;
public:
iterator() {
this->vp = NULL;
}
iterator(const iterator & it) {
this->vp = it.vp;
this->index = it.index;
}
iterator(const Vector *vp, int index) {
this->vp = vp;
this->index = index;
}
iterator & operator++() {
index++;
return *this;
}
iterator operator++(int) {
iterator copy(*this);
operator++();
return copy;
}
iterator & operator--() {
index--;
return *this;
}
iterator operator--(int) {
iterator copy(*this);
operator--();
return copy;
}
bool operator==(const iterator & rhs) {
return vp == rhs.vp && index == rhs.index;
}
bool operator!=(const iterator & rhs) {
return !(*this == rhs);
}
bool operator<(const iterator & rhs) {
extern void error(std::string msg);
if (vp != rhs.vp) error("Iterators are in different vectors");
return index < rhs.index;
}
bool operator<=(const iterator & rhs) {
extern void error(std::string msg);
if (vp != rhs.vp) error("Iterators are in different vectors");
return index <= rhs.index;
}
bool operator>(const iterator & rhs) {
extern void error(std::string msg);
if (vp != rhs.vp) error("Iterators are in different vectors");
return index > rhs.index;
}
bool operator>=(const iterator & rhs) {
extern void error(std::string msg);
if (vp != rhs.vp) error("Iterators are in different vectors");
return index >= rhs.index;
}
iterator operator+(const int & rhs) {
return iterator(vp, index + rhs);
}
iterator operator+=(const int & rhs) {
index += rhs;
return *this;
}
iterator operator-(const int & rhs) {
return iterator(vp, index - rhs);
}
iterator operator-=(const int & rhs) {
index -= rhs;
return *this;
}
int operator-(const iterator & rhs) {
extern void error(std::string msg);
if (vp != rhs.vp) error("Iterators are in different vectors");
return index - rhs.index;
}
ValueType & operator*() {
return vp->elements[index];
}
ValueType *operator->() {
return &vp->elements[index];
}
ValueType & operator[](int k) {
return vp->elements[index + k];
}
};
iterator begin() const {
return iterator(this, 0);
}
iterator end() const {
return iterator(this, count);
}
};
/* Implementation section */
extern void error(std::string msg);
/*
* Implementation notes: Vector constructor and destructor
* -------------------------------------------------------
* The constructor allocates storage for the dynamic array
* and initializes the other fields of the object. The
* destructor frees the memory used for the array.
*/
template <typename ValueType>
Vector<ValueType>::Vector() {
count = capacity = 0;
elements = NULL;
}
template <typename ValueType>
Vector<ValueType>::Vector(int n, ValueType value) {
count = capacity = n;
elements = (n == 0) ? NULL : new ValueType[n];
for (int i = 0; i < n; i++) {
elements[i] = value;
}
}
template <typename ValueType>
Vector<ValueType>::~Vector() {
if (elements != NULL) delete[] elements;
}
/*
* Implementation notes: Vector methods
* ------------------------------------
* The basic Vector methods are straightforward and should require
* no detailed documentation.
*/
template <typename ValueType>
int Vector<ValueType>::size() const {
return count;
}
template <typename ValueType>
bool Vector<ValueType>::isEmpty() const {
return count == 0;
}
template <typename ValueType>
void Vector<ValueType>::clear() {
if (elements != NULL) delete[] elements;
count = capacity = 0;
elements = NULL;
}
template <typename ValueType>
const ValueType & Vector<ValueType>::get(int index) const {
if (index < 0 || index >= count) error("get: index out of range");
return elements[index];
}
template <typename ValueType>
void Vector<ValueType>::set(int index, const ValueType & value) {
if (index < 0 || index >= count) error("set: index out of range");
elements[index] = value;
}
/*
* Implementation notes: insert, remove, add
* -----------------------------------------
* These methods must shift the existing elements in the array to
* make room for a new element or to close up the space left by a
* deleted one.
*/
template <typename ValueType>
void Vector<ValueType>::insert(int index, ValueType value) {
if (count == capacity) expandCapacity();
if (index < 0 || index > count) {
error("insert: index out of range");
}
for (int i = count; i > index; i--) {
elements[i] = elements[i - 1];
}
elements[index] = value;
count++;
}
template <typename ValueType>
void Vector<ValueType>::remove(int index) {
if (index < 0 || index >= count) error("remove: index out of range");
for (int i = index; i < count - 1; i++) {
elements[i] = elements[i + 1];
}
count--;
}
template <typename ValueType>
void Vector<ValueType>::add(ValueType value) {
insert(count, value);
}
template <typename ValueType>
void Vector<ValueType>::push_back(ValueType value) {
insert(count, value);
}
/*
* Implementation notes: Vector selection
* --------------------------------------
* The following code implements traditional array selection using
* square brackets for the index.
*/
template <typename ValueType>
ValueType & Vector<ValueType>::operator[](int index) {
if (index < 0 || index >= count) error("Selection index out of range");
return elements[index];
}
template <typename ValueType>
const ValueType & Vector<ValueType>::operator[](int index) const {
if (index < 0 || index >= count) error("Selection index out of range");
return elements[index];
}
template <typename ValueType>
Vector<ValueType> Vector<ValueType>::operator+(const Vector & v2) const {
Vector<ValueType> vec = *this;
foreach (ValueType value in v2) {
vec.add(value);
}
return vec;
}
template <typename ValueType>
Vector<ValueType> & Vector<ValueType>::operator+=(const Vector & v2) {
foreach (ValueType value in v2) {
*this += value;
}
return *this;
}
template <typename ValueType>
Vector<ValueType> & Vector<ValueType>::operator+=(const ValueType & value) {
this->add(value);
return *this;
}
template <typename ValueType>
bool Vector<ValueType>::operator==(const Vector & v2) {
if (this->size() != v2.size()) {
return false;
}
for (int i = 0, size = this->size(); i < size; i++) {
if (this->get(i) != v2.get(i)) {
return false;
}
}
return true;
}
template <typename ValueType>
bool Vector<ValueType>::operator!=(const Vector & v2) {
return !(*this == v2);
}
template <typename ValueType>
std::string Vector<ValueType>::toString() {
ostringstream os;
os << *this;
return os.str();
}
/*
* Implementation notes: copy constructor and assignment operator
* --------------------------------------------------------------
* The constructor and assignment operators follow a standard paradigm,
* as described in the associated textbook.
*/
template <typename ValueType>
Vector<ValueType>::Vector(const Vector & src) {
deepCopy(src);
}
template <typename ValueType>
Vector<ValueType> & Vector<ValueType>::operator=(const Vector & src) {
if (this != &src) {
if (elements != NULL) delete[] elements;
deepCopy(src);
}
return *this;
}
template <typename ValueType>
void Vector<ValueType>::deepCopy(const Vector & src) {
count = capacity = src.count;
elements = (capacity == 0) ? NULL : new ValueType[capacity];
for (int i = 0; i < count; i++) {
elements[i] = src.elements[i];
}
}
/*
* Implementation notes: The , operator
* ------------------------------------
* The comma operator works adding the right operand to the vector and
* then returning the vector by reference so that it is set for the next
* value in the chain.
*/
template <typename ValueType>
Vector<ValueType> & Vector<ValueType>::operator,(const ValueType & value) {
this->add(value);
return *this;
}
/*
* Implementation notes: mapAll
* ----------------------------
* The various versions of the mapAll function apply the function or
* function object to each element in ascending index order.
*/
template <typename ValueType>
void Vector<ValueType>::mapAll(void (*fn)(ValueType)) const {
for (int i = 0; i < count; i++) {
fn(elements[i]);
}
}
template <typename ValueType>
void Vector<ValueType>::mapAll(void (*fn)(const ValueType &)) const {
for (int i = 0; i < count; i++) {
fn(elements[i]);
}
}
template <typename ValueType>
template <typename FunctorType>
void Vector<ValueType>::mapAll(FunctorType fn) const {
for (int i = 0; i < count; i++) {
fn(elements[i]);
}
}
/*
* Implementation notes: expandCapacity
* ------------------------------------
* This function doubles the array capacity, copies the old elements
* into the new array, and then frees the old one.
*/
template <typename ValueType>
void Vector<ValueType>::expandCapacity() {
capacity = max(1, capacity * 2);
ValueType *array = new ValueType[capacity];
for (int i = 0; i < count; i++) {
array[i] = elements[i];
}
if (elements != NULL) delete[] elements;
elements = array;
}
/*
* Implementation notes: << and >>
* -------------------------------
* The insertion and extraction operators use the template facilities in
* strlib.h to read and write generic values in a way that treats strings
* specially.
*/
template <typename ValueType>
std::ostream & operator<<(std::ostream & os, const Vector<ValueType> & vec) {
os << "{";
int len = vec.size();
for (int i = 0; i < len; i++) {
if (i > 0) os << ", ";
writeGenericValue(os, vec[i], true);
}
return os << "}";
}
template <typename ValueType>
std::istream & operator>>(std::istream & is, Vector<ValueType> & vec) {
char ch;
is >> ch;
if (ch != '{') error("operator >>: Missing {");
vec.clear();
is >> ch;
if (ch != '}') {
is.unget();
while (true) {
ValueType value;
readGenericValue(is, value);
vec += value;
is >> ch;
if (ch == '}') break;
if (ch != ',') {
error(std::string("operator >>: Unexpected character ") + ch);
}
}
}
return is;
}
// hashing functions for vectors; defined in hashmap.cpp
int hashCode(const Vector<std::string>& v);
int hashCode(const Vector<int>& v);
int hashCode(const Vector<char>& v);
int hashCode(const Vector<long>& v);
int hashCode(const Vector<double>& v);
#endif

BIN
res/EnglishWords.dat Executable file

Binary file not shown.

144
res/expected-output-1.txt Executable file
View File

@ -0,0 +1,144 @@
Welcome to CS 106B Boggle!
This game is a search for words on a 2-D board of letter cubes.
The good news is that you might improve your vocabulary a bit.
The bad news is that you're probably going to lose miserably to
this little dictionary-toting hunk of silicon.
If only YOU had a gig of RAM!
Press Enter to begin the game ...
Do you want to generate a random board? y
It's your turn!
FYCL
IOMG
ORIL
HJHU
Your words (0): {}
Your score: 0
Type a word (or press Enter to end your turn): foo
That word is not in the dictionary.
FYCL
IOMG
ORIL
HJHU
Your words (0): {}
Your score: 0
Type a word (or press Enter to end your turn): bar
That word is not long enough.
FYCL
IOMG
ORIL
HJHU
Your words (0): {}
Your score: 0
Type a word (or press Enter to end your turn): foil
You found a new word! "FOIL"
FYCL
IOMG
ORIL
HJHU
Your words (1): {"FOIL"}
Your score: 1
Type a word (or press Enter to end your turn): foil
You have already guessed that word.
FYCL
IOMG
ORIL
HJHU
Your words (1): {"FOIL"}
Your score: 1
Type a word (or press Enter to end your turn): tuba
That word can't be formed on this board.
FYCL
IOMG
ORIL
HJHU
Your words (1): {"FOIL"}
Your score: 1
Type a word (or press Enter to end your turn): roof
You found a new word! "ROOF"
FYCL
IOMG
ORIL
HJHU
Your words (2): {"FOIL", "ROOF"}
Your score: 2
Type a word (or press Enter to end your turn): form
You found a new word! "FORM"
FYCL
IOMG
ORIL
HJHU
Your words (3): {"FOIL", "FORM", "ROOF"}
Your score: 3
Type a word (or press Enter to end your turn): room
You found a new word! "ROOM"
FYCL
IOMG
ORIL
HJHU
Your words (4): {"FOIL", "FORM", "ROOF", "ROOM"}
Your score: 4
Type a word (or press Enter to end your turn): roomy
You found a new word! "ROOMY"
FYCL
IOMG
ORIL
HJHU
Your words (5): {"FOIL", "FORM", "ROOF", "ROOM", "ROOMY"}
Your score: 6
Type a word (or press Enter to end your turn): grim
That word can't be formed on this board.
FYCL
IOMG
ORIL
HJHU
Your words (5): {"FOIL", "FORM", "ROOF", "ROOM", "ROOMY"}
Your score: 6
Type a word (or press Enter to end your turn): grim
That word can't be formed on this board.
FYCL
IOMG
ORIL
HJHU
Your words (5): {"FOIL", "FORM", "ROOF", "ROOM", "ROOMY"}
Your score: 6
Type a word (or press Enter to end your turn): banana
That word can't be formed on this board.
FYCL
IOMG
ORIL
HJHU
Your words (5): {"FOIL", "FORM", "ROOF", "ROOM", "ROOMY"}
Your score: 6
Type a word (or press Enter to end your turn): room
You have already guessed that word.
FYCL
IOMG
ORIL
HJHU
Your words (5): {"FOIL", "FORM", "ROOF", "ROOM", "ROOMY"}
Your score: 6
Type a word (or press Enter to end your turn):
It's my turn!
My words (16): {"COIF", "COIL", "COIR", "CORM", "FIRM", "GIRO", "GLIM", "HOOF", "IGLU", "LIMO", "LIMY", "MIRI", "MOIL", "MOOR", "RIMY", "ROIL"}
My score: 16
Ha ha ha, I destroyed you. Better luck next time, puny human!
Play again (Y/N)? n
Have a nice day.

232
res/expected-output-2.txt Executable file
View File

@ -0,0 +1,232 @@
Welcome to CS 106B Boggle!
This game is a search for words on a 2-D board of letter cubes.
The good news is that you might improve your vocabulary a bit.
The bad news is that you're probably going to lose miserably to
this little dictionary-toting hunk of silicon.
If only YOU had a gig of RAM!
Press Enter to begin the game ...
Do you want to generate a random board? n
Type the 16 letters to appear on the board: asdf
That is not a valid 16-letter board String. Try again.
Type the 16 letters to appear on the board: a0x3f-JKLxyz1234
That is not a valid 16-letter board String. Try again.
Type the 16 letters to appear on the board: ABCDEFGHIJKLMNOPQ
That is not a valid 16-letter board String. Try again.
Type the 16 letters to appear on the board: ABCDEFGHIJKLMNOP
It's your turn!
ABCD
EFGH
IJKL
MNOP
Your words (0): {}
Your score: 0
Type a word (or press Enter to end your turn): fink
You found a new word! "FINK"
ABCD
EFGH
IJKL
MNOP
Your words (1): {"FINK"}
Your score: 1
Type a word (or press Enter to end your turn): glop
You found a new word! "GLOP"
ABCD
EFGH
IJKL
MNOP
Your words (2): {"FINK", "GLOP"}
Your score: 2
Type a word (or press Enter to end your turn): mink
You found a new word! "MINK"
ABCD
EFGH
IJKL
MNOP
Your words (3): {"FINK", "GLOP", "MINK"}
Your score: 3
Type a word (or press Enter to end your turn):
It's my turn!
My words (5): {"FINO", "JINK", "KNIFE", "KNOP", "PLONK"}
My score: 7
Ha ha ha, I destroyed you. Better luck next time, puny human!
Play again (Y/N)? y
Do you want to generate a random board? n
Type the 16 letters to appear on the board: ABCDEFGHIJKLMNOP
It's your turn!
ABCD
EFGH
IJKL
MNOP
Your words (0): {}
Your score: 0
Type a word (or press Enter to end your turn): fink
You found a new word! "FINK"
ABCD
EFGH
IJKL
MNOP
Your words (1): {"FINK"}
Your score: 1
Type a word (or press Enter to end your turn): Fino
You found a new word! "FINO"
ABCD
EFGH
IJKL
MNOP
Your words (2): {"FINK", "FINO"}
Your score: 2
Type a word (or press Enter to end your turn): glop
You found a new word! "GLOP"
ABCD
EFGH
IJKL
MNOP
Your words (3): {"FINK", "FINO", "GLOP"}
Your score: 3
Type a word (or press Enter to end your turn): knife
You found a new word! "KNIFE"
ABCD
EFGH
IJKL
MNOP
Your words (4): {"FINK", "FINO", "GLOP", "KNIFE"}
Your score: 5
Type a word (or press Enter to end your turn): mink
You found a new word! "MINK"
ABCD
EFGH
IJKL
MNOP
Your words (5): {"FINK", "FINO", "GLOP", "KNIFE", "MINK"}
Your score: 6
Type a word (or press Enter to end your turn): JINK
You found a new word! "JINK"
ABCD
EFGH
IJKL
MNOP
Your words (6): {"FINK", "FINO", "GLOP", "JINK", "KNIFE", "MINK"}
Your score: 7
Type a word (or press Enter to end your turn): plonk
You found a new word! "PLONK"
ABCD
EFGH
IJKL
MNOP
Your words (7): {"FINK", "FINO", "GLOP", "JINK", "KNIFE", "MINK", "PLONK"}
Your score: 9
Type a word (or press Enter to end your turn): KnOp
You found a new word! "KNOP"
ABCD
EFGH
IJKL
MNOP
Your words (8): {"FINK", "FINO", "GLOP", "JINK", "KNIFE", "KNOP", "MINK", "PLONK"}
Your score: 10
Type a word (or press Enter to end your turn):
It's my turn!
My words (0): {}
My score: 0
WOW, you defeated me! Congratulations!
Play again (Y/N)? y
Do you want to generate a random board? n
Type the 16 letters to appear on the board: ABDDRCSIIMINSETA
It's your turn!
ABDD
RCSI
IMIN
SETA
Your words (0): {}
Your score: 0
Type a word (or press Enter to end your turn): discriminate
You found a new word! "DISCRIMINATE"
ABDD
RCSI
IMIN
SETA
Your words (1): {"DISCRIMINATE"}
Your score: 9
Type a word (or press Enter to end your turn): discriminates
You found a new word! "DISCRIMINATES"
ABDD
RCSI
IMIN
SETA
Your words (2): {"DISCRIMINATE", "DISCRIMINATES"}
Your score: 19
Type a word (or press Enter to end your turn): animis
You found a new word! "ANIMIS"
ABDD
RCSI
IMIN
SETA
Your words (3): {"ANIMIS", "DISCRIMINATE", "DISCRIMINATES"}
Your score: 22
Type a word (or press Enter to end your turn): seismic
You found a new word! "SEISMIC"
ABDD
RCSI
IMIN
SETA
Your words (4): {"ANIMIS", "DISCRIMINATE", "DISCRIMINATES", "SEISMIC"}
Your score: 26
Type a word (or press Enter to end your turn): racism
You found a new word! "RACISM"
ABDD
RCSI
IMIN
SETA
Your words (5): {"ANIMIS", "DISCRIMINATE", "DISCRIMINATES", "RACISM", "SEISMIC"}
Your score: 29
Type a word (or press Enter to end your turn): criminate
You found a new word! "CRIMINATE"
ABDD
RCSI
IMIN
SETA
Your words (6): {"ANIMIS", "CRIMINATE", "DISCRIMINATE", "DISCRIMINATES", "RACISM", "SEISMIC"}
Your score: 35
Type a word (or press Enter to end your turn): tansies
You found a new word! "TANSIES"
ABDD
RCSI
IMIN
SETA
Your words (7): {"ANIMIS", "CRIMINATE", "DISCRIMINATE", "DISCRIMINATES", "RACISM", "SEISMIC", "TANSIES"}
Your score: 39
Type a word (or press Enter to end your turn):
It's my turn!
My words (127): {"ABRI", "ABRIS", "ABSCISE", "ACINI", "ACME", "ACMES", "AIMS", "AINS", "ANIME", "ANIMES", "ANIMI", "ANIS", "ANISIC", "ANTE", "ANTES", "ANTI", "ANTIC", "ANTICS", "ANTIS", "ARBS", "ARCS", "ARISE", "ARMET", "ARMIES", "ARMS", "ATES", "BARIC", "BARM", "BARMIE", "BARMS", "BRIE", "BRIES", "BRIM", "BRIMS", "BRIS", "CABS", "CARB", "CARBS", "CARIES", "CITE", "CITES", "CRAB", "CRABS", "CRIES", "CRIME", "CRIMES", "CRIMINATES", "CRIS", "DINS", "DINT", "DISBAR", "DISC", "DISCI", "DISME", "DISMES", "EMIC", "EMIR", "EMIT", "ETIC", "ETNA", "INIA", "INTI", "INTIME", "INTIS", "ISBA", "ISMS", "ITEM", "ITEMS", "MESIC", "META", "METIS", "MICA", "MICRA", "MIES", "MINA", "MINI", "MINIS", "MINT", "MISDID", "MISE", "MITE", "MITES", "NATES", "NATIES", "NIES", "NIMS", "NISI", "RACISMS", "RICIN", "RICINS", "RIES", "RIME", "RIMES", "RIMS", "RISE", "SCAB", "SCAR", "SCRIM", "SCRIMS", "SEIS", "SEISIN", "SEISM", "SEMI", "SEMINA", "SEMIS", "SETA", "SICS", "SIES", "SIMIAN", "SIMIANS", "SIMS", "SITE", "SITES", "SMIT", "SMITE", "SMITES", "SNIT", "TAIN", "TAINS", "TANS", "TEIID", "TEIIDS", "TICS", "TIES", "TIME", "TIMES", "TINS"}
My score: 219
Ha ha ha, I destroyed you. Better luck next time, puny human!
Play again (Y/N)? n
Have a nice day.

22
src/Boggle.cpp Executable file
View File

@ -0,0 +1,22 @@
// This is the .cpp file you will edit and turn in.
// We have provided a minimal skeleton for you,
// but you must finish it as described in the spec.
// Also remove these comments here and add your own.
// TODO: remove this comment header and replace it with your own
#include <sstream>
#include "Boggle.h"
#include "random.h"
#include "shuffle.h"
#include "strlib.h"
static const int NUM_CUBES = 16; // the number of cubes in the game
static const int CUBE_SIDES = 6; // the number of sides on each cube
static string CUBES[NUM_CUBES] = { // the letters on all 6 sides of every cube
"AAEEGN", "ABBJOO", "ACHOPS", "AFFKPS",
"AOOTTW", "CIMOTU", "DEILRX", "DELRVY",
"DISTTY", "EEGHNW", "EEINSU", "EHRTVW",
"EIOSST", "ELRTTY", "HIMNQU", "HLNNRZ"
};
// TODO: implement the members you declared in Boggle.h

29
src/Boggle.h Executable file
View File

@ -0,0 +1,29 @@
// This is the .h file you will edit and turn in.
// We have provided a minimal skeleton for you,
// but you must finish it as described in the spec.
// Also remove these comments here and add your own, as well as on the members.
// TODO: remove this comment header and replace it with your own
#ifndef _boggle_h
#define _boggle_h
#include <iostream>
#include <string>
// TODO: include any other header files you need
using namespace std;
class Boggle {
public:
const string DICTIONARY_FILE = "EnglishWords.dat";
const int MIN_WORD_LENGTH = 4;
const int BOARD_SIZE = 4;
// TODO: decide the public member functions and declare them
private:
// TODO: decide the private member variables/functions and declare them
};
#endif

79
src/bogglemain.cpp Executable file
View File

@ -0,0 +1,79 @@
/*
* TDDD86 Boggle
* This file contains the main program and user interface for running your
* Boggle game. We provide you a skeleton of this file that contains a shell
* of the overall logic, but you must complete the playOneGame function.
*
* The playOneGame function talks to the Boggle class that you will write.
* This file should contain all user interaction (cout / cin), while the Boggle
* class should contain ALL game state such as the 16 letter cubes, the set of
* words that have been formed, the algorithms for searching for words, etc.
*
* Please do not modify this provided file. Your turned-in files should work
* with an unmodified version of all provided code files.
*/
#include <fstream>
#include <iostream>
#include <string>
#include "random.h"
#include "strlib.h"
#include "Boggle.h"
#include "bogglemain.h"
using namespace std;
int main() {
intro();
// play games repeatedly until user decides to quit
Boggle boggle;
while (true) {
playOneGame(boggle);
cout << endl;
if (!yesOrNo("Play again (Y/N)? ")) {
break;
}
}
cout << "Have a nice day." << endl;
return 0;
}
/*
* Explains the program to the user.
*/
void intro() {
cout << "Welcome to TDDD86 Boggle!" << endl;
cout << "This game is a search for words on a 2-D board of letter cubes." << endl;
cout << "The good news is that you might improve your vocabulary a bit." << endl;
cout << "The bad news is that you're probably going to lose miserably to" << endl;
cout << "this little dictionary-toting hunk of silicon." << endl;
cout << "If only YOU had a gig of RAM!" << endl;
cout << endl;
cout << "Press Enter to begin the game ... ";
string line;
getline(cin, line);
}
/*
* Prompts the user to answer a yes/no question and returns true if the user
* typed 'yes' (or anything that starts with a 'y', case-insensitively),
* false if the user types anything that starts with 'n', or re-prompts if
* the user doesn't type a 'y' or 'n' word.
*/
bool yesOrNo(string prompt) {
cout << prompt;
while (true) {
string answer;
getline(cin, answer);
answer = trim(toLowerCase(answer));
if (startsWith(answer, 'y')) {
return true;
} else if (startsWith(answer, 'n')) {
return false;
} else {
cout << "Please type a word that begins with 'y' or 'n'." << endl;
}
}
}

21
src/bogglemain.h Executable file
View File

@ -0,0 +1,21 @@
/*
* TDDD86 Boggle
* This file declares required function prototypes that are defined in
* our provided bogglemain.cpp and your boggleplay.cpp that you will write.
* See the respective .cpp files for implementation comments for each function.
* Please do not modify this provided file.
*/
#ifndef _bogglemain_h
#define _bogglemain_h
#include "Boggle.h"
#include <string>
using namespace std;
void intro();
void playOneGame(Boggle& boggle);
bool yesOrNo(string prompt);
void clearConsole();
#endif

32
src/boggleplay.cpp Executable file
View File

@ -0,0 +1,32 @@
// You will edit and turn in this CPP file.
// Also remove these comments here and add your own.
// TODO: remove this comment header and replace with your own
#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <sstream>
#include "Boggle.h"
#include "bogglemain.h"
#include "strlib.h"
// TODO: include any other header files you need
/*
* Plays one game of Boggle using the given boggle game state object.
*/
void playOneGame(Boggle& boggle) {
// TODO: implement this function (and add any other functions you like to help you)
}
/*
* Erases all currently visible text from the output console.
*/
void clearConsole() {
#if defined(_WIN32) || defined(_WIN64)
std::system("CLS");
#else
// assume POSIX
std::system("clear");
#endif
}

3
src/readme.txt Executable file
View File

@ -0,0 +1,3 @@
This directory contains the source code files (*.cpp, *.h)
that you will write as you complete the assignment.
We will also put any instructor-provided code here.

78
src/shuffle.h Executable file
View File

@ -0,0 +1,78 @@
/*
* TDDD86 Boggle
* This file contains implementation of a shuffling function that operates on
* a 1-D and 2-D array, vector, or Grid of any type.
* You can use it in your program.
* Please do not modify this provided file.
*/
#ifndef _shuffle_h
#define _shuffle_h
#include "grid.h"
#include "random.h"
#include <vector>
template <typename T>
void shuffle(T* array, int length) {
for (int i = 0; i < length; i++) {
int j = randomInteger(i, length - 1);
if (i != j) {
T temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
}
template <typename T>
void shuffle(T** array2d, int rows, int cols) {
int length = rows * cols;
for (int i = 0; i < length; i++) {
int j = randomInteger(i, length - 1);
if (i != j) {
int r1 = i / cols;
int c1 = i % cols;
int r2 = j / cols;
int c2 = j % cols;
T temp = array2d[r1][c1];
array2d[r1][c1] = array2d[r2][c2];
array2d[r2][c2] = temp;
}
}
}
template <typename T>
void shuffle(vector<T>& v) {
for (int i = 0, length = v.size(); i < length; i++) {
int j = randomInteger(i, length - 1);
if (i != j) {
T temp = v[i];
v[i] = v[j];
v[j] = temp;
}
}
}
template <typename T>
void shuffle(Grid<T>& grid) {
int rows = grid.numRows();
int cols = grid.numCols();
int length = rows * cols;
for (int i = 0; i < length; i++) {
int j = randomInteger(i, length - 1);
if (i != j) {
int r1 = i / cols;
int c1 = i % cols;
int r2 = j / cols;
int c2 = j % cols;
T temp = grid[r1][c1];
grid[r1][c1] = grid[r2][c2];
grid[r2][c2] = temp;
}
}
}
#endif