protected virtual IEnumerator PlayMoveRoutine(AIMove m, float cursorDelay)
        {
            var b = grid.Get(m.x, m.y);

            showCursor = true;
            CreateCursor(0, b, true);

            yield return(new WaitForSeconds(cursorDelay));

            if (grid.CanMove(b.block.x, b.block.y))
            {
                grid.Move(b.block, m.direction);
            }
            else
            {
                // Can't move?
                // Maybe it's due to optimisation...
                // Try to move the neighbor
                var neighbor = grid.Get(m.x + m.direction, m.y);
                if (neighbor != null)
                {
                    grid.Move(neighbor.block, -1 * m.direction);
                }
            }
        }
Beispiel #2
0
        public virtual int WeightDanger(AIMove m, Vector2 highestBlock, WeightData w)
        {
            const float DANGER_HEIGHT = 0.77f;

            // Combos avoid danger.
            // So doing combos is always nice, better than throwing blocks away
            if (w.combosCount > 0)
            {
                return(w.combosCount * Values.danger);
            }

            int weight = 0;
            //int width = m.gridAfterMove.GetUpperBound(0) + 1;
            int height = m.gridAfterMove.GetUpperBound(1) + 1;
            int dangerHeightThreshold = (int)(height * DANGER_HEIGHT);

            if (highestBlock.y > dangerHeightThreshold)
            {
                if (highestBlock.y > GetHighest(m.gridAfterMove).y)
                {
                    weight += Values.danger;
                }
            }

            return(weight);
        }
Beispiel #3
0
        public virtual int WeightGeneral(AIMove m, int depth)
        {
            // Weight is slightly impacted by the number of moves required to get to the combo
            // SHOULD BE NEGATIVE. GOING DEEPER IS NOT BETTER.

            // We could weight anything else here

            return(depth * Values.depth);
        }
Beispiel #4
0
        private void PrepareMoveToPlay(AIMove move)
        {
            nothingToDoCount = 0;
            PlayMove         = true;
            var path = GetPathFromChildren(move);

            foreach (var m in path)
            {
                movesToPlay.Enqueue(m);
            }
        }
Beispiel #5
0
        private List <AIMove> GetPathFromChildren(AIMove child)
        {
            List <AIMove> path = new List <AIMove>()
            {
                child
            };
            AIMove current = child.parent;

            while (current != null)
            {
                path.Insert(0, current);
                current = current.parent;
            }

            return(path);
        }
Beispiel #6
0
        /// <summary>
        /// Apply the move to the simplified grid and returns the new grid (with uncleared combos)
        /// </summary>
        public sbyte[,] GetGridWithMove(sbyte[,] baseGrid, AIMove move)
        {
            // Copy array
            sbyte[,] gridCopy = (sbyte[, ])baseGrid.Clone();
            int x1    = move.x;
            int x2    = move.x + move.direction;
            int yBase = move.y;

            // Swap
            sbyte a = baseGrid[x1, yBase];
            sbyte b = baseGrid[x2, yBase];

            gridCopy[x1, yBase] = b;
            gridCopy[x2, yBase] = a;

            // Do the fall checks from bot to top
            int pxStart = x1 < x2 ? x1 : x2;
            int pxMax   = x1 > x2 ? x1 : x2;

            gridCopy = ForceFall(gridCopy, pxStart, pxMax);

            return(gridCopy);
        }
