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

@@ -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;
}