Init
This commit is contained in:
commit
b9b11d401e
12
.gitignore
vendored
Executable file
12
.gitignore
vendored
Executable file
@ -0,0 +1,12 @@
|
||||
*~
|
||||
|
||||
.DS_Store
|
||||
|
||||
*.pro.user.*
|
||||
*.pro.user
|
||||
|
||||
build-*/
|
||||
*.app
|
||||
*.exe
|
||||
|
||||
build
|
60
Boggle.pro
Executable file
60
Boggle.pro
Executable 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
42
lib/StanfordCPPLib/error.cpp
Executable 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
56
lib/StanfordCPPLib/error.h
Executable 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
217
lib/StanfordCPPLib/foreach.h
Executable 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 << str << 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
549
lib/StanfordCPPLib/grid.h
Executable 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<double> createIdentityMatrix(int n) {
|
||||
* Grid<double> matrix(n, n);
|
||||
* for (int i = 0; i < 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
316
lib/StanfordCPPLib/lexicon.cpp
Executable 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
366
lib/StanfordCPPLib/lexicon.h
Executable 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 ¤tSetWord;
|
||||
if (currentSetWord == "" || currentDawgPrefix < currentSetWord) {
|
||||
tmpWord = currentDawgPrefix + lp->ordToChar(edgePtr->letter);
|
||||
return &tmpWord;
|
||||
} else {
|
||||
return ¤tSetWord;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
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
919
lib/StanfordCPPLib/map.h
Executable 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
|
218
lib/StanfordCPPLib/private/_main.h_
Executable file
218
lib/StanfordCPPLib/private/_main.h_
Executable 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
|
62
lib/StanfordCPPLib/private/main.h
Executable file
62
lib/StanfordCPPLib/private/main.h
Executable 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
|
63
lib/StanfordCPPLib/private/randompatch.h
Executable file
63
lib/StanfordCPPLib/private/randompatch.h
Executable 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
|
11
lib/StanfordCPPLib/private/tokenpatch.h
Executable file
11
lib/StanfordCPPLib/private/tokenpatch.h
Executable 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
|
25
lib/StanfordCPPLib/private/tplatform.h
Executable file
25
lib/StanfordCPPLib/private/tplatform.h
Executable 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
99
lib/StanfordCPPLib/random.cpp
Executable 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
58
lib/StanfordCPPLib/random.h
Executable 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> .. <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
628
lib/StanfordCPPLib/set.h
Executable 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
67
lib/StanfordCPPLib/simpio.cpp
Executable 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
53
lib/StanfordCPPLib/simpio.h
Executable 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
285
lib/StanfordCPPLib/stack.h
Executable 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
240
lib/StanfordCPPLib/strlib.cpp
Executable 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
222
lib/StanfordCPPLib/strlib.h
Executable 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
727
lib/StanfordCPPLib/vector.h
Executable 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<int> 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
BIN
res/EnglishWords.dat
Executable file
Binary file not shown.
144
res/expected-output-1.txt
Executable file
144
res/expected-output-1.txt
Executable 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
232
res/expected-output-2.txt
Executable 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
22
src/Boggle.cpp
Executable 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
29
src/Boggle.h
Executable 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
79
src/bogglemain.cpp
Executable 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
21
src/bogglemain.h
Executable 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
32
src/boggleplay.cpp
Executable 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
3
src/readme.txt
Executable 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
78
src/shuffle.h
Executable 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
|
Loading…
x
Reference in New Issue
Block a user