Beispiel #7
0
        /// <summary>
        /// Compute a weight on the move
        /// </summary>
        public virtual WeightData WeightMove(AIMove m, int width, int height, int depth)
        {
            var w = new WeightData();

            blocksInComboIndex      = 0;
            currentComboBlocksIndex = 0;

            if (m.gridAfterMove == null)
            {
                Log.Error("AI - Missing grid for move!");
                return(w);
            }

            int weight = WeightGeneral(m, depth);

            // Compute combos
            sbyte currentBlock = 0;
            int   currentCombo = 0;

            void CommitCommbo()
            {
                weight += WeightCombo(currentCombo, currentBlock, m.gridAfterMove, width, height);

                w.combosCount++;

                // Transfer current list to general list
                for (int i = 0; i < currentComboBlocksIndex; i++)
                {
                    if (blocksInComboIndex < blocksInCombo.Length)
                    {
                        blocksInCombo[blocksInComboIndex] = currentComboBlocks[i];
                        blocksInComboIndex++;
                    }
                }
            }

            var highestBlock = Vector2.one * -1;

            // Vertical
            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    sbyte block = m.gridAfterMove[x, y];
                    if (block == 99)
                    {
                        continue;
                    }

                    // Not in a combo
                    if (currentBlock == 0)
                    {
                        if (block > 0)
                        {
                            currentBlock = block;
                            currentCombo = 1;

                            // Same than a list.Add(new Vector) but better when 10 000 elements!
                            currentComboBlocks[currentComboBlocksIndex].x = x;
                            currentComboBlocks[currentComboBlocksIndex].y = y;
                            currentComboBlocksIndex++;
                        }
                        else
                        {
                            currentBlock            = 0;
                            currentCombo            = 0;
                            currentComboBlocksIndex = 0;
                        }
                    }
                    else
                    {
                        // Blocks are falling
                        if (block == 0)
                        {
                            // Skip
                            continue;
                        }

                        // Check for an identical block
                        if (currentBlock == block)
                        {
                            currentCombo++;

                            currentComboBlocks[currentComboBlocksIndex].x = x;
                            currentComboBlocks[currentComboBlocksIndex].y = y;
                            currentComboBlocksIndex++;
                        }
                        // Combo breaker
                        else
                        {
                            if (currentCombo >= 3)
                            {
                                CommitCommbo();
                            }

                            // Reset
                            currentCombo = 1;
                            currentBlock = block;
                            currentComboBlocks[currentComboBlocksIndex].x = x;
                            currentComboBlocks[currentComboBlocksIndex].y = y;
                            currentComboBlocksIndex++;
                        }
                    }

                    if (block > 0)
                    {
                        if (y > highestBlock.y)
                        {
                            highestBlock.x = x;
                            highestBlock.y = y;
                        }
                    }
                } // y

                if (currentCombo >= 3)
                {
                    CommitCommbo();
                }

                // Reset
                currentBlock            = 0;
                currentCombo            = 0;
                currentComboBlocksIndex = 0; // list.Clear
            } // x

            // Horizontal
            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    sbyte block = m.gridAfterMove[x, y];
                    if (block == 99)
                    {
                        continue;
                    }

                    // Not in a combo
                    if (currentBlock == 0)
                    {
                        if (block > 0)
                        {
                            currentBlock = block;
                            currentCombo = 1;
                            currentComboBlocks[currentComboBlocksIndex].x = x;
                            currentComboBlocks[currentComboBlocksIndex].y = y;
                            currentComboBlocksIndex++;
                        }
                        else
                        {
                            currentBlock            = 0;
                            currentCombo            = 0;
                            currentComboBlocksIndex = 0;
                        }
                    }
                    else
                    {
                        // Check for an identical block
                        if (currentBlock == block)
                        {
                            currentCombo++;
                            currentComboBlocks[currentComboBlocksIndex].x = x;
                            currentComboBlocks[currentComboBlocksIndex].y = y;
                            currentComboBlocksIndex++;
                        }
                        // Combo breaker
                        else
                        {
                            if (currentCombo >= 3)
                            {
                                CommitCommbo();
                            }

                            // Reset
                            currentCombo = 1;
                            currentBlock = block;
                            currentComboBlocks[currentComboBlocksIndex].x = x;
                            currentComboBlocks[currentComboBlocksIndex].y = y;
                            currentComboBlocksIndex++;
                        }
                    }
                } // x

                if (currentCombo >= 3)
                {
                    CommitCommbo();
                }

                // Reset
                currentBlock            = 0;
                currentCombo            = 0;
                currentComboBlocksIndex = 0;
            } // y

            // Check if the game over is near
            weight += WeightDanger(m, highestBlock, w);

            w.total         = weight;
            w.blocksInCombo = blocksInCombo.Take(blocksInComboIndex).ToArray();

            return(w);
        }
