🐛 fix-#87 #88

Merged
alexis.drai merged 4 commits from fix-#87 into main 3 years ago

@ -1,209 +1,219 @@
using Model.Dice; using Model.Dice;
using Model.Dice.Faces; using Model.Dice.Faces;
using Model.Players; using Model.Players;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Diagnostics;
using System.Numerics; using System.Linq;
using System.Text; using System.Numerics;
using System.Text;
namespace Model.Games
{ namespace Model.Games
public class Game {
{ public class Game
/// <summary> {
/// the name of the game 😎 /// <summary>
/// </summary> /// the name of the game 😎
public string Name /// </summary>
{ public string Name
get {
{ get
return name; {
} return name;
set // GameRunner will need to take care of forbidding }
// (or allowing) having two Games with the same name etc. set // GameRunner will need to take care of forbidding
{ // (or allowing) having two Games with the same name etc.
if (string.IsNullOrWhiteSpace(value)) {
{ if (string.IsNullOrWhiteSpace(value))
throw new ArgumentException("param should not be null or blank", nameof(value)); {
} throw new ArgumentException("param should not be null or blank", nameof(value));
name = value; }
} name = value;
} }
private string name; }
private string name;
/// <summary>
/// references the position in list of the current player, for a given game. /// <summary>
/// </summary> /// references the position in list of the current player, for a given game.
private int nextIndex; /// </summary>
private int nextIndex;
/// <summary>
/// the turns that have been done so far /// <summary>
/// </summary> /// the turns that have been done so far
private readonly List<Turn> turns; /// </summary>
private readonly List<Turn> turns;
/// </summary>
/// get a READ ONLY enumerable of all turns belonging to this game /// </summary>
/// </summary> /// get a READ ONLY enumerable of all turns belonging to this game
/// <returns>a readonly enumerable of all this game's turns</returns> /// </summary>
public IEnumerable<Turn> GetHistory() => turns.AsEnumerable(); /// <returns>a readonly enumerable of all this game's turns</returns>
public IEnumerable<Turn> GetHistory() => turns.AsEnumerable();
/// <summary>
/// the game's player manager, doing CRUD on players and switching whose turn it is /// <summary>
/// </summary> /// the game's player manager, doing CRUD on players and switching whose turn it is
private readonly IManager<Player> playerManager; /// </summary>
private readonly IManager<Player> playerManager;
/// <summary>
/// the group of dice used for this game /// <summary>
/// </summary> /// the group of dice used for this game
public IEnumerable<AbstractDie<AbstractDieFace>> Dice => dice; /// </summary>
private readonly IEnumerable<AbstractDie<AbstractDieFace>> dice; public IEnumerable<AbstractDie<AbstractDieFace>> Dice => dice;
private readonly IEnumerable<AbstractDie<AbstractDieFace>> dice;
/// <summary>
/// constructs a Game with its own history of Turns. /// <summary>
/// If <paramref name="turns"/> is null, starts a new history /// constructs a Game with its own history of Turns.
/// </summary> /// If <paramref name="turns"/> is null, starts a new history
/// <param name="name">the name of the game 😎</param> /// </summary>
/// <param name="turns">the turns that have been done so far</param> /// <param name="name">the name of the game 😎</param>
/// <param name="playerManager">the game's player manager, doing CRUD on players and switching whose turn it is</param> /// <param name="turns">the turns that have been done so far</param>
/// <param name="favGroup">the group of dice used for this game</param> /// <param name="playerManager">the game's player manager, doing CRUD on players and switching whose turn it is</param>
public Game(string name, IManager<Player> playerManager, IEnumerable<AbstractDie<AbstractDieFace>> dice, IEnumerable<Turn> turns) /// <param name="favGroup">the group of dice used for this game</param>
{ public Game(string name, IManager<Player> playerManager, IEnumerable<AbstractDie<AbstractDieFace>> dice, IEnumerable<Turn> turns)
Name = name; {
this.turns = turns is null ? new List<Turn>() : turns.ToList(); Name = name;
this.playerManager = playerManager; this.turns = turns is null ? new List<Turn>() : turns.ToList();
this.dice = dice; this.playerManager = playerManager;
this.nextIndex = 0; this.dice = dice;
} this.nextIndex = 0;
}
/// <summary>
/// constructs a Game with no history of turns. /// <summary>
/// </summary> /// constructs a Game with no history of turns.
/// <param name="name">the name of the game 😎</param> /// </summary>
/// <param name="playerManager">the game's player manager, doing CRUD on players and switching whose turn it is</param> /// <param name="name">the name of the game 😎</param>
/// <param name="favGroup">the group of dice used for this game</param> /// <param name="playerManager">the game's player manager, doing CRUD on players and switching whose turn it is</param>
public Game(string name, IManager<Player> playerManager, IEnumerable<AbstractDie<AbstractDieFace>> dice) /// <param name="favGroup">the group of dice used for this game</param>
: this(name, playerManager, dice, null) public Game(string name, IManager<Player> playerManager, IEnumerable<AbstractDie<AbstractDieFace>> dice)
{ } : this(name, playerManager, dice, null)
{ }
/// <summary>
/// performs a Turn, marks this Game as "started", and logs that Turn /// <summary>
/// </summary> /// performs a Turn, marks this Game as "started", and logs that Turn
/// <param name="player">the player whose turn it is</param> /// </summary>
public void PerformTurn(Player player) /// <param name="player">the player whose turn it is</param>
{ public void PerformTurn(Player player)
Turn turn = Turn.CreateWithDefaultTime( {
player, Turn turn = Turn.CreateWithDefaultTime(
ThrowAll() player,
); ThrowAll()
turns.Add(turn); );
} AddTurn(turn);
}
/// <summary>
/// finds and returns the player whose turn it is
/// </summary> private void AddTurn(Turn turn)
/// <returns></returns> {
/// <exception cref="Exception"></exception> if (!(turns.Contains(turn)))
public Player GetWhoPlaysNow() {
{ turns.Add(turn);
if (!playerManager.GetAll().Any()) }
{ }
throw new MemberAccessException("you are exploring an empty collection\nthis should not have happened");
} /// <summary>
return playerManager.GetAll().ElementAt(nextIndex); /// finds and returns the player whose turn it is
} /// </summary>
/// <returns></returns>
/// <summary> /// <exception cref="Exception"></exception>
/// this feels very dirty public Player GetWhoPlaysNow()
/// </summary> {
/// <param name="current">the current player</param> if (!playerManager.GetAll().Any())
/// <exception cref="MemberAccessException"></exception> {
/// <exception cref="ArgumentNullException"></exception> throw new MemberAccessException("you are exploring an empty collection\nthis should not have happened");
/// <exception cref="ArgumentException"></exception> }
public void PrepareNextPlayer(Player current) return playerManager.GetAll().ElementAt(nextIndex);
{ }
if (!playerManager.GetAll().Any())
{ /// <summary>
throw new MemberAccessException("you are exploring an empty collection\nthis should not have happened"); /// this feels very dirty
} /// </summary>
if (current == null) /// <param name="current">the current player</param>
{ /// <exception cref="MemberAccessException"></exception>
throw new ArgumentNullException(nameof(current), "param should not be null"); /// <exception cref="ArgumentNullException"></exception>
} /// <exception cref="ArgumentException"></exception>
if (!playerManager.GetAll().Contains(current)) public void PrepareNextPlayer(Player current)
{ {
throw new ArgumentException("param could not be found in this collection\n did you forget to add it?", nameof(current)); if (!playerManager.GetAll().Any())
} {
if (playerManager.GetAll().Last() == current) throw new MemberAccessException("you are exploring an empty collection\nthis should not have happened");
{ }
// if we've reached the last player, we need the index to loop back around if (current == null)
nextIndex = 0; {
} throw new ArgumentNullException(nameof(current), "param should not be null");
else }
{ if (!playerManager.GetAll().Contains(current))
// else we can just move up by one from the current index {
nextIndex++; throw new ArgumentException("param could not be found in this collection\n did you forget to add it?", nameof(current));
} }
} if (playerManager.GetAll().Last() == current)
{
/// <summary> // if we've reached the last player, we need the index to loop back around
/// throws all the Dice in FavGroup and returns a list of their Faces nextIndex = 0;
/// </summary> }
/// <returns>list of AbstractDieFaces after a throw</returns> else
private Dictionary<AbstractDie<AbstractDieFace>, AbstractDieFace> ThrowAll() {
{ // else we can just move up by one from the current index
Dictionary<AbstractDie<AbstractDieFace>, AbstractDieFace> faces = new(); nextIndex++;
foreach (AbstractDie<AbstractDieFace> die in dice) }
{ }
faces.Add(die, die.GetRandomFace());
} /// <summary>
return faces; /// throws all the Dice in FavGroup and returns a list of their Faces
} /// </summary>
/// <returns>list of AbstractDieFaces after a throw</returns>
public Player AddPlayerToGame(Player player) private Dictionary<AbstractDie<AbstractDieFace>, AbstractDieFace> ThrowAll()
{ {
return playerManager.Add(player); Dictionary<AbstractDie<AbstractDieFace>, AbstractDieFace> faces = new();
} foreach (AbstractDie<AbstractDieFace> die in dice)
{
public IEnumerable<Player> GetPlayersFromGame() faces.Add(die, die.GetRandomFace());
{ }
return playerManager.GetAll(); return faces;
} }
public Player UpdatePlayerInGame(Player oldPlayer, Player newPlayer) public Player AddPlayerToGame(Player player)
{ {
return playerManager.Update(oldPlayer, newPlayer); return playerManager.Add(player);
} }
public void RemovePlayerFromGame(Player player) public IEnumerable<Player> GetPlayersFromGame()
{ {
playerManager.Remove(player); return playerManager.GetAll();
} }
/// <summary> public Player UpdatePlayerInGame(Player oldPlayer, Player newPlayer)
/// represents a Game in string format {
/// </summary> return playerManager.Update(oldPlayer, newPlayer);
/// <returns>a Game in string format</returns> }
public override string ToString()
{ public void RemovePlayerFromGame(Player player)
StringBuilder sb = new(); {
sb.Append($"Game: {Name}"); playerManager.Remove(player);
}
sb.Append("\nPlayers:");
foreach (Player player in GetPlayersFromGame()) /// <summary>
{ /// represents a Game in string format
sb.Append($" {player.ToString()}"); /// </summary>
} /// <returns>a Game in string format</returns>
public override string ToString()
sb.Append($"\nNext: {GetWhoPlaysNow()}"); {
StringBuilder sb = new();
sb.Append("\nLog:\n"); sb.Append($"Game: {Name}");
foreach (Turn turn in this.turns)
{ sb.Append("\nPlayers:");
sb.Append($"\t{turn.ToString()}\n"); foreach (Player player in GetPlayersFromGame())
} {
sb.Append($" {player.ToString()}");
return sb.ToString(); }
}
} sb.Append($"\nNext: {GetWhoPlaysNow()}");
}
sb.Append("\nLog:\n");
foreach (Turn turn in this.turns)
{
sb.Append($"\t{turn.ToString()}\n");
}
return sb.ToString();
}
}
}

