private static bool GenerateNumber(GameFieldModel model, Random rand, IndexPair pair)
        {
            var availableNumbers = GetHeuristicsAvailableNumbers(model, pair);
            sbyte number = rand.Choose(availableNumbers);

            model.SetItemNumber(pair, number);

            return !model.IsItemEmpty(pair);
        }
        private static Dictionary<IndexPair, IEnumerable<sbyte>> GetAvailableDictByPairs(GameFieldModel model, IEnumerable<IndexPair> pairs, IndexPair checkedPair, int rank)
        {
            var dict = new Dictionary<IndexPair, IEnumerable<sbyte>>();

            foreach (var pair in pairs)
            {
                if (rank > 1 && model.IsItemNotAvailable(pair, checkedPair))
                {
                    model.SelectedPair = pair;
                    dict.Add(pair, GetHeuristicsAvailableNumbers(model, pair, rank - 1));
                    model.SelectedPair = null;
                }
                else
                {
                    dict.Add(pair, model.GetAvailableNumbers(pair, checkedPair));
                }
            }

            return dict;
        }
        private static IEnumerable<sbyte> GetAvailableByDict(Dictionary<IndexPair, IEnumerable<sbyte>> dict, IndexPair pair)
        {
            var currentPairValue = dict.First(item => item.Key.X == pair.X && item.Key.Y == pair.Y).Value;
            if (currentPairValue.Count() == 1)
                return currentPairValue;

            while (/*RemoveFilledGroupNumbers(dict, 3) ||
                   SetGroupNumbersIfFilled(dict, 3) ||
                RemoveFilledGroupNumbers(dict, 2) ||
                SetGroupNumbersIfFilled(dict, 2) ||
                RemoveFilledGroupNumbers(dict, 1) ||
                SetGroupNumbersIfFilled(dict, 1)*/
                RemoveSingleNumbers(dict) ||
                SetNumbersIfSingle(dict))
            {
                currentPairValue = dict.First(item => item.Key.X == pair.X && item.Key.Y == pair.Y).Value;
                if (currentPairValue.Count() == 1)
                    return currentPairValue;
            }

            return dict.First(item => item.Key.X == pair.X && item.Key.Y == pair.Y).Value;
        }
 private void ResetNumber(IndexPair pair)
 {
     field[pair.X, pair.Y].ResetNumber();
 }
 private void ResetIsVisible(IndexPair pair)
 {
     field[pair.X, pair.Y].ResetIsVisible();
 }
        private void InitField()
        {
            field = new CellItem[CellLineCount, CellLineCount];
            indexPairs = new IndexPair[CellLineCount, CellLineCount];

            for (int i = 0; i < CellLineCount; i++)
                for (int j = 0; j < CellLineCount; j++)
                {
                    indexPairs[i, j] = new IndexPair(i, j);
                }

            foreach (var pair in GetAllPairs())
                field[pair.X, pair.Y] = new CellItem();

            cancellationTokenSource = new CancellationTokenSource();

            GameFieldFillHelper.Init(this, cancellationTokenSource.Token);
        }
 private IEnumerable<sbyte> GetRowNumbers(IndexPair pair, IndexPair checkedPair)
 {
     return GetAvailableNumbersByPairs(GetRowPairs(pair), checkedPair);
 }
        public IEnumerable<IndexPair> GetBlockPairs(IndexPair pair)
        {
            int xBlock = pair.X / BlockLineCount;
            int yBlock = pair.Y / BlockLineCount;

            int blockColumn = xBlock * BlockLineCount;
            int blockRow = yBlock * BlockLineCount;

            for (int i = 0; i < BlockLineCount; i++)
                for (int j = 0; j < BlockLineCount; j++)
                {
                    var xCell = blockColumn + i;
                    var yCell = blockRow + j;

                    yield return indexPairs[xCell, yCell];
                }
        }
        public void UpdateByTap(PointF point)
        {
            if (Model.IsInitializing)
                return;

            var ctmPoint = new PointF(point.X, Frame.Height - point.Y);

            if (Mode == EMode.Normal)
            {
                var x = (int)(ctmPoint.X / cellWidth);
                var y = (int)(ctmPoint.Y / cellHeight);
                var pair = new IndexPair(x, y);

                if (Model.GetItemVisible(pair))
                    return;

                SelectedPair = pair;

                DialogViewModel = new DialogViewModel(GetDialogFrame(ctmPoint), dialogBorder);

                Mode = EMode.Dialog;

                return;
            }

            if (Mode == EMode.Dialog)
            {
                if (DialogViewModel == null || DialogViewModel.IsInvisible)
                    return;

                if (DialogViewModel.IsInside(ctmPoint))
                {
                    Model.SetItemVisible(SelectedPair, true);

                    if (DialogViewModel.GetNumber(ctmPoint) != Model.GetItemNumber(SelectedPair))
                    {
                        Mode = EMode.Lose;
                    }
                    else if (Model.IsAllItemsVisible)
                    {
                        Mode = EMode.Win;
                    }
                    else
                    {
                        Mode = EMode.Normal;
                    }
                }
                else
                {
                    Mode = EMode.Normal;
                }

                SelectedPair = null;
                DialogViewModel = null;

                return;
            }
        }
 public sbyte GetItemNumber(IndexPair pair)
 {
     return field[pair.X, pair.Y].Number;
 }
 public void SetItemNumber(IndexPair pair, sbyte value)
 {
     field[pair.X, pair.Y].Number = value;
 }
 public bool IsItemNotAvailable(IndexPair pair, IndexPair checkedPair)
 {
     return IsItemEmpty(pair) || !GetItemVisible(pair) || checkedPair.X == pair.X && checkedPair.Y == pair.Y;
 }
 public bool IsSelectedPair(IndexPair pair)
 {
     var selectedPair = SelectedPair;
     return isInitializing && selectedPair != null && selectedPair.X == pair.X && selectedPair.Y == pair.Y;
 }
 public bool IsItemEmpty(IndexPair pair)
 {
     return field[pair.X, pair.Y].IsEmpty;
 }
 public IEnumerable<IndexPair> GetRowPairs(IndexPair pair)
 {
     for (int i = 0; i < CellLineCount; i++)
     {
         yield return indexPairs[i, pair.Y];
     }
 }
 public bool GetItemVisible(IndexPair pair)
 {
     return field[pair.X, pair.Y].IsVisible;
 }
        private static IEnumerable<sbyte> GetHeuristicsAvailableNumbers(GameFieldModel model, IndexPair pair, int rank = 1)
        {
            var blockDict = GetBlockAvailableDict(model, pair, rank);
            var available = GetAvailableByDict(blockDict, pair).ToList();

            if (available.Count < 2)
                return available;

            var rowDict = GetRowAvailableDict(model, pair, rank);
            available = available.Intersect(GetAvailableByDict(rowDict, pair)).ToList();

            if (available.Count < 2)
                return available;

            var columnDict = GetColumnAvailableDict(model, pair, rank);
            return available.Intersect(GetAvailableByDict(columnDict, pair));
        }
 private static Dictionary<IndexPair, IEnumerable<sbyte>> GetBlockAvailableDict(GameFieldModel model, IndexPair pair, int rank)
 {
     var blockPairs = model.GetBlockPairs(pair);
     return GetAvailableDictByPairs(model, blockPairs, pair, rank);
 }
 public void SetItemVisible(IndexPair pair, bool isVisible)
 {
     field[pair.X, pair.Y].IsVisible = isVisible;
 }
 public IEnumerable<IndexPair> GetColumnPairs(IndexPair pair)
 {
     for (int j = CellLineCount - 1; j >= 0; j--)
     {
         yield return indexPairs[pair.X, j];
     }
 }
        private IEnumerable<sbyte> GetAvailableNumbersByPairs(IEnumerable<IndexPair> pairs, IndexPair checkedPair)
        {
            foreach (var pair in pairs)
            {
                if (IsItemNotAvailable(pair, checkedPair))
                    continue;

                yield return GetItemNumber(pair);
            }
        }
        private IEnumerable<sbyte> GetCheckedAvailableNumbers(IndexPair pair, IndexPair checkedPair)
        {
            var cellBlockNumbers = GetBlockNumbers(pair, checkedPair);
            var cellRowNumbers = GetRowNumbers(pair, checkedPair);

            var blockRowNumbers = cellBlockNumbers.Union(cellRowNumbers).Distinct().ToList();

            if (blockRowNumbers.Count == CellLineCount)
                return new List<sbyte>();

            var cellColumnNumbers = GetColumnNumbers(pair, checkedPair);

            var alreadyGeneratedNumbers = blockRowNumbers.Union(cellColumnNumbers).Distinct();

            return numberList.Except(alreadyGeneratedNumbers);
        }
        public void UpdateByOffboardTap()
        {
            if (Mode != EMode.Dialog)
                return;

            Mode = EMode.Normal;
            SelectedPair = null;
            DialogViewModel = null;
        }
 private IEnumerable<sbyte> GetDefaultAvailableNumbers(IndexPair pair)
 {
     return GetItemNumber(pair).Yield();
 }
 private void FillCellBackground(IndexPair pair)
 {
     context.AddRect(new RectangleF(pair.X * cellWidth, pair.Y * cellHeight, cellWidth, cellHeight));
     context.DrawPath(CGPathDrawingMode.Fill);
 }
 public IEnumerable<sbyte> GetAvailableNumbers(IndexPair pair, IndexPair checkedPair)
 {
     return IsItemNotAvailable(pair, checkedPair)
             ? GetCheckedAvailableNumbers(pair, checkedPair)
             : GetDefaultAvailableNumbers(pair);
 }