public static IPlayer CreateCompetitor(StrikeInfo strikeModel, Ball ball, Hole hole, User player, ExperimentHistory history, IBallKickPhysics ballKick)
        {
            if (history == null)
                throw new NullReferenceException("history");

            IPlayer competitor;

            var competitorModel = strikeModel.CompetitorModel;

            if (competitorModel == null)
                throw new NullReferenceException("Модель соперника не задана");

            if (competitorModel is UniformCompetitorModel)
            {
                competitor = new UniformCompetitor(ball, hole, strikeModel.CompetitorModel as UniformCompetitorModel, player, ballKick);
            }
            else if (competitorModel is NormalAdaptiveCompetitorModel)
            {
                var errorGenerator = new NormalAdaptiveCompetitorRandom(strikeModel.CompetitorModel as NormalAdaptiveCompetitorModel, history);

                competitor = new Competitor(ball.Position.X, hole.Position.X, errorGenerator, ballKick);
            }
            else if (competitorModel is UniformAdaptiveCompetitorModel)
            {
                var errorGenerator = new UniformAdaptiveCompetitorRandom(strikeModel.CompetitorModel as UniformAdaptiveCompetitorModel, history, strikeModel.Hole.Size, strikeModel.Ball.Size);

                competitor = new Competitor(ball.Position.X, hole.Position.X, errorGenerator, ballKick);
            }
            else
            {
                throw new InvalidOperationException($"Модель соперника \"{competitorModel.GetType().Name}\" не поддерживается");
            }

            return competitor;
        }
        public void Initialize()
        {
            _dt = 1;

            t_ = 0;

            var currentStrike = gameObjects["currentStrikeInfo"] as StrikeInfo;

            if (currentStrike == null) throw new NullReferenceException("currentStrikeInfo");

            _strikeModel = currentStrike.Model;

            _strike = gameObjects["strike"] as Strike;

            if (_strike == null) throw new NullReferenceException("strike");

            _t2 = Convert.ToInt32((_strike.StrikeTimeSpan.TotalSeconds + _strikeModel.Delay) * 1000);

            _ball = gameObjects["ball"] as Ball;

            _ballStartPosition = new Vector2(_ball.Position.X, _ball.Position.Y);

            _hole = gameObjects["hole"] as Hole;

            var currentUser = gameObjects["currentUser"] as User;

            if (currentUser == null) throw new NullReferenceException("currentUser");
        }
        public NormalRandomPlayer(Ball ball, Hole hole, NormalPlayerModel playerModel, IBallKickPhysics ballKick)
        {
            _ball = ball;
            _hole = hole;
            _ballKick = ballKick;

            _playerModel = playerModel;
        }
        public HoleView(Hole hole, ICanvasView canvasView)
        {
            this.hole = hole;
            this.canvasView = canvasView;

            hole.PositionChanged += OnPositionChanged;
            hole.ColorChanged += hole_ColorChanged;
            hole.IsHitChanged += OnIsHitChanged;

            canvasView.SizeChanged += canvasView_SizeChanged;
        }
        public UniformCompetitor(Ball ball, Hole hole, UniformCompetitorModel competitorModel, User player, IBallKickPhysics ballKick)
        {
            _player = player;
            _ballKick = ballKick;
            _ball = ball;
            _hole = hole;
            _competitorModel = competitorModel;

            if (_competitorModel == null)
                throw new NullReferenceException("Не задана модель соперника");
        }
        public void Initialize()
        {
            _currentStrike = GameObjects["currentStrikeInfo"] as StrikeInfo;

            if (_currentStrike == null)
                throw new NullReferenceException("currentStrikeInfo");

            _ball = GetBall();
            SetupBall(_ball);

            _hole = GetHole();
            SetupHole(_hole);

            #region Задание параметров отображаемой мишени

            var holeInfo = _currentStrike.Hole;

            var holeView = GameObjects["holeView"] as HoleView;

            if (holeView == null)
                throw new NullReferenceException("holeView");

            // если отображаемый размер мишени не задан, используется действительный размер
            holeView.SetSize(holeInfo.VisibleSize == null ? holeInfo.Size : holeInfo.VisibleSize.Value);

            #endregion

            // Текущая игра
            var currentGame = GameObjects["currentGame"] as Game;

            if (currentGame == null)
                throw new NullReferenceException("currentGame");

            // Все игроки
            _users = GameObjects["users"] as Users;

            if (_users == null)
                throw new NullReferenceException("users");

            // Текущий игрок - испытуемый бьет первым
            _currentUser = _users.FirstOrDefault(t => t.UserInfo.UserType == UserTypeEnum.Bot);

            if (_currentUser == null)
                throw new NullReferenceException("currentUser");

            GameObjects["currentUser"] = _currentUser;

            // Снять выделение с имени игрока
            var userScoreView = GameObjects["userScoreView"] as UserScoreView;

            if (userScoreView == null)
                throw new NullReferenceException("userScoreView");

            userScoreView.IsActive = false;

            // Показать баллы соперника
            var botScoreView = GameObjects["botScoreView"] as UserScoreView;

            if (botScoreView == null)
                throw new NullReferenceException("botScoreView");

            botScoreView.Score = _currentUser.TotalScore;
            botScoreView.IsActive = true;

            GameObjects["currentUserScoreView"] = botScoreView;
        }
        private void SetupHole(Hole hole)
        {
            hole.Position = (Vector2)GameObjects["holeStartPosition"];

            var holeInfo = _currentStrike.Hole;
            hole.Size = holeInfo.Size;
            hole.IsHit = null;

            try
            {
                hole.Color = (Color)ColorConverter.ConvertFromString(holeInfo.Color);
            }
            catch (Exception exception)
            {
                _logger.Error(exception);

                hole.Color = Colors.Gray;
            }
        }
        public void Initialize()
        {
            _stopwatch.Reset();

            // Таймер
            _timer = _gameObjects["timer"] as Timer;

            if (_timer == null) throw new NullReferenceException("timer");

            _timer.Reset();

            // Таймер время до нажатия пробела
            _timerBeforeSpaceDown = _gameObjects["timerBeforeSpaceDown"] as Timer2;

            if (_timerBeforeSpaceDown == null)
                throw new NullReferenceException("timerBeforeSpaceDown");

            _timerBeforeSpaceDown.Reset();

            _firstLoop = true;

            _currentStrike = _gameObjects["currentStrikeInfo"] as StrikeInfo;

            if (_currentStrike == null)
                throw new NullReferenceException("currentStrikeInfo");

            var ballStartPosition = CreateBallStartPosition();
            StoreBallStartPosition(ballStartPosition);

            _ball = GetBall();
            SetupBall(_ball, ballStartPosition);

            var holeStartPosition = CreateHoleStartPosition();
            StoreHoleStartPosition(holeStartPosition);

            _hole = GetHole();
            SetupHole(_hole, holeStartPosition);

            #region Задание параметров отображаемой мишени

            var holeView = _gameObjects["holeView"] as HoleView;

            if (holeView == null)
                throw new NullReferenceException("holeView");

            var holeInfo = _currentStrike.Hole;
            // если отображаемый размер мишени не задан, используется действительный размер
            holeView.SetSize(holeInfo.VisibleSize == null ? holeInfo.Size : holeInfo.VisibleSize.Value);

            #endregion

            // Текущая игра
            _currentGame = _gameObjects["currentGame"] as Game;

            if (_currentGame == null)
                throw new NullReferenceException("currentGame");

            // Все игроки
            var users = _gameObjects["users"] as Users;

            if (users == null)
                throw new NullReferenceException("users");

            // Текущий игрок - испытуемый бьет первым
            _currentUser = users.FirstOrDefault(t => t.UserInfo.UserType == UserTypeEnum.User);

            if (_currentUser == null) throw new NullReferenceException("currentUser");

            _gameObjects["currentUser"] = _currentUser;

            // Снять выделение с имени игрока
            var botScoreView = GameObjects["botScoreView"] as UserScoreView;

            if (botScoreView != null)
            {
                botScoreView.IsActive = false;
            }

            // Показать очки игрока
            var userScoreView = GameObjects["userScoreView"] as UserScoreView;

            if (userScoreView == null) throw new NullReferenceException("userScoreView");

            userScoreView.Score = _currentUser.TotalScore;
            userScoreView.IsActive = true;

            GameObjects["currentUserScoreView"] = userScoreView;

            // Режим игрока
            var experiment = GameObjects["experiment"] as Experiment;

            if (experiment == null) throw new NullReferenceException("experiment");

            _inTestMode = experiment.Mode != null && experiment.Mode.Value == ExeprimentModeEnum.Test && _currentStrike.InTestMode != null;
        }
        private void SetupHole(Hole hole, Vector2 position)
        {
            hole.Position = position;

            _logger.Debug(string.Format("Hole position: {0};{1}", hole.Position.X, hole.Position.Y));

            var holeInfo = _currentStrike.Hole;
            hole.Size = holeInfo.Size;
            hole.IsHit = null;

            try
            {
                hole.Color = (Color)ColorConverter.ConvertFromString(holeInfo.Color);
            }
            catch (Exception exception)
            {
                _logger.Error(exception);

                hole.Color = Colors.Gray;
            }
        }
        public static Strike CreateStrike(Ball ball, Hole hole, StrikeInfo currentKick, KickResult kickResult,
            TimeSpan timeBeforeSpaceDown = new TimeSpan())
        {
            var kickedBall = new Ball()
            {
                Size = ball.Size,
                Position = ComputeBallPosition(ball, kickResult)
            };

            var miss = GetMiss(hole, kickedBall);

            var strikeTimeSpan = TimeSpan.FromSeconds(kickResult.ElapsedTime);

            var strike = new Strike
            {
                Number = currentKick.RepeatTimes,
                StrikeInfo = currentKick,
                DateTime = System.DateTime.Now,
                ErrorDistance = kickedBall.Position.X - hole.Position.X,
                IsHit = Math.Abs(miss - 0.0) < 0.001,
                MissDistance = Math.Round(miss, 3),
                MissTime = Math.Round(miss / currentKick.Model.Velocity, 3),
                BeforeStrikeTimeSpan = timeBeforeSpaceDown,
                StrikeTimeSpan = strikeTimeSpan,
                TotalTimeSpan = timeBeforeSpaceDown + strikeTimeSpan,
                StartBallPosition = ball.Position.Copy(),
                StartHolePosition = hole.Position.Copy()
            };

            return strike;
        }
        private static double GetMiss(Hole hole, Ball ball)
        {
            var radiusHole = hole.Size / 2;
            var lHole = hole.Position.X - radiusHole;
            var rHole = hole.Position.X + radiusHole;

            var radiusBall = ball.Size / 2;
            var lBall = ball.Position.X - radiusBall;
            var rBall = ball.Position.X + radiusBall;

            if (lHole > lBall) return lBall - lHole; // недолет

            if (rHole < rBall) return rBall - rHole; // перелет

            return 0.0;
        }