Click here to Skip to main content
15,898,134 members
Articles / Mobile Apps

Windows Phone Crosswords

Rate me:
Please Sign up or sign in to vote.
5.00/5 (22 votes)
3 Jul 2012CPOL6 min read 62.9K   1.4K   42  
Learn how to create a Windows Phone crosswords game taking advantage of online internet resources
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Crosswords.Core;
using Crosswords.Models;
using Crosswords.WebHelper;
using System.Text.RegularExpressions;
using System.Windows.Threading;
using System.Threading;
using System.Collections.Specialized;

namespace Crosswords
{
    public class BoardViewModel : INotifyPropertyChanged
    {
        #region members
        string txtUser = "";
        string txtClue = "";
        bool isBusy = false;
        HtmlParser htmlParser;
        char[,] boardValues = new char[15, 15];
        int size;
        Dispatcher dispatcher;
        Action<object, NotifyCollectionChangedEventArgs> squaresChangedCallback;
        public event EventHandler HtmlLoaded;
        #endregion Members

        #region ctr
        public BoardViewModel(Dispatcher dispatcher, int size, Action<object, NotifyCollectionChangedEventArgs> squaresChangedCallback)
        {
            this.dispatcher = dispatcher;
            this.size = size;
            this.squaresChangedCallback = squaresChangedCallback;
            this.Clues = new ObservableCollection<Clue>();
            squares.CollectionChanged += (s, e) =>
            {
                squaresChangedCallback(s, e);
            };
        }

        #endregion ctr

        #region properties

        public string TxtUser
        {
            get
            {
                return txtUser;
            }
            set
            {
                txtUser = value;
                NotifyPropertyChanged("TxtUser");
            }
        }

        public string TxtClue
        {
            get
            {
                return txtClue;
            }
            set
            {
                txtClue = value;
                NotifyPropertyChanged("TxtClue");
            }
        }

        public bool IsBusy
        {
            get
            {
                return isBusy;
            }
            set
            {
                isBusy = value;
                NotifyPropertyChanged("IsBusy");
            }
        }

        ObservableNotifiableCollection<Square> squares = new ObservableNotifiableCollection<Square>();
        public ObservableNotifiableCollection<Square> Squares
        {
            get
            {
                return squares;
            }
            set
            {
                squares = value;
                NotifyPropertyChanged("Squares");
            }
        }

        private ObservableCollection<Clue> clues;
        public ObservableCollection<Clue> Clues
        {
            get
            {
                return clues;
            }
            set
            {
                if (value != clues)
                {
                    clues = value;
                    NotifyPropertyChanged("Clues");
                }
            }
        }
        public bool IsDataLoaded
        {
            get;
            private set;
        }
        #endregion properties        

        #region methods
        public void LoadGrid()
        {
            TxtClue = "";
            Clues.Clear();
            foreach (var square in Squares)
            {
                square.UserLetter = "";
                square.Letter = "";
                square.IsSelected = false;
                squaresChangedCallback(squares,
                    new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, square, square.Row * size + square.Column));
            }

            IsBusy = true;
            htmlParser = new HtmlParser(size,
                //onSuccess
                (html) =>
                {
                    IsBusy = false;
                    processHtmlResult();
                },
                //onFailure
                () =>
                {
                    IsBusy = false;
                },
                //onProgressChanged
                (percentage) =>
                {
                }
            );
        }

        private void processHtmlResult()
        {
            if (HtmlLoaded != null)
                HtmlLoaded(this, new EventArgs());

            var board = htmlParser.Parse();
            SetSquares(board);

            var dictWords = new Dictionary<string, string>();
            AddHorizontalWordsToDict(dictWords);
            AddVerticalWordsToDict(dictWords);

            dispatcher.BeginInvoke(delegate
            {
                LoadClues(dictWords, "");
            });
        }

