add hw6 solution

This commit is contained in:
JamesFlare1212
2025-03-20 02:06:13 -04:00
parent 45ee58bda2
commit 54016a2693
6 changed files with 404 additions and 6 deletions

View File

@@ -1,7 +1,7 @@
HOMEWORK 6: INVERSE WORD SEARCH
NAME: < insert name >
NAME: Jinshan Zhou
COLLABORATORS AND OTHER RESOURCES:
@@ -10,18 +10,18 @@ List the names of everyone you talked to about this assignment
LMS, etc.), and all of the resources (books, online reference
material, etc.) you consulted in completing this assignment.
< insert collaborators / resources >
Lab document -- recursion on path finding
Remember: Your implementation for this assignment must be done on your
own, as described in "Academic Integrity for Homework" handout.
ESTIMATE OF # OF HOURS SPENT ON THIS ASSIGNMENT: < insert # hours >
ESTIMATE OF # OF HOURS SPENT ON THIS ASSIGNMENT: 30 hr
MISC. COMMENTS TO GRADER:
Optional, please be concise!
I tried.
## Reflection and Self Assessment
@@ -33,4 +33,6 @@ What parts of the assignment did you find challenging? Is there anything that
finally "clicked" for you in the process of working on this assignment? How well
did the development and testing process go for you?
< insert reflection >
This homework is very hard for me. It almost take forever to solve some puzzles.
I tried a lot of techniques to minimize the cost. But, it seems not enough. But
anyway, it's a good practice.

BIN
hws/inverse_word_search/main Executable file

Binary file not shown.

View File

