Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions Lacrit/assignment3/Dictionary.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include <fstream>
#include <iostream>
#include <unordered_set>
#include <string>


class Dictionary {
public:
Dictionary();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please try to keep indentation consistent.

Dictionary(std::string);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if nod needed by the compiler, putting names for the parameters helps readers understand what parameters are.

~Dictionary();
void Fill(std::string);
bool isPrefix(const std::string&);

std::unordered_set<std::string> words;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those probably don't need to be public.

std::unordered_set<std::string> prefixes;
std::string path;
};

Dictionary::Dictionary() {};
Dictionary::Dictionary(std::string path):
path(path)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It helps readability having different naming conventions for fields and parameters. On the Google Style for example, we end fields with '_'.

{}
// Load the word dictionary and prefixes dictionary from a given file
void Dictionary::Fill(std::string path)
{
std::string line;
std::ifstream file(path);
if (file.is_open()) {
while (std::getline(file, line)) {
// Add to word dictionary
this->words.insert(line);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this-> is not needed.

// Add to prefixes dictionary
this->prefixes.insert(line);
for (size_t i = 1; i < line.length(); i++) {
this->prefixes.insert(line.substr(0, i));
}
}
}
file.close();
}
Dictionary::~Dictionary() {};
125 changes: 125 additions & 0 deletions Lacrit/assignment3/Main.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#include <map>
#include <string>
#include <unordered_set>
#include <vector>
#include "Dictionary.hpp"

// prolly not the best solution to store it like that
int rows = 2;
int cols = 3;

class Main {
private:
struct cell {
std::string value;
int row;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's ok to store them, but they are technically not needed.
As I explain in more detail in a comment above, you can from int index to coordinates and back 'easily'
Using a int to refer to the index of a cell in the board vector is ok, but a few comments will help :)

int col;
std::vector<int> neighbours;
cell(int row, int col);
};
std::vector<cell> board;
Dictionary dict;
std::unordered_set<std::string> found_words;
void Words(int pos, std::string str = "", std::unordered_set<int> visited = std::unordered_set<int>());

public:
Main(Dictionary dict);
~Main();

void Load(std::string letters);
void Print();
std::unordered_set<std::string> Result();
};

// Main board constructor
Main::Main(Dictionary dict)
{
this->dict = dict;
int row = 0;
int col = 0;


for (int i = 0; i < rows; i++) {
row = i / rows;
for ( int j = 0; j < cols; j++) {
col = j % cols;
board.push_back(cell(row, col));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(*)
I think here row is 0 and col is j.
You can use i and j directly, right?

}
}

//get all neighbours of a cell
std::vector<int> shift {-1, 0, 1};
for (cell &sq : board) {
for (int row_shift : shift) {
for (int col_shift : shift) {
row = sq.row + row_shift;
col = sq.col + col_shift;
if (row >= 0 & row < rows & col >= 0 & col < cols & !(row_shift == 0 & col_shift == 0)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it works, but you probably should use logical and && instead of bitwise and &

sq.neighbours.push_back(row * rows + col);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(*)
row * rows + col should be either:
row + rows * col or row * cols + col
One way to think about it is (for the first one):
When col = 0, this goes from 0 -> rows -1, so the next available number when col = 1 is rows.
In that case, if n = row + rows * col
You can extract them back (using that row < rows, and they are both positive integers):
n / rows -> (row + rows * col) / rows -> row / rows + (rows * col) / rows -> 0 + col -> col
n % rows -> (row + rows * col) % rows -> row % rows + (rows * col) % rows -> row + 0 -> row

}
}
}
}
}

Main::~Main() {}

Main::cell::cell(int row, int col):
row(row),
col(col)
{}

// Load a string of letters into the board
void Main::Load(std::string letters) {
int i = 0;
for (cell &it : board) {
it.value = letters[i];
i += 1;
}
// Clear any previously found words
found_words.clear();
}

