Finding words in a crosswords (homework assistance)

One of my kids had the following task: find a set of words in the following crosswords:


The set of words was given. The crosswords was created by another student, who accidentally might have drawn the wrong letter at the wrong position, which makes the task of finding the given words hard, especially for little kids.

After attempting for a while, I decided to give them a hand. Here is a program to help them out:
  • Input: a crosswords and a set of words to look for
  • The code to find a given word in the crosswords is simple, just laborious and tedious: find the match to the first letter, then go into all the 8 possible directions trying to find the rest of the word. If found => success!
  • The interesting part of the problem is to deal with the potential partial matches. To deal with that, take each word and recursively create a set of partial sub-words. The sub-words are created by removing characters from the initial word. Do so in such a way to always start with sub-words that have the max number of characters.
We've managed to find "families", which was very hard manually:


Whether was a partial match, thou:


Code is below, cheers, Marcelo.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace Puzzle
{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length != 2)
            {
                Console.WriteLine("Usage: Puzzle.exe <crosswords file> <words file>");
                return;
            }

            FileInfo fi = new FileInfo(args[0]);
            StreamReader sr = fi.OpenText();
            int nRows = 0;
            int nCols = 0;
            while (!sr.EndOfStream)
            {
                nRows++;
                nCols = sr.ReadLine().Length;
            }
            sr.Close();

            char[,] puzzle = new char[nRows, nCols];
            sr = fi.OpenText();
            int r = 0;
            while (!sr.EndOfStream)
            {
                string line = sr.ReadLine();
                for (int c = 0; c < nCols; c++)
                {
                    puzzle[r, c] = line[c];
                }
                r++;
            }
            sr.Close();

            fi = new FileInfo(args[1]);
            sr = fi.OpenText();
            while (!sr.EndOfStream)
            {
                string word = sr.ReadLine().ToUpper().Trim();
                Console.WriteLine("Searching word: {0}", word);
                Console.WriteLine();
                TryPartialWord(word, "", 0, puzzle, nRows, nCols);
                Console.WriteLine();
                Console.ReadLine();
            }
            sr.Close();
        }

        static bool TryPartialWord(string originalWord,
                                   string currentWord,
                                   int currentIndex,
                                   char[,] puzzle,
                                   int nRows,
                                   int nCols)
        {
            if (currentIndex >= originalWord.Length)
            {
                return FindWord(currentWord, puzzle, nRows, nCols);
            }

            if (TryPartialWord(originalWord, currentWord + originalWord[currentIndex].ToString(), currentIndex + 1, puzzle, nRows, nCols)) return true;
            if (TryPartialWord(originalWord, currentWord, currentIndex + 1, puzzle, nRows, nCols)) return true;

            return false;
        }

        static bool FindWord(string word, char[,] puzzleInput, int nRows, int nCols)
        {
            char[,] puzzle = (char[,])puzzleInput.Clone();

            bool found = false;
            for (int r = 0; r < nRows; r++)
            {
                for (int c = 0; c < nCols; c++)
                {
                    if (puzzle[r, c] == word[0])
                    {
                        //Right
                        found = true;
                        for (int i = 1; i < word.Length; i++)
                        {
                            if (i + c >= nCols || word[i] != puzzle[r, i + c])
                            {
                                found = false;
                                break;
                            }
                        }
                        if (found)
                        {
                            for (int i = 0; i < word.Length; i++)
                            {
                                puzzle[r, i + c] = '*';
                            }
                            break;
                        }

                        //Left
                        found = true;
                        for (int i = 1; i < word.Length; i++)
                        {
                            if (c - i < 0 || word[i] != puzzle[r, c - i])
                            {
                                found = false;
                                break;
                            }
                        }
                        if (found)
                        {
                            for (int i = 0; i < word.Length; i++)
                            {
                                puzzle[r, c - i] = '*';
                            }
                            break;
                        }

                        //Up
                        found = true;
                        for (int i = 1; i < word.Length; i++)
                        {
                            if (r - i < 0 || word[i] != puzzle[r - i, c])
                            {
                                found = false;
                                break;
                            }
                        }
                        if (found)
                        {
                            for (int i = 0; i < word.Length; i++)
                            {
                                puzzle[r - i, c] = '*';
                            }
                            break;
                        }

                        //Down
                        found = true;
                        for (int i = 1; i < word.Length; i++)
                        {
                            if (r + i >= nRows || word[i] != puzzle[r + i, c])
                            {
                                found = false;
                                break;
                            }
                        }
                        if (found)
                        {
                            for (int i = 0; i < word.Length; i++)
                            {
                                puzzle[r + i, c] = '*';
                            }
                            break;
                        }

                        //Diagonal up right
                        found = true;
                        for (int i = 1; i < word.Length; i++)
                        {
                            if (r - i < 0 || c + i >= nCols || word[i] != puzzle[r - i, c + i])
                            {
                                found = false;
                                break;
                            }
                        }
                        if (found)
                        {
                            for (int i = 0; i < word.Length; i++)
                            {
                                puzzle[r - i, c + i] = '*';
                            }
                            break;
                        }

                        //Diagonal up left
                        found = true;
                        for (int i = 1; i < word.Length; i++)
                        {
                            if (r - i < 0 || c - i < 0 || word[i] != puzzle[r - i, c - i])
                            {
                                found = false;
                                break;
                            }
                        }
                        if (found)
                        {
                            for (int i = 0; i < word.Length; i++)
                            {
                                puzzle[r - i, c - i] = '*';
                            }
                            break;
                        }

                        //Diagonal down right
                        found = true;
                        for (int i = 1; i < word.Length; i++)
                        {
                            if (r + i >= nRows || c + i >= nCols || word[i] != puzzle[r + i, c + i])
                            {
                                found = false;
                                break;
                            }
                        }
                        if (found)
                        {
                            for (int i = 0; i < word.Length; i++)
                            {
                                puzzle[r + i, c + i] = '*';
                            }
                            break;
                        }

                        //Diagonal down left
                        found = true;
                        for (int i = 1; i < word.Length; i++)
                        {
                            if (r + i >= nRows || c - i < 0 || word[i] != puzzle[r + i, c - i])
                            {
                                found = false;
                                break;
                            }
                        }
                        if (found)
                        {
                            for (int i = 0; i < word.Length; i++)
                            {
                                puzzle[r + i, c - i] = '*';
                            }
                            break;
                        }
                    }
                }

                if (found)
                {
                    break;
                }
            }

            if (found)
            {
                Console.WriteLine("FOUND: {0}", word);
                Console.WriteLine();
                for (int r = 0; r < nRows; r++)
                {
                    for (int c = 0; c < nCols; c++)
                    {
                        Console.Write("{0}", puzzle[r, c]);
                    }
                    Console.WriteLine();
                }
            }

            return found;
        }
    }
}

Comments

Popular posts from this blog

Advent of Code - Day 6, 2024: BFS and FSM

Golang vs. C#: performance characteristics (simple case study)

Advent of Code - Day 7, 2024: Backtracking and Eval