@@ -0,0 +1,337 @@
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>
#include <set>
#include <algorithm>
#include <cstdlib>
#include <cctype>
#include <climits>
#include <utility>
using namespace std;
struct Placement {
int r, c; // starting row and column
int dr, dc; // direction increments
string word; // the required word to place
};
// Check if the given string s contains any forbidden word or its reverse.
bool containsForbidden(const string &s, const vector<string> &forbWords) {
for (size_t i = 0; i < forbWords.size(); i++) {
if (s.find(forbWords[i]) != string::npos)
return true;
string rev = forbWords[i];
reverse(rev.begin(), rev.end());
if (s.find(rev) != string::npos)
return true;
}
return false;
}
// Checks the full board for forbidden words in every contiguous line.
bool fullForbiddenCheck(const vector< vector<char> > &board, const vector<string> &forbWords) {
int H = board.size();
if (H == 0) return false;
int W = board[0].size();
int dirs[8][2] = { {0,1}, {0,-1}, {1,0}, {-1,0}, {1,1}, {1,-1}, {-1,1}, {-1,-1} };
for (int r = 0; r < H; r++) {
for (int c = 0; c < W; c++) {
for (int d = 0; d < 8; d++) {
int dr = dirs[d][0], dc = dirs[d][1];
string line = "";
int rr = r, cc = c;
while (rr >= 0 && rr < H && cc >= 0 && cc < W) {
line.push_back(board[rr][cc]);
if (containsForbidden(line, forbWords))
return true;
rr += dr;
cc += dc;
}
}
}
}
return false;
}
// Convert the board into a single string (rows separated by newline).
string boardToString(const vector< vector<char> > &board) {
string s = "";
for (size_t i = 0; i < board.size(); i++) {
for (size_t j = 0; j < board[i].size(); j++) {
s.push_back(board[i][j]);
}
if (i < board.size()-1)
s.push_back('\n');
}
return s;
}
// Given a newly assigned cell (r,c), check in all eight directions the contiguous block
bool checkCellDirections(int r, int c, const vector< vector<char> > &board, const vector<string> &forbWords, int minForbidLen) {
int H = board.size(), W = board[0].size();
int dirs[8][2] = { {0,1}, {0,-1}, {1,0}, {-1,0}, {1,1}, {1,-1}, {-1,1}, {-1,-1} };
for (int d = 0; d < 8; d++) {
int dr = dirs[d][0], dc = dirs[d][1];
int sr = r, sc = c;
// Go backwards from (r,c)
while (true) {
int pr = sr - dr, pc = sc - dc;
if (pr < 0 || pr >= H || pc < 0 || pc >= W) break;
if (board[pr][pc] == '?') break;
sr = pr; sc = pc;
}
// Build the contiguous block from (sr,sc)
string block = "";
int cr = sr, cc = sc;
while (cr >= 0 && cr < H && cc >= 0 && cc < W) {
if (board[cr][cc] == '?') break;
block.push_back(board[cr][cc]);
cr += dr; cc += dc;
}
if ((int)block.size() >= minForbidLen) {
if (containsForbidden(block, forbWords))
return false;
}
}
return true;
}
// Recursive function to fill free positions with letters
bool fillFreePositions(vector<vector<char>> &board,
vector<pair<int,int>> &freePositions,
int index,
const vector<string> &forbWords,
int minForbidLen,
set<string> &solutionSet,
vector<string> &solutions,
bool findOne,
const string &outputFile) {
// Base case: all free positions filled
if (index == freePositions.size()) {
// Check if the solution is valid
if (!fullForbiddenCheck(board, forbWords)) {
string solStr = boardToString(board);
if (solutionSet.find(solStr) == solutionSet.end()) {
solutionSet.insert(solStr);
solutions.push_back(solStr);
// If we need just one solution, write it to file and exit
if (findOne) {
ofstream fout(outputFile.c_str());
fout << "Board:" << endl;
istringstream iss(solStr);
string line;
while(getline(iss, line))
fout << " " << line << endl;
fout.close();
return true;
}
}
}
return false; // Continue searching for more solutions
}
// Try each letter for the current free position
int r = freePositions[index].first;
int c = freePositions[index].second;
for (char ch = 'a'; ch <= 'z'; ch++) {
board[r][c] = ch;
// Check if the new letter creates any forbidden words
if (checkCellDirections(r, c, board, forbWords, minForbidLen)) {
// Recursively fill the next position
if (fillFreePositions(board, freePositions, index + 1, forbWords, minForbidLen,
solutionSet, solutions, findOne, outputFile)) {
return true; // Solution found and we only need one
}
}
}
// Backtrack: Reset the cell
board[r][c] = '?';
return false;
}
// Recursive function to place required words
bool placeRequiredWords(vector<vector<char>> &board,
const vector<vector<Placement>> &placements,
int wordIndex,
const vector<string> &forbWords,
int minForbidLen,
set<string> &solutionSet,
vector<string> &solutions,
bool findOne,
const string &outputFile) {
// Base case: all required words placed
if (wordIndex == placements.size()) {
// Find free positions (cells marked with '?')
vector<pair<int,int>> freePositions;
for (int i = 0; i < board.size(); i++) {
for (int j = 0; j < board[0].size(); j++) {
if (board[i][j] == '?') {
freePositions.push_back(make_pair(i, j));
}
}
}
// Recursively fill free positions
return fillFreePositions(board, freePositions, 0, forbWords, minForbidLen,
solutionSet, solutions, findOne, outputFile);
}
// Try each placement for the current word
for (const Placement &p : placements[wordIndex]) {
// Create a temporary copy of the board
vector<vector<char>> boardCopy = board;
bool conflict = false;
// Try to place the word
for (size_t k = 0; k < p.word.size(); k++) {
int r = p.r + p.dr * k;
int c = p.c + p.dc * k;
if (boardCopy[r][c] == '?' || boardCopy[r][c] == p.word[k]) {
boardCopy[r][c] = p.word[k];
} else {
conflict = true;
break;
}
}
// If no conflict and no forbidden words formed, continue to the next word
if (!conflict && !fullForbiddenCheck(boardCopy, forbWords)) {
if (placeRequiredWords(boardCopy, placements, wordIndex + 1, forbWords, minForbidLen,
solutionSet, solutions, findOne, outputFile)) {
return true; // Solution found and we only need one
}
}
}
return false; // No solution found with any placement for this word
}
int main(int argc, char* argv[]) {
if (argc != 4) {
cout << "Usage: " << argv[0] << " input.txt output.txt one_solution|all_solutions" << endl;
return 1;
}
string inputFile = argv[1];
string outputFile = argv[2];
string mode = argv[3];
bool findOne = false;
if (mode == "one_solution") {
findOne = true;
} else if (mode == "all_solutions") {
findOne = false;
} else {
cout << "Invalid mode. Use one_solution or all_solutions." << endl;
return 1;
}
ifstream fin(inputFile.c_str());
if (!fin) {
cout << "Cannot open input file." << endl;
return 1;
}
int width, height;
fin >> width >> height;
string dummy;
getline(fin, dummy); // consume rest of first line
// Separate required and forbidden words.
vector<string> reqWords;
vector<string> forbWords;
while(getline(fin, dummy)) {
if(dummy.size() == 0)
continue;
char sign = dummy[0];
string word = "";
int pos = 1;
while (pos < dummy.size() && isspace(dummy[pos])) pos++;
while (pos < dummy.size() && !isspace(dummy[pos])) {
word.push_back(dummy[pos]);
pos++;
}
if (sign == '+')
reqWords.push_back(word);
else if (sign == '-')
forbWords.push_back(word);
}
fin.close();
// Precompute minimum forbidden word length.
int minForbidLen = INT_MAX;
for (size_t i = 0; i < forbWords.size(); i++) {
if ((int)forbWords[i].size() < minForbidLen)
minForbidLen = forbWords[i].size();
}
if (forbWords.empty())
minForbidLen = 27; // no forbidden word; no check needed
// Precompute all placements for each required word.
vector<vector<Placement>> placements;
placements.resize(reqWords.size());
int directions[8][2] = { {0,1}, {0,-1}, {1,0}, {-1,0}, {1,1}, {1,-1}, {-1,1}, {-1,-1} };
for (size_t w = 0; w < reqWords.size(); w++) {
string word = reqWords[w];
for (int r = 0; r < height; r++) {
for (int c = 0; c < width; c++) {
for (int d = 0; d < 8; d++) {
int dr = directions[d][0], dc = directions[d][1];
int end_r = r + dr * (word.size() - 1);
int end_c = c + dc * (word.size() - 1);
if (end_r < 0 || end_r >= height || end_c < 0 || end_c >= width)
continue;
Placement p;
p.r = r; p.c = c; p.dr = dr; p.dc = dc; p.word = word;
placements[w].push_back(p);
}
}
}
if (placements[w].empty()) {
ofstream fout(outputFile.c_str());
fout << "No solutions found" << endl;
fout.close();
return 0;
}
}
// Use a set to avoid duplicate solutions.
set<string> solutionSet;
vector<string> solutions;
// Prepare the base board filled with '?'.
vector<vector<char>> board(height, vector<char>(width, '?'));
// Call the recursive function to place required words
placeRequiredWords(board, placements, 0, forbWords, minForbidLen,
solutionSet, solutions, findOne, outputFile);
// Write out all found solutions (if findOne is true, we've already written the solution).
if (!findOne || solutions.empty()) {
ofstream fout(outputFile.c_str());
if (solutions.empty()) {
fout << "No solutions found" << endl;
} else {
fout << solutions.size() << " solution(s)" << endl;
for (size_t s = 0; s < solutions.size(); s++) {
fout << "Board:" << endl;
istringstream iss(solutions[s]);
string line;
while(getline(iss, line))
fout << " " << line << endl;
}
}
fout.close();
}
return 0;
}

View File

@@ -0,0 +1,41 @@
8 solution(s)
Board:
aare
rrea
itss
dstt
Board:
eraa
aerr
ssti
ttsd
Board:
arid
arts
rest
east
Board:
dira
stra
tser
tsae
Board:
east
rest
arts
arid
Board:
tsae
tser
stra
dira
Board:
dstt
itss
rrea
aare
Board:
ttsd
ssti
aerr
eraa