<commit_before>﻿/*********************************************************************************
 * Game.cs
 * 
 * Copyright (c) 2004-2017 <NAME>
 * 
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 * 
 *        http://www.apache.org/licenses/LICENSE-2.0
 * 
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 * 
 *********************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;

namespace Sandra.Chess
{
    /// <summary>
    /// Represents a standard game of chess.
    /// </summary>
    public class Game
    {
        private readonly Position initialPosition;
        private readonly MoveTree moveTree;

        private Position currentPosition;
        private MoveTree activeTree;

        private Game(Position initialPosition, MoveTree moveTree)
        {
            this.initialPosition = initialPosition;
            currentPosition = initialPosition.Copy();
            this.moveTree = moveTree;
            activeTree = moveTree;
        }

        /// <summary>
        /// Creates a new game with a given initial <see cref="Position"/>.
        /// </summary>
        public Game(Position initialPosition) : this(initialPosition,
                                                     new MoveTree(initialPosition.SideToMove == Color.Black))
        {
        }

        /// <summary>
        /// Returns a copy of this game, with the same initial <see cref="Position"/> and shared <see cref="Chess.MoveTree"/>,
        /// but in which <see cref="ActiveTree"/> can be manipulated independently.
        /// </summary>
        public Game Copy() => new Game(initialPosition, moveTree);

        /// <summary>
        /// Gets the initial position of this game.
        /// </summary>
        public Position InitialPosition => initialPosition.Copy();

        /// <summary>
        /// Gets the <see cref="Color"/> of the side to move in the initial position.
        /// </summary>
        public Color InitialSideToMove => initialPosition.SideToMove;

        /// <summary>
        /// Gets a reference to the root of the <see cref="Chess.MoveTree"/> of this <see cref="Game"/>.
        /// </summary>
        public MoveTree MoveTree => moveTree;

        /// <summary>
        /// Gets the current position of this game.
        /// </summary>
        public Position CurrentPosition => currentPosition.Copy();

        /// <summary>
        /// Gets the move tree which is currently active.
        /// </summary>
        public MoveTree ActiveTree => activeTree;

        private void setActiveTree(MoveTree value)
        {
            // Replay all moves until the new active tree has been reached.
            Stack<Move> previousMoves = new Stack<Move>();
            MoveTree newActiveTree = value;

            MoveTree current;
            for (current = newActiveTree; current.ParentVariation != null; current = current.ParentVariation.ParentTree)
            {
                previousMoves.Push(current.ParentVariation.Move);
            }

            // 'value' should be embedded somewhere inside this.moveTree.
            if (current != moveTree)
            {
                throw new ArgumentException(nameof(value), "value is not embedded in Game.MoveTree.");
            }

            Position newPosition = initialPosition.Copy();
            foreach (Move move in previousMoves)
            {
                newPosition.FastMakeMove(move);
            }

            currentPosition = newPosition;
            activeTree = newActiveTree;
            RaiseActiveMoveIndexChanged();
        }

        public void SetActiveTree(MoveTree value)
        {
            if (value == null)
            {
                throw new ArgumentNullException(nameof(value));
            }

            if (activeTree != value)
            {
                setActiveTree(value);
            }
        }

        public bool IsFirstMove => activeTree.ParentVariation == null;
        public bool IsLastMove => activeTree.MainLine == null;
        public Move PreviousMove() => activeTree.ParentVariation.Move;

        public void Backward()
        {
            if (IsFirstMove)
            {
                throw new InvalidOperationException("Cannot go backward when it's the first move.");
            }

            // Replay until the previous move.
            setActiveTree(activeTree.ParentVariation.ParentTree);
        }

        public void Forward()
        {
            if (IsLastMove)
            {
                throw new InvalidOperationException("Cannot go forward when it's the last move.");
            }

            currentPosition.FastMakeMove(activeTree.MainLine.Move);<commit_msg>Instead of throwing, just no effect in Game.Backward() and Game.Forward() if at the start or end of the game.<commit_after>﻿/*********************************************************************************
 * Game.cs
 * 
 * Copyright (c) 2004-2017 <NAME>
 * 
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 * 
 *        http://www.apache.org/licenses/LICENSE-2.0
 * 
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 * 
 *********************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;

namespace Sandra.Chess
{
    /// <summary>
    /// Represents a standard game of chess.
    /// </summary>
    public class Game
    {
        private readonly Position initialPosition;
        private readonly MoveTree moveTree;

        private Position currentPosition;
        private MoveTree activeTree;

        private Game(Position initialPosition, MoveTree moveTree)
        {
            this.initialPosition = initialPosition;
            currentPosition = initialPosition.Copy();
            this.moveTree = moveTree;
            activeTree = moveTree;
        }

        /// <summary>
        /// Creates a new game with a given initial <see cref="Position"/>.
        /// </summary>
        public Game(Position initialPosition) : this(initialPosition,
                                                     new MoveTree(initialPosition.SideToMove == Color.Black))
        {
        }

        /// <summary>
        /// Returns a copy of this game, with the same initial <see cref="Position"/> and shared <see cref="Chess.MoveTree"/>,
        /// but in which <see cref="ActiveTree"/> can be manipulated independently.
        /// </summary>
        public Game Copy() => new Game(initialPosition, moveTree);

        /// <summary>
        /// Gets the initial position of this game.
        /// </summary>
        public Position InitialPosition => initialPosition.Copy();

        /// <summary>
        /// Gets the <see cref="Color"/> of the side to move in the initial position.
        /// </summary>
        public Color InitialSideToMove => initialPosition.SideToMove;

        /// <summary>
        /// Gets a reference to the root of the <see cref="Chess.MoveTree"/> of this <see cref="Game"/>.
        /// </summary>
        public MoveTree MoveTree => moveTree;

        /// <summary>
        /// Gets the current position of this game.
        /// </summary>
        public Position CurrentPosition => currentPosition.Copy();

        /// <summary>
        /// Gets the move tree which is currently active.
        /// </summary>
        public MoveTree ActiveTree => activeTree;

        private void setActiveTree(MoveTree value)
        {
            // Replay all moves until the new active tree has been reached.
            Stack<Move> previousMoves = new Stack<Move>();
            MoveTree newActiveTree = value;

            MoveTree current;
            for (current = newActiveTree; current.ParentVariation != null; current = current.ParentVariation.ParentTree)
            {
                previousMoves.Push(current.ParentVariation.Move);
            }

            // 'value' should be embedded somewhere inside this.moveTree.
            if (current != moveTree)
            {
                throw new ArgumentException(nameof(value), "value is not embedded in Game.MoveTree.");
            }

            Position newPosition = initialPosition.Copy();
            foreach (Move move in previousMoves)
            {
                newPosition.FastMakeMove(move);
            }

            currentPosition = newPosition;
            activeTree = newActiveTree;
            RaiseActiveMoveIndexChanged();
        }

        public void SetActiveTree(MoveTree value)
        {
            if (value == null)
            {
                throw new ArgumentNullException(nameof(value));
            }

            if (activeTree != value)
            {
                setActiveTree(value);
            }
        }

        public bool IsFirstMove => activeTree.ParentVariation == null;
        public bool IsLastMove => activeTree.MainLine == null;
        public Move PreviousMove() => activeTree.ParentVariation.Move;

        public void Backward()
        {
            // No effect if first move.
            if (IsFirstMove) return;

            // Replay until the previous move.
            setActiveTree(activeTree.ParentVariation.ParentTree);
        }

        public void Forward()
        {
            // No effect if last move.
            if (IsLastMove) return;

            currentPosition.FastMakeMove(activeTree.MainLine.Move);
{'fraction_non_alphanumeric': 0.12147251244995606, 'fraction_numerical': 0.002343521140513622, 'mean_word_length': 1.927958833619211, 'pattern_counts': {'":': 0, '<': 55, '<?xml version=': 0, '>': 73, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4584334', 'n_tokens_mistral': 2428, 'n_tokens_neox': 2330, 'n_words': 791}