// Print the board
void Main::Print() {
for (const cell &sq : board) {
std::cout << sq.value << " ";
if (sq.col == cols - 1) {
std::cout << std::endl;
}
}
}

std::unordered_set<std::string> Main::Result()
{
// a
// Find words for all cells on the board
for (size_t i = 0; i < board.size(); i++)
{
Words(i);
}
return found_words;
}

// Find all words starting at a given position
void Main::Words(int position, std::string string, std::unordered_set<int> visited) {

cell &sq = board[position];
string += sq.value;
visited.insert(position);

// If the string is a word, add it to the found words
if (dict.words.find(string) != dict.words.end()) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be a function isWord() in the dictionary class, and the code bellow (dict.prefixes.find(string) != dict.prefixes.end()) ==> isPrefix()

found_words.insert(string);
}

// If the string is a prefix, continue looking
if (dict.prefixes.find(string) != dict.prefixes.end()) {
for (const int &neighbour : sq.neighbours) {
if (visited.find(neighbour) == visited.end()) {
Words(neighbour, string, visited);
}
}
}
visited.erase(position);
}
18 changes: 18 additions & 0 deletions Lacrit/assignment3/Test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include "Main.hpp"

int main() {
const std::string path = "dict.txt";
std::string board = "aartcd";
Dictionary dict(path);
dict.Fill(path);
Main m(dict);
m.Load(board);
m.Print();
std::unordered_set<std::string> res = m.Result();
std::cout << std::endl;
for (auto it = res.begin(); it != res.end(); ++it)
{
std::cout << *it << std::endl;
}
return 0;
}
47 changes: 47 additions & 0 deletions Lacrit/assignment3/Unit_tests.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#include "Unit_tests.h"

void test_IsWord(Dictionary &d){
EXPECT_TRUE(d.words.find("cat") != d.words.end());
EXPECT_TRUE(d.words.find("car") != d.words.end());
EXPECT_FALSE(d.words.find("rat") != d.words.end());
EXPECT_FALSE(d.words.find("ca") != d.words.end());
EXPECT_FALSE(d.words.find("CAT") != d.words.end());
}

void test_IsPrefix(Dictionary& d){
EXPECT_TRUE(d.prefixes.find("c") != d.prefixes.end());
EXPECT_TRUE(d.prefixes.find("ca") != d.prefixes.end());
EXPECT_TRUE(d.prefixes.find("cat") != d.prefixes.end());
EXPECT_TRUE(d.prefixes.find("card") != d.prefixes.end());
EXPECT_FALSE(d.prefixes.find("") != d.prefixes.end());
EXPECT_FALSE(d.prefixes.find("a") != d.prefixes.end());
EXPECT_FALSE(d.prefixes.find("Ra") != d.prefixes.end());
}

void test_IsWordAfterRemoval(Dictionary & d){
d.words.erase("car");
EXPECT_FALSE(d.words.find("car") != d.words.end());
}

void test_IsPrefixAfterRemoval(Dictionary & d){
EXPECT_TRUE(d.prefixes.find("c") != d.prefixes.end());
EXPECT_TRUE(d.prefixes.find("ca") != d.prefixes.end());
EXPECT_TRUE(d.prefixes.find("car") != d.prefixes.end());
d.prefixes.erase("card");
EXPECT_FALSE(d.prefixes.find("card") != d.prefixes.end());

d.words.erase("bicycle");
EXPECT_FALSE(d.prefixes.find("b") != d.prefixes.end());
EXPECT_FALSE(d.prefixes.find("bi") != d.prefixes.end());
EXPECT_FALSE(d.prefixes.find("bic") != d.prefixes.end());
}

int main (){
Dictionary d("dict.txt");
d.Fill("dict.txt");
test_IsWord(d);
test_IsPrefix(d);
test_IsWordAfterRemoval(d);
test_IsPrefixAfterRemoval(d);
return 0;
}
15 changes: 15 additions & 0 deletions Lacrit/assignment3/Unit_tests.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#include "codeu_test_lib.h"
#include "Dictionary.hpp"

