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()); }
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; }