        public void LoadClues(Dictionary<string, string> dictWords, string note)
        {
            var dictionaryHelper = new DictionaryHelper(dictWords);
            dictionaryHelper.GetDictionaryEntries((key, word, definition) =>
            {
                var sb = new StringBuilder();
                sb.AppendLine(string.Format("{0}: {1}", key, definition));

                lock (clues)
                {
                    if (note == "(plural)" && !definition.Contains("(noun)"))
                    {
                        definition = "";
                    }

                    var clue = new Clue()
                        {
                            WordId = key,
                            Definition = string.Format("{0} {1}", definition, note)
                        };

                    if (string.IsNullOrEmpty(definition))
                    {
                        if (word.Trim().Length > 3 && 
                            word.ToLower().Last() == 's' && 
                            string.IsNullOrEmpty(note))
                        {
                            var dictPlural = new Dictionary<string, string>();
                            dictPlural.Add(key, word.Substring(0, word.Length - 1));
                            LoadClues(dictPlural, "(plural)");
                        }
                        else
                        {
                            squares.Where(s => (s.WordId ?? "").Split(',').Contains(key))
                                .ToList().ForEach(s =>
                                {
                                    s.UserLetter = s.Letter;
                                    squaresChangedCallback(squares,
                                        new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, s, s.Row * size + s.Column));
                                });
                        }
                    }
                    else
                    {
                        var indexToInsert = 0;
                        for (var index = 0; index < clues.Count(); index++)
                        {
                            if (clues[index].WordId.CompareTo(clue.WordId) > 0)
                            {
                                indexToInsert = index;
                                break;
                            }
                        }
                        Clue[] cluesAux = new Clue[clues.Count()];
                        clues.CopyTo(cluesAux, 0);
                        var sortedClues = cluesAux.ToList().OrderBy(x => x.WordId);
                        clues.Clear();
                        sortedClues.ToList().ForEach(c => clues.Add(c));
                        clues.Insert(indexToInsert, clue);
                    }
                }
                NotifyPropertyChanged("Clues");
            });
            
