#include #include #include #include #include #include #include #include #include #include #include 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 &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 > &board, const vector &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 > &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 > &board, const vector &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> &board, vector> &freePositions, int index, const vector &forbWords, int minForbidLen, set &solutionSet, vector &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> &board, const vector> &placements, int wordIndex, const vector &forbWords, int minForbidLen, set &solutionSet, vector &solutions, bool findOne, const string &outputFile) { // Base case: all required words placed if (wordIndex == placements.size()) { // Find free positions (cells marked with '?') vector> 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> 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 reqWords; vector 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> 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 solutionSet; vector solutions; // Prepare the base board filled with '?'. vector> board(height, vector(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; }