//Rozdział 24.
//Metoda szablonowa
// Symulacja gry

public abstract class Game
{
    public void Run()
    {
        Start();
        while (!HaveWinner)
            TakeTurn();
            WriteLine($"Gracz {WinningPlayer} wygrał.");
    }
}

protected abstract void Start();
protected abstract bool HaveWinner { get; }
protected abstract void TakeTurn();
protected abstract int WinningPlayer { get; }

public abstract class Game
{
    public Game(int numberOfPlayers)
    {
        this.numberOfPlayers = numberOfPlayers;
    }
    protected int currentPlayer;
    protected readonly int numberOfPlayers;
    // pozostałe składowe pominięto
}

public class Chess : Game
{
    public Chess() : base(2) { /* 2 graczy */ }
    protected override void Start()
    {
        WriteLine($"Rozpoczęcie gry w szachy z {numberOfPlayers} graczami.");
    }

    protected override bool HaveWinner => turn == maxTurns;
    protected override void TakeTurn()
    {
        WriteLine($"Gracz {currentPlayer} wykonał {turn++}. ruch.");
        currentPlayer = (currentPlayer + 1) % numberOfPlayers;
    }
    protected override int WinningPlayer => currentPlayer;
    private int maxTurns = 10;
    private int turn = 1;
}


// Funkcyjna odmiana Metody szablonowej

 type GameState = {
    CurrentPlayer: int;
    NumberOfPlayers: int;
    HaveWinner: bool;
    WinningPlayer: int;
}
 let runGame initialState startAction takeTurnAction
haveWinnerAction =
    let state = initialState
    startAction state
    while not (haveWinnerAction state) do
        takeTurnAction state
    printfn "Gracz %i wygrał." state.WinningPlayer
 let chess() =
    let mutable turn = 0
    let mutable maxTurns = 10
    let state = {
        NumberOfPlayers = 2;
        CurrentPlayer = 0;
        WinningPlayer = -1;
    }
    let start state =
        printfn "Rozpoczęcie gry w szachy z %i graczami" state.NumberOfPlayers

    let takeTurn state =
        printfn "Gracz %i wykonał ruch %i." turn state.CurrentPlayer
        state.CurrentPlayer <- (state.CurrentPlayer+1) % state.
        NumberOfPlayers
        turn <- turn + 1
        state.WinningPlayer <- state.CurrentPlayer

    let haveWinner state =
        turn = maxTurns

    runGame state start takeTurn haveWinner
 