            this.IsDataLoaded = true;
        }

        public void SelectSquaresByPosition(double gridWidth, double gridHeight, Point swipeDownPoint, Point swipeUpPoint)
        {
            var factor = size / gridWidth;
            var col1 = (int)(swipeDownPoint.X * factor);
            var row1 = (int)(swipeDownPoint.Y * factor);
            var col2 = (int)(swipeUpPoint.X * factor);
            var row2 = (int)(swipeUpPoint.Y * factor);

            var col = (col2 + col1) / 2;
            var row = (row2 + row1) / 2;

            if (col >= 0 &&
                row >= 0 &&
                col < size &&
                row < size)
            {
                var wordId = squares[row * size + col].WordId;

                if (wordId != null)
                {
                    var wordId1 = "";

                    if (col1 == col2 && row1 != row2)
                    {
                        if (wordId != null)
                        {
                            wordId1 = wordId.Split(',')[1];
                        }
                    }
                    else if (col1 != col2 && row1 == row2)
                    {
                        if (wordId != null)
                        {
                            wordId1 = wordId.Split(',')[0];
                        }
                    }

                    SelectSquaresByWordId(wordId1);
                }
            }
        }

        public void SelectSquaresByWordId(string wordId1)
        {
            var isSomeSquareUnSelected =
                squares
                    .Where(s => s.WordId.Split(',').Contains(wordId1)
                                && !s.IsSelected).Any();

            var isSomeEmptySquareUnSelected =
                squares
                    .Where(s => s.WordId.Split(',').Contains(wordId1)
                                && (s.UserLetter ?? "").Trim() == ""
                                && !s.IsSelected).Any();

            if (isSomeEmptySquareUnSelected || !isSomeSquareUnSelected)
            {
                squares
                    .ToList()
                    .ForEach(s =>
                    {
                        var split = s.WordId.Split(',');
                        s.IsSelected = split.Contains(wordId1) && (s.UserLetter ?? "").Trim() == "";
                        squaresChangedCallback(squares,
                            new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, s, s.Row * size + s.Column));
                    });
            }
            else
            {
                squares
                    .ToList()
                    .ForEach(s =>
                    {
                        var split = s.WordId.Split(',');
                        s.IsSelected = split.Contains(wordId1);
                        squaresChangedCallback(squares,
                            new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, s, s.Row * size + s.Column));
                    });
            }

            var txt = "";

            if (clues.Count() > 0)
            {
                var selectedClue = clues.Where(c => c.WordId == wordId1);
                if (selectedClue.Any())
                {
                    var clue = selectedClue.First();
                    txt = clue.Definition;
                }
                TxtClue = txt.Trim();
            }
        }

        public void TypeLetter(string letter)
        {
            var selectedSquares = this.Squares.Where(s => s.IsSelected);
            if (selectedSquares.Count() > 0)
            {
                var square = selectedSquares.First();
                if (square != null)
                {
                    square.UserLetter = letter;
                    square.IsSelected = false;

                    squaresChangedCallback(squares,
                        new NotifyCollectionChangedEventArgs(
                            NotifyCollectionChangedAction.Add, square, square.Row * size + square.Column));

                    var isSomeSquareSelected =
                        squares.Where(s => s.IsSelected).Any();

                    if (!isSomeSquareSelected)
                    {
                        TxtClue = "";
                    }
                }
            }
        }

        private string AddVerticalWordsToDict(Dictionary<string, string> dictWords)
        {
            string line;
            line = "";
            for (var col = 0; col < size; col++)
            {
                for (var row = 0; row < size; row++)
                {
                    if (col < size && row < size)
                    {
                        var val = boardValues[row, col];
                        line = string.Concat(line, val);
                    }
                }
                RegexOptions options = RegexOptions.None;
                Regex regex = new Regex(@"[ ]{2,}", options);
                line = regex.Replace(line, @" ")
                    .Trim();
                var words = line.Split(' ');
                for (var i = 0; i < words.Count(); i++)
                {
                    dictWords.Add(string.Format("V{0}{1}", (char)(65 + col), i + 1), words[i]);
                }
                line = "";
            }
            return line;
        }

        private string AddHorizontalWordsToDict(Dictionary<string, string> dictWords)
        {
            var line = "";
            for (var row = 0; row < size; row++)
            {
                for (var col = 0; col < size; col++)
                {
                    if (col < size && row < size)
                    {
                        var val = boardValues[row, col];
                        line = string.Concat(line, val);
                    }
                }
                RegexOptions options = RegexOptions.None;
                Regex regex = new Regex(@"[ ]{2,}", options);
                line = regex.Replace(line, @" ")
                    .Trim();
                var words = line.Split(' ');
                for (var i = 0; i < words.Count(); i++)
                {
                    dictWords.Add(string.Format("H{0}{1}", (char)(65 + row), i + 1), words[i]);
                }
                line = "";
            }
            return line;
        }

        private void SetSquares(string board)
        {
            squares.Clear();
            for (var row = 0; row < 15; row++)
            {
                var index = 0;
                var lastLetter = ' ';
                for (var col = 0; col < 15; col++)
                {
                    if (col < size && row < size)
                    {
                        var val = (char)board[row * 15 + col];
                        boardValues[row, col] = val;
                        var square = new Square();
                        square.Row = row;
                        square.Column = col;
                        squares.Add(square);
                        var text = val.ToString();
                        if (!string.IsNullOrEmpty(text.Trim()) && lastLetter == ' ')
                        {
                            index++;
                        }
                        lastLetter = val;
                        if (val != ' ')
                        {
                            square.WordId = string.Format("H{0}{1}", (char)(65 + row), index);
                        }
                        else
                        {
                            square.WordId = "";
                        }
                        square.Letter = text;
                        var fontSize = 28;
                        switch (size)
                        {
                            case 4:
                                fontSize = 52;
                                break;
                            case 7:
                                fontSize = 40;
                                break;
                            case 10:
                                fontSize = 28;
                                break;
                        }
                    }
                }
            }

            for (var col = 0; col < 15; col++)
            {
                var index = 0;
                var lastLetter = ' ';
                for (var row = 0; row < 15; row++)
                {
                    if (col < size && row < size)
                    {
                        var val = (char)board[row * 15 + col];
                        var square = this.squares[row * size + col];
                        var text = val.ToString();
                        if (!string.IsNullOrEmpty(text.Trim()) && lastLetter == ' ')
                        {
                            index++;
                        }
                        lastLetter = val;
                        if (val != ' ')
                        {
                            square.WordId = string.Concat(square.WordId, ",",
                                string.Format("V{0}{1}", (char)(65 + col), index));
                        }
                        else
                        {
                            square.WordId = "";
                        }
                    }
                }
            }
        }

        #endregion methods

        #region notification
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (null != handler)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion notification
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Instructor / Trainer Alura Cursos Online
Brazil Brazil

Comments and Discussions