<commit_before>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using ITCC.Logging.Core;
using TicTacToeGame.Common.Enums;
using TicTacToeGame.Common.Interfaces;
using TicTacToeGame.Common.Utils;

namespace TicTacToeGame.Common
{
    public sealed class Game
    {
        #region public

        public const int VictoryLength = 5;
        public const int StepWaitInterval = 50;

        public static Game CreateNewGame(GameConfiguration configuration)
        {
            if (configuration == null || !configuration.IsValid())
                return null;

            return new Game(configuration);
        }

        public void Start()
        {
            lock (_stateLock)
            {
                if (_started)
                    return;
                _started = true;

            }

            _gameThread = new Thread(GameLoop);
            _gameThread.Start();
        }

        public void ReportStepProcessed()
        {
            lock (_stepLock)
            {
                _stepProcessed = true;
            }
        }

        public void WaitGameCompleted() => _gameThread.Join();

        public event EventHandler<GameStateChangedEventArgs> GameStateChanged;
        public event EventHandler<GameEndedEventArgs> GameEnded; 
         
        #endregion

        #region private
        private Game(GameConfiguration configuration)
        {
            _width = configuration.Width;
            _height = configuration.Height;
            _botTurnLength = configuration.BotTurnLength;
            _firstPlayer = configuration.FirstPlayer;
            _secondPlayer = configuration.SecondPlayer;

            _currentSign = CellSign.X;
            _currentPlayer = _firstPlayer;
            _field = new CellSign[_height, _width];
            LogMessage(LogLevel.Info, $"Game {_height}x{_width} created ({_firstPlayer.Name} vs {_secondPlayer.Name})");
        }

        private void GameLoop()
        {
            LogMessage(LogLevel.Info, "Game loop started");
            while (true)
            {
                _step++;
                var move = GetNextMove();

                if (move == null)
                {
                    if (_currentPlayer.Type == PlayerType.Bot)
                        LogMessage(LogLevel.Info, $"Move by {_currentPlayer.Name} took longer than {_botTurnLength}ms, {NotCurrentPlayer.Name} won");
                    else
                        LogMessage(LogLevel.Info, $"{_currentPlayer.Name} tried to submit null move");
                    ReportCurrentMoveInvalid();
                    return;
                }

                if (!MoveIsValid(move))
                {
                    LogMessage(LogLevel.Info, $"Move ({move.X}, {move.Y}) by {_currentPlayer.Name} is not valid, {NotCurrentPlayer.Name} won");
                    ReportCurrentMoveInvalid();
                    return;
                }

                ApplyMove(move);
                var winningSet = GetWinningSet();
                if (winningSet != null)
                {
                    LogMessage(LogLevel.Info, $"{_currentPlayer.Name} won with ({move.X}, {move.Y}) move");
                    ReportCurrentPlayerWon(winningSet);
                    return;
                }<commit_msg>Game ended reports fixed<commit_after>﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using ITCC.Logging.Core;
using TicTacToeGame.Common.Enums;
using TicTacToeGame.Common.Interfaces;
using TicTacToeGame.Common.Utils;

namespace TicTacToeGame.Common
{
    public sealed class Game
    {
        #region public

        public const int VictoryLength = 5;
        public const int StepWaitInterval = 50;

        public static Game CreateNewGame(GameConfiguration configuration)
        {
            if (configuration == null || !configuration.IsValid())
                return null;

            return new Game(configuration);
        }

        public void Start()
        {
            lock (_stateLock)
            {
                if (_started)
                    return;
                _started = true;

            }

            _gameThread = new Thread(GameLoop);
            _gameThread.Start();
        }

        public void ReportStepProcessed()
        {
            lock (_stepLock)
            {
                _stepProcessed = true;
            }
        }

        public void WaitGameCompleted() => _gameThread.Join();

        public event EventHandler<GameStateChangedEventArgs> GameStateChanged;
        public event EventHandler<GameEndedEventArgs> GameEnded; 
         
        #endregion

        #region private
        private Game(GameConfiguration configuration)
        {
            _width = configuration.Width;
            _height = configuration.Height;
            _botTurnLength = configuration.BotTurnLength;
            _firstPlayer = configuration.FirstPlayer;
            _secondPlayer = configuration.SecondPlayer;

            _currentSign = CellSign.X;
            _currentPlayer = _firstPlayer;
            _field = new CellSign[_height, _width];
            LogMessage(LogLevel.Info, $"Game {_height}x{_width} created ({_firstPlayer.Name} vs {_secondPlayer.Name})");
        }

        private void GameLoop()
        {
            LogMessage(LogLevel.Info, "Game loop started");
            while (true)
            {
                _step++;
                var move = GetNextMove();

                if (move == null)
                {
                    if (_currentPlayer.Type == PlayerType.Bot)
                    {
                        LogMessage(LogLevel.Info,
                            $"Move by {_currentPlayer.Name} took longer than {_botTurnLength}ms, {NotCurrentPlayer.Name} won");
                        ReportMoveTimeout();
                    }
                    else
                    {
                        LogMessage(LogLevel.Info, $"{_currentPlayer.Name} tried to submit null move");
                        ReportCurrentMoveInvalid();
                    }
                        
                    return;
                }

                if (!MoveIsValid(move))
                {
                    LogMessage(LogLevel.Info, $"Move ({move.X}, {move.Y}) by {_currentPlayer.Name} is not valid, {NotCurrentPlayer.Name} won");
                    ReportCurrentMoveInvalid();
                    return;
                }

                ApplyMove(move);
                var winningSet = GetWinningSet();
                if (winningSet != null)
                {
                    LogMessage(LogLevel.Info, $"{_currentPlayer.Name} won with ({move.X}, {move.Y}) move");
                    ReportCurrentPlayerWon(winningSet);
                    return;
                }
{'fraction_non_alphanumeric': 0.08397613156745742, 'fraction_numerical': 0.0008732353369233009, 'mean_word_length': 1.508029197080292, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2617099', 'n_tokens_mistral': 1729, 'n_tokens_neox': 1625, 'n_words': 372}