#ifndef UNIT_TESTS
#define UNIT_TESTS

void test_IsWord(const Dictionary& d);

void test_IsPrefix(const Dictionary& d);

void test_IsWordAfterRemoval(Dictionary& d);

void test_IsPrefixAfterRemoval(Dictionary& d);

#endif
81 changes: 81 additions & 0 deletions Lacrit/assignment3/codeu_test_lib.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#include <iostream>
#include <vector>

// Some convenient macros for simple testing.
// If expectation is fulfilled, prints nothing;
// If expectation is not fulfilled, prints what went wrong (expectation vs.
// actual value) with the filename and line number for convenience.

#define EXPECT_TRUE(statement) \
if (!(statement)) { \
std::cout << __FILE__ << ":" << __LINE__ << " Failed: " \
<< "Statement (" #statement << ") is false, expected true." \
<< std::endl; \
}

#define EXPECT_FALSE(statement) \
if (statement) { \
std::cout << __FILE__ << ":" << __LINE__ << " Failed: " \
<< "Statement (" #statement << ") is true, expected false." \
<< std::endl; \
}

#define EXPECT_EQ(expected, actual) \
if ((expected) != (actual)) { \
std::cout << __FILE__ << ":" << __LINE__ << " Failed: " \
<< "Statement (" << #actual << ") is " << actual \
<< ", expected " << (expected) << " (" << #expected << ")." \
<< std::endl; \
}

#define EXPECT_NULL(statement) \
if (statement != nullptr) { \
std::cout << __FILE__ << ":" << __LINE__ << " Failed: " \
<< "Statement (" << #statement \
<< ") is not null, expected null." << std::endl; \
}

// Print operator for vectors. Must be defined in order to use EXPECT_EQ macro
// with vectors (see example below).
/*
template <class T>
inline std::ostream& operator<<(std::ostream& os, const std::vector<T>& v) {
os << "{";
for (int i = 0; i < v.size(); i++) {
if (i > 0) {
os << ", ";
}
os << v[i];
}
os << "}";
}
*/
// Example usage:

// EXPECT_TRUE(1 < 3); // Prints nothing.
// EXPECT_TRUE(5 < 3); // main.cpp:53 Failed: Statement (5 < 3) is
// // false, expected true.
// EXPECT_TRUE(true); // Prints nothing.
// EXPECT_TRUE(false); // Prints: tests.cpp:56 Failed: Statement (false) is
// // false, expected true.
// EXPECT_FALSE(5 > 6);
// EXPECT_FALSE(5 > 0); // Prints: tests.cpp:59 Failed: Statement (5 > 0) is
// // true, expected false.
// EXPECT_EQ(4, 2 + 2);
// EXPECT_EQ(4, 3 + 1);
// EXPECT_EQ(10 * 10, 50 + 51); // tests:37 Failed: Statement (50 + 51) is 101,
// // expected 100 (10 * 10).
// EXPECT_EQ("pizza", std::string("pizz") + "a");
// EXPECT_EQ("pizza", std::string("pizz") + "aaaa");
// // tests.cpp:39 Failed: Statement (std::string("pizz")+"aaaa") is pizzaaaa,
// // expected pizza ("pizza").
//
// int x;
// EXPECT_NULL(&x); // main.cpp:71 Failed: Statement (&x) is not null,
// // expected null.
//
// std::vector<int> expected_vec{1, 2, 3};
// std::vector<int> actual_vec{4, 5, 6};
// EXPECT_EQ(expected_vec, actual_vec);
// // main.cpp:77 Failed: Statement (actual_vec) is {4, 5, 6}, expected
// // {1, 2, 3} (expected_vec).
4 changes: 4 additions & 0 deletions Lacrit/assignment3/dict.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
car
card
cart
cat