HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Boggle board solver in C++

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
solverboggleboard

Problem

This C++ Boggle board solver is intended to take in many boards one after another and score them.

I would like comments on code style, whether there are C++ standard library features that I could use to streamline the code, appropriate division between public and private, etc.

Download code

Download dictionary file

Boggle

Boggle is a board game with a 4x4 board of squares, each of which has a letter, in which you score points by finding words on the board. This is an example Boggle board:

c a t c
a t c a
t c a t
c a t c


This board contains the words 'cat', 'act', 'tact', etc. The words must be made up of neighboring squares (left, right, up, down, and diagonal), and you can't use the same square twice in a word. Words don't need to be in a straight line.

Code

Boggle class

The Boggle class stores the board.

  • board stores the letters in a vector of structs, each of which stores a letter, the row and column, and a vector of indices for neighboring squares.



  • Load loads a string into the board.



  • Print prints the board.



  • Score finds all words on the board and calculates how much they're worth.



  • Words (private member function) finds all words starting at a given square on the board.



...

```
#include
#include
#include
#include

// Map word lengths to points
std::map POINTS = {{3, 1}, {5, 2}, {6, 3}, {7, 5}, {8, 11}};

// Boggle board class
class Boggle {
private:
struct square {
std::string value;
int row;
int col;
std::vector neighbors;

square(int row, int col);
};

int size;
std::vector board;
Dictionary dict;
std::map points;
std::unordered_set found_words;
void Words(int position, std::string str = "", std::unordered_set visited = std::unordered_set());

public:
Boggle(Dictionary dict, int size = 4, std::map points = POINTS);
~Boggle();

void Load(std::string letters);
void Print();
int Score();
};

// Boggle board constructor
Bogg

Solution

About the constructor of Boggle

From a stylistic point of view, instead of assigning member fields inside the constructor in java style, the C++ way is rather to use an initializer list.

That is to say, instead of:

Boggle::Boggle(Dictionary dict, int size, std::map points) {
    this->dict = dict;
    this->size = size;
    this->points = points;


You can write:

Boggle::Boggle(Dictionary dict, int size, std::map points):
   dict(dict),
   size(size),
   points(point)
{


One big advantage of using an initializer list over assignments inside the constructor's body, is that you can now declare these variables as const, or even use a reference instead, which avoids the copy. Using references will save a lot of work, but you have to make sure that the referred-to object is not deleted before the end of the Boggle instance.

Performance

Your code is likely to be much slower than it could be. One source of slowness is the std::unordered_set visited. Each call to the recursive Word function makes a copy of the set. There are two ideas that could improve this a lot.

The first idea is to use a reference instead of a copy. That is to say, use std::unordered_set &visited. With a reference, you also have to make sure that the set is restored to its initial state before quitting the function: add visited.erase(position); before returning.

Another more important idea is that, instead of using a std::set, you could simply use an array of flags that indicate, for each possible position, whether it was visited or not. insert and erase operations on such a representation of a set will be considerably more efficient: it simply consists in setting an array element to true or false.

Yet another performance idea: using a prefix-tree data structure might be a lot faster: https://en.wikipedia.org/wiki/Trie . But there is not such container in standard C++.

Code Snippets

Boggle::Boggle(Dictionary dict, int size, std::map<int, int> points) {
    this->dict = dict;
    this->size = size;
    this->points = points;
Boggle::Boggle(Dictionary dict, int size, std::map<int, int> points):
   dict(dict),
   size(size),
   points(point)
{

Context

StackExchange Code Review Q#146877, answer score: 2

Revisions (0)

No revisions yet.