@ -17,7 +17,7 @@ namespace Model.Games
/// Two turns are equal if they are litterally the same instance in RAM /// Two turns are equal if they are litterally the same instance in RAM
/// (default behaviors Equals() and GetHashCode()) /// (default behaviors Equals() and GetHashCode())
/// </summary> /// </summary>
public class Turn public sealed class Turn : IEquatable<Turn>
{ {
/// <summary> /// <summary>
@ -115,5 +115,27 @@ namespace Model.Games
return sb.ToString(); return sb.ToString();
} }
public bool Equals(Turn other)
{
return Player.Equals(other.Player)
&& When.Equals(other.When)
&& DiceNFaces.SequenceEqual(other.DiceNFaces);
}
public override bool Equals(object obj)
{
if (obj is not Turn)
{
return false;
}
return Equals(obj as Turn);
}
public override int GetHashCode()
{
return HashCode.Combine(Player, When, DiceNFaces);
}
} }
} }

@ -149,9 +149,6 @@ namespace Tests.Model_UTs
int n = 5; int n = 5;
IEnumerable<Player> players = game.GetPlayersFromGame();
Debug.WriteLine(players);
Player currentPlayer; Player currentPlayer;
for (int i = 0; i < n; i++) for (int i = 0; i < n; i++)
{ {

@ -79,16 +79,6 @@ namespace Tests.Model_UTs
Assert.Equal(expected, actual); Assert.Equal(expected, actual);
} }
class Point
{
public int X { get; set; }
public int Y { get; set; }
public Point(int x, int y)
{
X = x; Y = y;
}
}
[Fact] [Fact]
public void TestEqualsFalseIfNotPlayer() public void TestEqualsFalseIfNotPlayer()
{ {

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Tests.Model_UTs
{
public class Point
{
public int X { get; private set; }
public int Y { get; private set; }
public Point(int x, int y)
{
X = x; Y = y;
}
}
}

@ -13,7 +13,9 @@ namespace Tests.Model_UTs
public class TurnTest public class TurnTest
{ {
private readonly Dictionary<AbstractDie<AbstractDieFace>, AbstractDieFace> DICE_N_FACES; private readonly Dictionary<AbstractDie<AbstractDieFace>, AbstractDieFace> DICE_N_FACES_1;
private readonly Dictionary<AbstractDie<AbstractDieFace>, AbstractDieFace> DICE_N_FACES_2;
private static readonly AbstractDieFace FACE_ONE = new NumberDieFace(1); private static readonly AbstractDieFace FACE_ONE = new NumberDieFace(1);
private static readonly AbstractDieFace FACE_TWO = new NumberDieFace(12); private static readonly AbstractDieFace FACE_TWO = new NumberDieFace(12);
private static readonly AbstractDieFace FACE_THREE = new ImageDieFace(54); private static readonly AbstractDieFace FACE_THREE = new ImageDieFace(54);
@ -57,13 +59,19 @@ namespace Tests.Model_UTs
public TurnTest() public TurnTest()
{ {
DICE_N_FACES = new() DICE_N_FACES_1 = new()
{ {
{ NUM1, FACE_ONE }, { NUM1, FACE_ONE },
{ NUM2, FACE_TWO }, { NUM2, FACE_TWO },
{ IMG1, FACE_THREE }, { IMG1, FACE_THREE },
{ CLR1, FACE_FOUR } { CLR1, FACE_FOUR }
}; };
DICE_N_FACES_2 = new()
{
{ NUM1, FACE_TWO },
{ IMG1, FACE_THREE },
{ CLR1, FACE_FOUR }
};
} }
@ -77,7 +85,7 @@ namespace Tests.Model_UTs
Assert.NotEqual(DateTimeKind.Utc, dateTime.Kind); Assert.NotEqual(DateTimeKind.Utc, dateTime.Kind);
// Act // Act
Turn turn = Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES); Turn turn = Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES_1);
// Assert // Assert
Assert.Equal(DateTimeKind.Utc, turn.When.Kind); Assert.Equal(DateTimeKind.Utc, turn.When.Kind);
@ -95,7 +103,7 @@ namespace Tests.Model_UTs
Assert.Equal(DateTimeKind.Utc, dateTime.Kind); Assert.Equal(DateTimeKind.Utc, dateTime.Kind);
// Act // Act
Turn turn = Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES); Turn turn = Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES_1);
// Assert // Assert
Assert.Equal(DateTimeKind.Utc, turn.When.Kind); Assert.Equal(DateTimeKind.Utc, turn.When.Kind);
@ -110,7 +118,7 @@ namespace Tests.Model_UTs
DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc); DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc);
// Act // Act
void action() => Turn.CreateWithSpecifiedTime(dateTime, null, DICE_N_FACES); void action() => Turn.CreateWithSpecifiedTime(dateTime, null, DICE_N_FACES_1);
// Assert // Assert
Assert.Throws<ArgumentNullException>(action); Assert.Throws<ArgumentNullException>(action);
@ -137,10 +145,10 @@ namespace Tests.Model_UTs
// Arrange // Arrange
DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc); DateTime dateTime = new(year: 2018, month: 06, day: 15, hour: 16, minute: 30, second: 0, kind: DateTimeKind.Utc);
Player player = new("Chucky"); Player player = new("Chucky");
DICE_N_FACES.Clear(); DICE_N_FACES_1.Clear();
// Act // Act
void action() => Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES); void action() => Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES_1);
// Assert // Assert
Assert.Throws<ArgumentException>(action); Assert.Throws<ArgumentException>(action);
@ -155,7 +163,7 @@ namespace Tests.Model_UTs
Player player = new("Chloe"); Player player = new("Chloe");
// Act // Act
Turn turn = Turn.CreateWithDefaultTime(player, DICE_N_FACES); Turn turn = Turn.CreateWithDefaultTime(player, DICE_N_FACES_1);
// Assert // Assert
Assert.Equal(DateTimeKind.Utc, turn.When.Kind); Assert.Equal(DateTimeKind.Utc, turn.When.Kind);
@ -178,7 +186,7 @@ namespace Tests.Model_UTs
+ FACE_THREE.ToString() + " " + FACE_THREE.ToString() + " "
+ FACE_FOUR.ToString(); + FACE_FOUR.ToString();
Turn turn = Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES); Turn turn = Turn.CreateWithSpecifiedTime(dateTime, player, DICE_N_FACES_1);
// Act // Act
string actual = turn.ToString(); string actual = turn.ToString();
@ -195,11 +203,120 @@ namespace Tests.Model_UTs
Player player = new("Erika"); Player player = new("Erika");
// Act // Act
Turn turn = Turn.CreateWithDefaultTime(player, DICE_N_FACES); Turn turn = Turn.CreateWithDefaultTime(player, DICE_N_FACES_1);
IEnumerable<KeyValuePair<AbstractDie<AbstractDieFace>, AbstractDieFace>> expected = DICE_N_FACES.AsEnumerable(); IEnumerable<KeyValuePair<AbstractDie<AbstractDieFace>, AbstractDieFace>> expected = DICE_N_FACES_1.AsEnumerable();
// Assert // Assert
Assert.Equal(expected, turn.DiceNFaces); Assert.Equal(expected, turn.DiceNFaces);
}
[Fact]
public void TestEqualsFalseIfNotTurn()
{
// Arrange
Point point;
Turn turn;
Player player = new("Freddie");
// Act
point = new(1, 2);
turn = Turn.CreateWithDefaultTime(player, DICE_N_FACES_1);
// Assert
Assert.False(point.Equals(turn));
Assert.False(point.GetHashCode().Equals(turn.GetHashCode()));
Assert.False(turn.Equals(point));
Assert.False(turn.GetHashCode().Equals(point.GetHashCode()));
}
[Fact]
public void TestGoesThruToSecondMethodIfObjIsTypeTurn()
{
// Arrange
Object t1;
Turn t2;
Player player1 = new Player("Marvin");
Player player2 = new Player("Noah");
// Act
t1 = Turn.CreateWithDefaultTime(player1, DICE_N_FACES_1);
t2 = Turn.CreateWithDefaultTime(player2, DICE_N_FACES_2);
// Assert
Assert.False(t1.Equals(t2));
Assert.False(t1.GetHashCode().Equals(t2.GetHashCode()));
Assert.False(t2.Equals(t1));
Assert.False(t2.GetHashCode().Equals(t1.GetHashCode()));
}
[Fact]
public void TestEqualsFalseIfNotSamePlayer()
{
// Arrange
Player player1= new("Panama");
Player player2= new("Clyde");
// Act
Turn t1 = Turn.CreateWithDefaultTime(player1, DICE_N_FACES_2);
Turn t2 = Turn.CreateWithDefaultTime(player2, DICE_N_FACES_2);
// Assert
Assert.False(t1.Equals(t2));
Assert.False(t1.GetHashCode().Equals(t2.GetHashCode()));
Assert.False(t2.Equals(t1));
Assert.False(t2.GetHashCode().Equals(t1.GetHashCode()));
}
[Fact]
public void TestEqualsFalseIfNotSameTime()
{
// Arrange
Player player = new("Oscar");
// Act
Turn t1 = Turn.CreateWithSpecifiedTime(new DateTime(1994, 07, 10), player, DICE_N_FACES_1);
Turn t2 = Turn.CreateWithSpecifiedTime(new DateTime(1991, 08, 20), player, DICE_N_FACES_1);
// Assert
Assert.False(t1.Equals(t2));
Assert.False(t1.GetHashCode().Equals(t2.GetHashCode()));
Assert.False(t2.Equals(t1));
Assert.False(t2.GetHashCode().Equals(t1.GetHashCode()));
}
[Fact]
public void TestEqualsFalseIfNotSameDiceNFaces()
{
// Arrange
Player player = new("Django");
// Act
Turn t1 = Turn.CreateWithDefaultTime(player, DICE_N_FACES_1);
Turn t2 = Turn.CreateWithDefaultTime(player, DICE_N_FACES_2);
// Assert
Assert.False(t1.Equals(t2));
Assert.False(t1.GetHashCode().Equals(t2.GetHashCode()));
Assert.False(t2.Equals(t1));
Assert.False(t2.GetHashCode().Equals(t1.GetHashCode()));
}
[Fact]
public void TestEqualsTrueIfExactlySameProperties()
{
// Arrange
Player player = new("Elyse");
// Act
Turn t1 = Turn.CreateWithSpecifiedTime(new DateTime(1990, 04, 29), player, DICE_N_FACES_1);
Turn t2 = Turn.CreateWithSpecifiedTime(new DateTime(1990, 04, 29), player, DICE_N_FACES_1);
// Assert
Assert.True(t1.Equals(t2));
Assert.True(t1.GetHashCode().Equals(t2.GetHashCode()));
Assert.True(t2.Equals(t1));
Assert.True(t2.GetHashCode().Equals(t1.GetHashCode()));
} }
} }
} }

Loading…
Cancel
Save