mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-21 23:00:43 -08:00
Removed spaces from top-level directory names.
Spaces tend to cause annoyances in a Unix-style shell environment. This change fixes that.
This commit is contained in:
114
08_Batnum/csharp/BatnumGame.cs
Normal file
114
08_Batnum/csharp/BatnumGame.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user