Beispiel #1
0
    private IEnumerator GetGoodPosition()
    {
        isWinning = true;
        isReady   = false;

        ChangeText("Waiting for", "other modules...");

        // This waits for an arbitrary amount of time, to let other copies of this module through at different rates.
        yield return(new WaitForSecondsRealtime(URandom.Range(0, 2)));

        // This waits until another module that uses threads in this exact method is finished.
        yield return(new WaitWhile(() => _isUsingThreads));

        _isUsingThreads = true;

        bool isEvaluating = false;

        string position = "";

        ChangeText("Preparing...", "Please wait.");

        var game  = new CGameResult {
        };
        var moves = new List <CGameResult>();

        new Thread(() =>
        {
            // Find a game that takes 6-8 moves to complete in ideal play, using the Rust library.
            while (true)
            {
                position     = RandomPosition;
                isEvaluating = true;
                game         = Engine.Calculate(position, Position.Depth, true);

                if (!Mathf.Abs(game.Evaluation).InRange(112, 116))
                {
                    continue;
                }

                // Sometimes the evaluation is in favor of black, we need to advance the game by one move so that it is black to move.
                if (game.Evaluation < 0)
                {
                    position = game.Move(position);
                }

                // Set the player side to always whichever one is winning.
                color = (PieceColor)Convert.ToInt32(game.Evaluation < 0);

                // Reset the move list.
                moves = new List <CGameResult>();

                var colorMut             = color;
                string positionMut       = position;
                bool isGameCorrectlyOver = false;

                // The bot plays against itself until the perfect game is constructed.
                for (int depth = Position.Depth; depth > 0; depth--)
                {
                    var gameMut = Engine.Calculate(positionMut, depth, colorMut == PieceColor.White);

                    if ((gameMut.Evaluation == sbyte.MaxValue && color == PieceColor.White) ||
                        (gameMut.Evaluation == sbyte.MinValue && color == PieceColor.Black))
                    {
                        isGameCorrectlyOver = true;
                    }

                    try
                    {
                        positionMut = gameMut.Move(positionMut);
                    }
                    // There are no moves to play when this exception is triggered.
                    catch (IndexOutOfRangeException)
                    {
                        break;
                    }

                    colorMut = colorMut.Flip();

                    moves.Add(gameMut);
                }

                // Ensures that what it logs is indeed a checkmate. This reverifies that the puzzle is possible.
                if (isGameCorrectlyOver && moves.Count == 128 - Math.Abs(game.Evaluation) - (color == PieceColor.White ? 1 : 0))
                {
                    break;
                }
            }

            this.position = position;

            souvenirPositions = new List <string>();

            isReady = true;
        }).Start();

        // As long as the thread is running, it should generate and render random positions to distract the player.
        while (!isReady)
        {
            yield return(new WaitUntil(() => isEvaluating || isReady));

            isEvaluating = false;

            RenderPosition(position);

            PlaySound(new[] { Sounds._1dch.Capture, Sounds._1dch.Check, Sounds._1dch.Opponent, Sounds._1dch.Self }.PickRandom());
        }

        Log("The position is {0}; {1} to play, mate in {2}. To beat Rustmate, the best sequence of moves are {3}.", position, color, (128 - Math.Abs(game.Evaluation)) / 2, ToLog(moves));

        MovesLeft = (128 - Math.Abs(game.Evaluation)) / 2;

        _isUsingThreads = false;

        PlaySound(Sounds._1dch.GameStart);

        ChangeText("Mate in", "", MovesLeft.ToString());
    }
Beispiel #2
0
    private void OnInteract(int arg)
    {
        // This prevents you from making a move while the computer is thinking.
        if (!isReady)
        {
            return;
        }

        // This prevents you from selecting an empty space as the origin.
        if (position[arg] == Position.PieceChars[0] && last == null)
        {
            return;
        }

        // This prevents you from selecting a piece that isn't yours as the origin.
        if (position[arg].GetPieceColor() != color && last == null)
        {
            return;
        }

        // Gives button feedback.
        ButtonEffect(Buttons[arg], 1, Sounds._1dch.Click);

        // Highlight the selected square.
        BoardRenderers[arg].material.color = _colorScheme[2];

        // The destination is selected.
        if (last != null)
        {
            // The user did not deselect.
            if (last != arg)
            {
                bool isLegalMove = Engine.IsLegalMove(position, (sbyte)last, (sbyte)arg);

                // Updates the position on a legal move, cancels the selection otherwise.
                if (isLegalMove)
                {
                    // Creates the desired move.
                    var move = new CGameResult
                    {
                        Piece       = position[(int)last].Piece(),
                        Origin      = (sbyte)last,
                        Destination = (sbyte)arg
                    };

                    position = move.Move(position, this);

                    Log("You play {0}, the position is now {1}.", ToLog(move), position);

                    souvenirPositions.Add(ToLog(move));

                    MovesLeft--;
                    StartCoroutine(GetEngineMove());
                }

                PlaySound(isLegalMove ? Sounds._1dch.Self : Sounds._1dch.Illegal);
            }

            RenderPosition(position);
        }

        // Toggle _lastSelect between null and the argument passed in to the method.
        last = last == null ? (int?)arg : null;
    }