private void model_Moved(object sender, MoveEventArgs e)
        {
            if (isModelLoadingMoves)
            {
                return;
            }

            // if in navigational mode (possible only if the human player has moved)
            if (navMode)
            {
                // request for AI turn
                RequestForAITurn();

                // exit navigational mode
                navMode = false;
            }

            // if the game has not ended and if it is engine turn
            if (!model.IsEnded && AITurn)
            {
                // start engine thinking
                EngineInputParameters inputParams = GetEngineInputParams();
                engineWorker.RunWorkerAsync(inputParams);
            }
        }
        /// <summary>
        /// Starts engine thinking.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected override void engineWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            EngineInputParameters inputParams = e.Argument as EngineInputParameters;

            // call the web service engine synchronously
            string canMove = engineService.GetNextMove(inputParams.FEN, inputParams.RepetitiveMoveCandidate, inputParams.DepthLevel);

            e.Result = Utils.GetCANMove(model, canMove);
        }
        /// <summary>
        /// Gets the engine input parameters from the current game.
        /// </summary>
        /// <returns></returns>
        private EngineInputParameters GetEngineInputParams()
        {
            EngineInputParameters inputParams = new EngineInputParameters();

            // set the current board FEN
            inputParams.FEN = Utils.GetFEN(model.CurrentBoard);

            // set the repetitive move candidate
            Move repMove = model.RepetitiveMoveCandidate;

            inputParams.RepetitiveMoveCandidate = repMove != null?Utils.GetCAN(repMove) : null;

            // set the depth level
            inputParams.DepthLevel = OpponentsSettings.Default.AIOpponentLevel;

            return(inputParams);
        }
        /// <summary>
        /// Force engine to start thinking and move.
        /// </summary>
        internal void ForceAIMove()
        {
            if (model == null || !model.IsInitialized)
            {
                return;
            }

            // if the game has not ended and the engine has ended thinking
            if (!model.IsEnded && !engineWorker.IsBusy)
            {
                // exit navigational mode
                navMode = false;

                // request for AI turn
                RequestForAITurn();

                // start engine thinking
                EngineInputParameters inputParams = GetEngineInputParams();
                engineWorker.RunWorkerAsync(inputParams);
            }
        }