Quiz: Count the ways to find a word by walking on a grid



/* ============================================================================
 
The problem: count the ways to find a word by walking on a grid

You are given a rectangular grid of letters and a word to find. 
You must compute the number of ways to find the word within the grid using the following rules:

* start at any cell within the grid
* from there, move to any of the cell’s eight neighboring cells
* continue moving from that neighbor to its neighbors, and so on, until you have spelled out the word
* you may visit cells more than once, but you cannot visit the same cell twice in a row (i.e., you must move for each turn)

Constraints:
* grid will contain between 1 and 50 elements, inclusive.
* Each element of grid will contain between 1 and 50 uppercase (’A’-’Z’) letters, inclusive.
* Each element of grid will contain the same number of characters.
* find will contain between 1 and 50 uppercase (’A’-’Z’) letters, inclusive.  
 
 
For instance, consider the following grid, taken from the examples in the problem statement:

ABC
FED
GAI

If you were asked to find the word “AEA” on this grid, you could do it in four ways:

1:
*BC ABC *BC
FED F*D FED
GAI GAI GAI

2:
*BC ABC ABC
FED F*D FED
GAI GAI G*I

3:
ABC ABC *BC
FED F*D FED
G*I GAI GAI

4:
ABC ABC ABC
FED F*D FED
G*I GAI G*I

If you were asked to find “ABCD”, you could do it in only one way:

1:
*BC A*C AB* ABC
FED FED FED FE*
GAI GAI GAI GAI

If you were asked to find “AAB”, you could not: 
there are no “A” cells on the grid that have other “A” cells as neighbors. 
  
============================================================================ */

/*
 *  Author :  David Tran
 *  Date   :  2008-03-28
 */
using System;
using System.Collections.Generic;
using System.Text;

namespace Quiz
{
    class Quiz
    {
        static void Main(string[] args)
        {
            new Quiz().Solve();
        }

        public void Solve()
        {
            LoadProblem();
            foreach (Index index in starts)
            {
                FindSolution(index.i, index.j, 0);
            }
            Console.WriteLine("Total Solution = {0}", solutions);
        }

        struct Index
        {
            public readonly int i;
            public readonly int j;
            public Index(int i, int j)
            {
                this.i = i;
                this.j = j;
            }
        }

        int rows;
        int cols;
        Dictionary<int, List<Index>>[,] grid;
        int lastNumber;
        List<Index> starts;
        int solutions = 0;

        private void LoadProblem()
        {
            // to simplify, we hard-coded the problem data for now.
            rows = 3;
            cols = 3;
            int cellLength = 2;
            string[,] gridData = {
                {"AA", "BB", "CZ"},
                {"FF", "EE", "DD"},
                {"GX", "AA", "IY"},
            };
            string goal = "AAEEAA";

            // split goal string to build up dictionary
            IDictionary<string, List<int>> dictionary = new Dictionary<string, List<int>>();
            for (int nb = 0, position = 0; position < goal.Length; nb++, position += cellLength)
            {
                string substring = goal.Substring(position, cellLength);
                if (!dictionary.ContainsKey(substring))
                {
                    dictionary[substring] = new List<int>();
                }
                dictionary[substring].Add(nb);
            }

            if (dictionary.Count <= 0)
            {
                throw new Exception("No input data ?!");
            }

            lastNumber = (goal.Length / cellLength) - 1;
            starts = new List<Index>();
            grid = new Dictionary<int, List<Index>>[rows, cols];

            // build up grid and starts
            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < cols; j++)
                {
                    string key = gridData[i, j];
                    if (dictionary.ContainsKey(key))
                    {
                        grid[i, j] = new Dictionary<int, List<Index>>();
                        foreach (int nb in dictionary[key])
                        {
                            grid[i, j].Add(nb, null);
                            if (nb == 0)
                            {
                                starts.Add(new Index(i, j));
                            }
                        }
                    }
                }
            }
        }

        private void FindSolution(int i, int j, int nb)
        {
            if (nb == lastNumber)
            {
                solutions++;
            }
            else
            {
                // build neighbors when needed, and memorize after builded.
                if (grid[i, j][nb] == null)
                {
                    FindNeighbors(i, j, nb);
                }

                foreach (Index index in grid[i, j][nb])
                {
                    FindSolution(index.i, index.j, nb + 1);
                }
            }
        }

        private void FindNeighbors(int i, int j, int nb)
        {
            int nextNb = nb + 1;
            List<Index> neighbors = new List<Index>();
            AddNeighbor(i - 1, j - 1, nextNb, neighbors);
            AddNeighbor(i - 1, j    , nextNb, neighbors);
            AddNeighbor(i - 1, j + 1, nextNb, neighbors);
            AddNeighbor(i    , j - 1, nextNb, neighbors);
            AddNeighbor(i    , j + 1, nextNb, neighbors);
            AddNeighbor(i + 1, j - 1, nextNb, neighbors);
            AddNeighbor(i + 1, j    , nextNb, neighbors);
            AddNeighbor(i + 1, j + 1, nextNb, neighbors);
            grid[i, j][nb] = neighbors;
        }

        private void AddNeighbor(int i, int j, int nb, List<Index> list)
        {
            if (i >= 0 && i < rows &&
                j >= 0 && j < cols &&
                grid[i, j] != null &&
                grid[i, j].ContainsKey(nb))
            {
                list.Add(new Index(i, j));
            }
        }
    }
}

Leave a Reply