Beispiel #8
0
        /// <summary>
        /// Get all possible moves from the simplified grid
        /// </summary>
        public List <AIMove> GetMoves(int level, sbyte[,] g, int minX, int maxX, AIMove parent)
        {
            // Explore the grid!
            int width  = g.GetUpperBound(0) + 1;
            int height = g.GetUpperBound(1) + 1;

            // Find the moves
            var moves        = new List <AIMove>();
            int currentCount = 0;
            int limit        = settings.movesLimits.Length > level ? settings.movesLimits[level] : int.MaxValue;

            // Look left only on the first step. Then right only.
            int start = minX + 1;

            for (int x = start;
                 x < maxX;
                 x++)
            {
                // Be sure we're in the grid
                if (x < 0 || x >= width)
                {
                    continue;
                }

                for (int y = 0; y < height; y++)
                {
                    int block = g[x, y];
                    if (block >= 0 && block < 99) // Not empty & not garbage
                    {
                        // Check left
                        if (x > 0 && x == start)
                        {
                            if (block != 0 || g[x - 1, y] != 0)
                            {
                                if (parent == null || (parent.x != (x - 1) && parent.y != y && parent.direction != -1))
                                {
                                    moves.Add(new AIMove(x, y, -1, parent));
                                    currentCount++;
                                }
                            }
                        }

                        // Check right
                        if (x < width - 1)
                        {
                            if (block != 0 || g[x + 1, y] != 0)
                            {
                                if (parent == null || (parent.x != (x + 1) && parent.y != y && parent.direction != 1))
                                {
                                    moves.Add(new AIMove(x, y, 1, parent));
                                    currentCount++;
                                }
                            }
                        }
                    }

                    if (level > 0 && currentCount > limit)
                    {
                        return(moves);
                    }
                }
            }

            // First depth = randomize please
            if (level == 0 && limit > 0)
            {
                return(moves.OrderBy(m => Random.Range(0f, 1f)).Take(limit).ToList());
            }

            return(moves);
        }
Beispiel #9
0
        /// <summary>
        /// Compute a list of possible moves from a given grid
        /// </summary>
        /// <param name="level">Depth</param>
        /// <param name="n">Branch index</param>
        /// <param name="g"></param>
        /// <param name="minX">Left bound</param>
        /// <param name="maxX">Right bound</param>
        /// <param name="parent"></param>
        /// <returns></returns>
        public List <AIMove> GetWeightedMoves(int level, int n, sbyte[,] g, int minX, int maxX, AIMove parent)
        {
            int width  = g.GetUpperBound(0) + 1;
            int height = g.GetUpperBound(1) + 1;

            var moves = GetMoves(level, g, minX, maxX, parent);

            if (moves.Count > 0)
            {
                foreach (var m in moves)
                {
                    m.gridAfterMove = GetGridWithMove(g, m);

                    var weightData = heuristic.WeightMove(m, width, height, level);

                    m.weight     = weightData.total + (parent?.weight ?? 0);
                    m.depthLevel = level;
                    m.comboCount = weightData.combosCount + (parent?.comboCount ?? 0);

                    m.gridAfterMove = RemoveCombos(m.gridAfterMove, weightData.blocksInCombo);
                }
            }

            return(moves);
        }
 protected virtual void PlayMove(AIMove m, float cursorDelay = 0.25f)
 {
     StartCoroutine(PlayMoveRoutine(m, cursorDelay));
 }