Files
basic-computer-games/08_Batnum/csharp/BatnumGame.cs
Martin Thoma e64fb6795c MAINT: Apply pre-commit
Remove byte-order-marker pre-commit check as there would be
many adjustments necessary
2022-03-05 09:29:23 +01:00

115 lines
3.7 KiB
C#

using Batnum.Properties;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Batnum
{
public enum WinOptions
{
/// <summary>
/// Last person to play wins
/// </summary>
WinWithTakeLast = 1,
/// <summary>
/// Last person to play loses
/// </summary>
WinWithAvoidLast = 2
}
public enum Players
{
Computer = 1,
Human = 2
}
public class BatnumGame
{
public BatnumGame(int pileSize, WinOptions winCriteria, int minTake, int maxtake, Players firstPlayer, Func<string, int>askPlayerCallback)
{
this.pileSize = pileSize;
this.winCriteria = winCriteria;
this.minTake = minTake;
this.maxTake = maxtake;
this.currentPlayer = firstPlayer;
this.askPlayerCallback = askPlayerCallback;
}
private int pileSize;
private WinOptions winCriteria;
private int minTake;
private int maxTake;
private Players currentPlayer;
private Func<string, int> askPlayerCallback;
/// <summary>
/// Returns true if the game is running
/// </summary>
public bool IsRunning => pileSize > 0;
/// <summary>
/// Takes the next turn
/// </summary>
/// <returns>A message to be displayed to the player</returns>
public string TakeTurn()
{
//Edge condition - can occur when minTake is more > 1
if (pileSize < minTake)
{
pileSize = 0;
return string.Format(Resources.END_DRAW, minTake);
}
return currentPlayer == Players.Computer ? ComputerTurn() : PlayerTurn();
}
private string PlayerTurn()
{
int draw = askPlayerCallback(Resources.INPUT_TURN);
if (draw == 0)
{
pileSize = 0;
return Resources.INPUT_ZERO;
}
if (draw < minTake || draw > maxTake || draw > pileSize)
{
return Resources.INPUT_ILLEGAL;
}
pileSize = pileSize - draw;
if (pileSize == 0)
{
return winCriteria == WinOptions.WinWithTakeLast ? Resources.END_PLAYERWIN : Resources.END_PLAYERLOSE;
}
currentPlayer = Players.Computer;
return "";
}
private string ComputerTurn()
{
//first calculate the move to play
int sumTake = minTake + maxTake;
int draw = pileSize - sumTake * (int)(pileSize / (float)sumTake);
draw = Math.Clamp(draw, minTake, maxTake);
//detect win/lose conditions
switch (winCriteria)
{
case WinOptions.WinWithAvoidLast when (pileSize == minTake): //lose condition
pileSize = 0;
return string.Format(Resources.END_COMPLOSE, minTake);
case WinOptions.WinWithAvoidLast when (pileSize <= maxTake): //avoid automatic loss on next turn
draw = Math.Clamp(draw, minTake, pileSize - 1);
break;
case WinOptions.WinWithTakeLast when pileSize <= maxTake: // win condition
draw = Math.Min(pileSize, maxTake);
pileSize = 0;
return string.Format(Resources.END_COMPWIN, draw);
}
pileSize -= draw;
currentPlayer = Players.Human;
return string.Format(Resources.COMPTURN, draw, pileSize);
}
}
}