diff --git a/Qwirkle/Files/Game.xml b/Qwirkle/Files/Game.xml index 1683161..c55059d 100644 --- a/Qwirkle/Files/Game.xml +++ b/Qwirkle/Files/Game.xml @@ -1 +1 @@ -false1714000102030405060708090100110120130140150161011121314151617181911011111211311411511620212223242526272829210211212213214215216303132333435363738393103113123133143153164041424344454647484941041141241341441541650515253545556575859510511512513514515516606162636465666768696106116126136146156167071727374757677787971071171271371471571680818283848586878889810811812813814815816909192939495969798999109119129139149159161001011021031041051061071081091010101110121013101410151016110111112113114115116117118119111011111112111311141115111612012112212312412512612712812912101211121212131214121512161301311321331341351361371381391310131113121313131413151316 \ No newline at end of file +false1714001020304050607080901001101201301401501600111213141516171819110111112113114115116102122232425262728292102112122132142152162031323334353637383931031131231331431531630414243444546474849410411412413414415416405152535455565758595105115125135145155165061626364656667686961061161261361461561660717273747576777879710711712713714715716708182838485868788898108118128138148158168091929394959697989991091191291391491591690101102103104105106107108109101010111012101310141015101610011111211311411511611711811911101111111211131114111511161101211221231241251261271281291210121112121213121412151216120131132133134135136137138139131013111312131313141315131613 \ No newline at end of file diff --git a/Qwirkle/QwirkleClassLibrary/Boards/Cell.cs b/Qwirkle/QwirkleClassLibrary/Boards/Cell.cs index 1100117..e1f9c03 100644 --- a/Qwirkle/QwirkleClassLibrary/Boards/Cell.cs +++ b/Qwirkle/QwirkleClassLibrary/Boards/Cell.cs @@ -64,7 +64,7 @@ public class Cell : INotifyPropertyChanged /// True if the cell is empty, false if the cell contains a tile. public bool IsFree { - get { return Tile == null; } + get { return Tile! == null!; } } @@ -75,7 +75,7 @@ public class Cell : INotifyPropertyChanged /// True if added succefully (if the cell didn't already contain a tile), false if there already was a tile in this cell. public bool SetTile(Tile addedTile) { - if (Tile == null) + if (Tile! == null!) { Tile = addedTile; diff --git a/Qwirkle/QwirkleClassLibrary/Games/Game.cs b/Qwirkle/QwirkleClassLibrary/Games/Game.cs index 7290c56..615734b 100644 --- a/Qwirkle/QwirkleClassLibrary/Games/Game.cs +++ b/Qwirkle/QwirkleClassLibrary/Games/Game.cs @@ -7,7 +7,6 @@ using QwirkleClassLibrary.Events; using QwirkleClassLibrary.Players; using System.ComponentModel; using System.Runtime.CompilerServices; -using static System.Formats.Asn1.AsnWriter; namespace QwirkleClassLibrary.Games { @@ -167,7 +166,7 @@ namespace QwirkleClassLibrary.Games /// Returns the Board of the game /// /// Board - public Board? GetBoard() + public Board GetBoard() { return board; } @@ -365,8 +364,8 @@ namespace QwirkleClassLibrary.Games return false; } - if (!IsMoveCorrect(tile, x, y, board!)) return false; - if (board!.AddTileInCell(x, y, tile)) + if (!IsMoveCorrect(tile, x, y, board)) return false; + if (board.AddTileInCell(x, y, tile)) { AddCellUsed(board.GetCell(x, y)); return player.RemoveTileToPlayer(tile); @@ -477,12 +476,12 @@ namespace QwirkleClassLibrary.Games previousTilesFound = true; } - if (cellUsed.Contains(extendedCell)) + if (cellUsed.Contains(extendedCell!)) { previousTilesFound = true; } - if (extendedCell?.Tile == null) + if (extendedCell?.Tile! == null!) { break; } @@ -554,8 +553,43 @@ namespace QwirkleClassLibrary.Games return false; } + + /// + /// Check that there isn't any same tile on a said line when a tile is forming a line + /// + /// + /// + /// + /// + public static bool CheckTileInCompletedLines(Tile? t1, ref int nbTiles, ref List checkdoubles) + { + if (t1! != null!) + { + nbTiles++; + + if (checkdoubles.Any(t => t.CompareTo(t1) == 0)) + { + return false; + } + + checkdoubles.Add(t1); + } + + return true; + } - public bool CheckWrongCompletedLines(Tile tile, int x, int y, int dx, int dy, Board b, ref List checkdoubles) + /// + /// Check if the line is completed with the tile placed + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static bool CheckWrongCompletedLines(int x, int y, int dx, int dy, Board b, ref List checkdoubles) { int nbTiles = 1; @@ -564,67 +598,30 @@ namespace QwirkleClassLibrary.Games var extendedCell = b.GetCell(x + i * dx, y + i * dy); var extendedCell2 = b.GetCell(x - i * dx, y - i * dy); - if (extendedCell?.Tile == null && extendedCell2?.Tile == null) + if (extendedCell?.Tile! == null! && extendedCell2?.Tile! == null!) { break; } - - if (extendedCell?.Tile != null) - { - nbTiles++; - - foreach (var t in checkdoubles) - { - if (t.CompareTo(extendedCell.Tile) == 0) - { - return false; - } - } - - checkdoubles.Add(extendedCell.Tile); - } - - if (extendedCell2?.Tile != null) - { - nbTiles++; - foreach (var t in checkdoubles) - { - if (t.CompareTo(extendedCell2.Tile) == 0) - { - return false; - } - } - - checkdoubles.Add(extendedCell2.Tile); - } + if(!CheckTileInCompletedLines(extendedCell?.Tile, ref nbTiles, ref checkdoubles)) return false; + + if(!CheckTileInCompletedLines(extendedCell2?.Tile, ref nbTiles, ref checkdoubles)) return false; } return nbTiles <= 6; } - /// - /// Main method to check if the move the player is trying to make is correct - /// - /// - /// - /// - /// - /// bool public bool IsMoveCorrect(Tile t, int x, int y, Board b) { - bool previousTilesFound = false; - - var checkDoubles = new List(); - if (!b.HasOccupiedCase()) { return true; } - if (b.GetCell(x, y)!.Tile != null) + if (b.GetCell(x, y)!.Tile! != null!) { OnPlaceTile(new PlaceTileNotifiedEventArgs(t, " : Cell already used !")); + return false; } var surroundingCells = new List @@ -634,10 +631,26 @@ namespace QwirkleClassLibrary.Games b.GetCell(x, y + 1), b.GetCell(x, y - 1) }; + + if (surroundingCells.All(cell => cell?.Tile! == null!)) + { + OnPlaceTile(new PlaceTileNotifiedEventArgs(t, + " : You can't place a tile that isn't adjacent to another one !")); + return false; + } + + return IsTilePlacementCorrect(t, x, y, b, surroundingCells); + } + + public bool IsTilePlacementCorrect(Tile t, int x, int y, Board b, List surroundingCells) + { + bool previousTilesFound = false; + + var checkDoubles = new List(); foreach (var cell in surroundingCells) { - if (cell?.Tile == null) + if (cell?.Tile! == null!) { continue; } @@ -652,7 +665,6 @@ namespace QwirkleClassLibrary.Games if (cell.Tile.GetColor == t.GetColor && cell.Tile.GetShape == t.GetShape) { OnPlaceTile(new PlaceTileNotifiedEventArgs(t, " is already placed on the same line / column !")); - return false; } @@ -663,26 +675,17 @@ namespace QwirkleClassLibrary.Games { return false; } - - if (!CheckWrongCompletedLines(t, x, y, dx, dy, b, ref checkDoubles)) - { - OnPlaceTile(new PlaceTileNotifiedEventArgs(t, " : You can't complete this line ! (More than 6 tiles / same tiles on the line)")); - return false; - } - } - - if (!CheckTilesInLine(cellUsed, b, x, y)) - { + if (CheckWrongCompletedLines(x, y, dx, dy, b, ref checkDoubles)) continue; OnPlaceTile(new PlaceTileNotifiedEventArgs(t, - "isn't on the same line as the ones previously placed !")); + " : You can't complete this line ! (More than 6 tiles / same tiles on the line)")); return false; } - if (surroundingCells.All(cell => cell?.Tile == null)) + if (!CheckTilesInLine(cellUsed, b, x, y)) { OnPlaceTile(new PlaceTileNotifiedEventArgs(t, - " : You can't place a tile that isn't adjacent to another one !")); + "isn't on the same line as the ones previously placed !")); return false; } @@ -690,7 +693,6 @@ namespace QwirkleClassLibrary.Games OnPlaceTile(new PlaceTileNotifiedEventArgs(t, " : You must place your tile next / on the same line as the ones previously placed !")); return false; - } @@ -710,6 +712,9 @@ namespace QwirkleClassLibrary.Games int score = cellsPlayed.Count; int nbCellsInLine = cellsPlayed.Count; + int nbCellsInPerpLine = 1; + + var checkedCells = new List(); if (cellsPlayed.Count == 6) { @@ -740,9 +745,9 @@ namespace QwirkleClassLibrary.Games } score += cellsPlayed.Sum(cell => - CalculateAdjacentScore(cell, b, cellsPlayed, cellsX, cellsY, ref nbCellsInLine)); + CalculateAdjacentScore(cell, b, cellsPlayed, new Tuple(cellsX, cellsY), ref nbCellsInLine, ref nbCellsInPerpLine, ref checkedCells)); - if (nbCellsInLine == 6) + if (nbCellsInLine == 6 || nbCellsInPerpLine == 6) { score += 6; } @@ -762,12 +767,12 @@ namespace QwirkleClassLibrary.Games /// /// /// - /// - /// + /// + /// + /// /// /// int - public int CalculateAdjacentScore(Cell cell, Board b, ReadOnlyCollection cellsPlayed, int cellsX, - int cellsY, ref int nbCellsInLine) + public int CalculateAdjacentScore(Cell cell, Board b, ReadOnlyCollection cellsPlayed, Tuple orientation, ref int nbCellsInLine, ref int nbCellsInPerpLine, ref List checkedCells) { int score = 0; @@ -779,12 +784,10 @@ namespace QwirkleClassLibrary.Games b.GetCell(cell.GetX, cell.GetY - 1) }; - var checkedSurroundingCells = new List(); - foreach (var adjacentCell in surroundingCells) { - if (adjacentCell?.Tile == null || cellsPlayed.Contains(adjacentCell) || - checkedSurroundingCells.Contains(adjacentCell)) + if (adjacentCell?.Tile! == null! || cellsPlayed.Contains(adjacentCell) || + checkedCells.Contains(adjacentCell)) { continue; } @@ -792,10 +795,10 @@ namespace QwirkleClassLibrary.Games int dx = adjacentCell.GetX - cell.GetX; int dy = adjacentCell.GetY - cell.GetY; - score += CalculateLineScore(cellsPlayed, cell, new Tuple(dx, dy), b, - new Tuple(cellsX, cellsY), ref nbCellsInLine); + score += CalculateLineScore(cellsPlayed, cell, new Tuple(dx, dy), + new Tuple(orientation.Item1, orientation.Item2), ref nbCellsInLine, ref nbCellsInPerpLine, ref checkedCells); - checkedSurroundingCells.Add(adjacentCell); + checkedCells.Add(adjacentCell); } return score; @@ -807,20 +810,20 @@ namespace QwirkleClassLibrary.Games /// /// /// - /// /// /// + /// + /// /// int - public int CalculateLineScore(ReadOnlyCollection cellsPlayed, Cell cell, Tuple direction, - Board b, Tuple orientation, ref int nbCellsInLine) + public int CalculateLineScore(ReadOnlyCollection cellsPlayed, Cell cell, Tuple direction, Tuple orientation, ref int nbCellsInLine, ref int nbCellsInPerpLine, ref List checkedCells) { int score = 0; for (int i = 1; i < 6; i++) { - var extendedCell = b.GetCell(cell.GetX + i * direction.Item1, cell.GetY + i * direction.Item2); + var extendedCell = board.GetCell(cell.GetX + i * direction.Item1, cell.GetY + i * direction.Item2); - if (extendedCell?.Tile == null || cellsPlayed.Contains(extendedCell)) + if (extendedCell?.Tile! == null! || cellsPlayed.Contains(extendedCell) || checkedCells.Contains(extendedCell)) { break; } @@ -829,12 +832,17 @@ namespace QwirkleClassLibrary.Games { nbCellsInLine++; } + + if (direction.Item1 != 0 && orientation.Item1 != -1 || direction.Item2 != 0 && orientation.Item2 != -1) + { + nbCellsInPerpLine++; + } + checkedCells.Add(extendedCell); score++; } - if (direction.Item1 == 0 && orientation.Item1 == -1 && orientation.Item2 != -1 || - direction.Item2 == 0 && orientation.Item2 == -1 && orientation.Item1 != -1) + if (ShouldIncreaseScore(direction, orientation)) { score += 1; } @@ -842,7 +850,12 @@ namespace QwirkleClassLibrary.Games return score; } - + public static bool ShouldIncreaseScore(Tuple direction, Tuple orientation) + { + return direction.Item1 == 0 && orientation.Item1 == -1 && orientation.Item2 != -1 || + direction.Item2 == 0 && orientation.Item2 == -1 && orientation.Item1 != -1; + } + /// /// Returns the list of the positions of the players who still have tiles in their bag /// @@ -876,7 +889,7 @@ namespace QwirkleClassLibrary.Games { foreach (var t in players[t1].Tiles) { - for (int b = 0; b < board!.ReadCells.Count; b++) + for (int b = 0; b < board.ReadCells.Count; b++) { int x = board.ReadCells[b].GetX; int y = board.ReadCells[b].GetY; diff --git a/Qwirkle/QwirkleClassLibrary/Games/IPlayer.cs b/Qwirkle/QwirkleClassLibrary/Games/IPlayer.cs index 0a54e84..26ce37f 100644 --- a/Qwirkle/QwirkleClassLibrary/Games/IPlayer.cs +++ b/Qwirkle/QwirkleClassLibrary/Games/IPlayer.cs @@ -24,7 +24,9 @@ public interface IPlayer public int GetPlayerScore(Player player, ReadOnlyCollection cellsPlayed, Board b); - int CalculateAdjacentScore(Cell cell, Board b, ReadOnlyCollection cellsPlayed, int cellsX, int cellsY, ref int nbCellsInLine); + int CalculateAdjacentScore(Cell cell, Board b, ReadOnlyCollection cellsPlayed, Tuple orientation, + ref int nbCellsInLine, ref int nbCellsInPerpLine, ref List checkedCells); - int CalculateLineScore(ReadOnlyCollection cellsPlayed, Cell cell, Tuple direction, Board b, Tuple orientation, ref int nbCellsInLine); + int CalculateLineScore(ReadOnlyCollection cellsPlayed, Cell cell, Tuple direction, + Tuple orientation, ref int nbCellsInLine, ref int nbCellsInPerpLine, ref List checkedCells); } \ No newline at end of file diff --git a/Qwirkle/QwirkleClassLibrary/Tiles/Tile.cs b/Qwirkle/QwirkleClassLibrary/Tiles/Tile.cs index de68ec4..4c72ccf 100644 --- a/Qwirkle/QwirkleClassLibrary/Tiles/Tile.cs +++ b/Qwirkle/QwirkleClassLibrary/Tiles/Tile.cs @@ -41,19 +41,13 @@ namespace QwirkleClassLibrary.Tiles /// A getter for the shape of the Tile. /// /// The shape attribute of the Tile. - public Shape GetShape - { - get { return shape; } - } + public Shape GetShape => shape; /// /// A getter for the color of the Tile. /// /// The color attribute of the Tile. - public Color GetColor - { - get { return color; } - } + public Color GetColor => color; /// /// This method is used to override the ToString() method. It is simply a tool to facilitate the development. @@ -66,20 +60,66 @@ namespace QwirkleClassLibrary.Tiles public int CompareTo(object? obj) { - if (obj == null) return 1; + if (obj == null) + { + return 1; + } var otherTile = obj as Tile; - if (otherTile != null) + + if (color == otherTile!.color) { - if (color == otherTile.color) - { - return shape.CompareTo(otherTile.shape); - } + return shape.CompareTo(otherTile.shape); + } + + return color.CompareTo(otherTile.color); + + } - return color.CompareTo(otherTile.color); + public override bool Equals(object? obj) + { + if (obj == null || GetType() != obj.GetType()) + { + return false; } - throw new ArgumentException("Object is not a Tile"); + var otherTile = obj as Tile; + return color == otherTile!.color && shape == otherTile.shape; + } + + public override int GetHashCode() + { + return HashCode.Combine(color, shape); + } + + public static bool operator ==(Tile tile1, Tile tile2) + { + return EqualityComparer.Default.Equals(tile1, tile2); + } + + public static bool operator !=(Tile tile1, Tile tile2) + { + return !(tile1 == tile2); + } + + public static bool operator <(Tile tile1, Tile tile2) + { + return tile1.CompareTo(tile2) < 0; + } + + public static bool operator >(Tile tile1, Tile tile2) + { + return tile1.CompareTo(tile2) > 0; + } + + public static bool operator <=(Tile tile1, Tile tile2) + { + return tile1.CompareTo(tile2) <= 0; + } + + public static bool operator >=(Tile tile1, Tile tile2) + { + return tile1.CompareTo(tile2) >= 0; } } } \ No newline at end of file diff --git a/Qwirkle/QwirkleViews/Pages/Gameboard.xaml b/Qwirkle/QwirkleViews/Pages/Gameboard.xaml index 1413b28..d3627eb 100644 --- a/Qwirkle/QwirkleViews/Pages/Gameboard.xaml +++ b/Qwirkle/QwirkleViews/Pages/Gameboard.xaml @@ -74,7 +74,7 @@ ToolTipProperties.Text="Click here to exit ;)" Style="{StaticResource GameButton}" /> - + @@ -98,7 +98,7 @@ - + @@ -119,7 +119,7 @@ - + @@ -140,7 +140,7 @@ - + diff --git a/Qwirkle/QwirkleViews/Pages/SetPlayers.xaml.cs b/Qwirkle/QwirkleViews/Pages/SetPlayers.xaml.cs index b029414..7b0226b 100644 --- a/Qwirkle/QwirkleViews/Pages/SetPlayers.xaml.cs +++ b/Qwirkle/QwirkleViews/Pages/SetPlayers.xaml.cs @@ -54,7 +54,7 @@ public partial class SetPlayers : ContentPage game.GiveTilesToPlayers(); game.SetNextPlayer(); Shell.Current.GoToAsync("Gameboard"); - //Navigation.PushAsync(new Gameboard()); + } diff --git a/Qwirkle/QwirkleViews/PopUpEndGame.xaml.cs b/Qwirkle/QwirkleViews/PopUpEndGame.xaml.cs index fe153d9..34288e2 100644 --- a/Qwirkle/QwirkleViews/PopUpEndGame.xaml.cs +++ b/Qwirkle/QwirkleViews/PopUpEndGame.xaml.cs @@ -1,4 +1,5 @@ using CommunityToolkit.Maui.Views; +using Microsoft.Maui.Controls; using QwirkleClassLibrary.Games; using System.Collections.ObjectModel; @@ -32,7 +33,8 @@ public partial class PopUpEndGame : Popup public async void OnButtonNextClick(object sender, EventArgs e) { - await CloseAsync(); + Close(); + await Shell.Current.GoToAsync("MainPage"); } } diff --git a/Qwirkle/QwirkleViews/QwirkleViews.csproj b/Qwirkle/QwirkleViews/QwirkleViews.csproj index f2f4f2a..3f682eb 100644 --- a/Qwirkle/QwirkleViews/QwirkleViews.csproj +++ b/Qwirkle/QwirkleViews/QwirkleViews.csproj @@ -1,8 +1,7 @@  - net8.0-android;net8.0-ios;net8.0-maccatalyst - $(TargetFrameworks);net8.0-windows10.0.19041.0 + net8.0-windows10.0.19041.0 @@ -61,15 +60,15 @@ - + - + - + diff --git a/Qwirkle/QwirkleViews/Resources/Raw/f1.mp3 b/Qwirkle/QwirkleViews/Resources/Raw/f1.mp3 deleted file mode 100644 index e4e3d9a..0000000 Binary files a/Qwirkle/QwirkleViews/Resources/Raw/f1.mp3 and /dev/null differ diff --git a/Qwirkle/TestBase/TestGame.cs b/Qwirkle/TestBase/TestGame.cs index d479be3..1775ecc 100644 --- a/Qwirkle/TestBase/TestGame.cs +++ b/Qwirkle/TestBase/TestGame.cs @@ -287,25 +287,6 @@ public class TestGame Assert.False(game.PlaceTile(game.GetPlayingPlayer(), game.PlayerList[game.GetPlayingPlayerPosition()].Tiles[0], -5, 1)); } - // [Fact] - // public void Test_DrawTile() - // { - // Game game = new Game(); - // game.AddPlayerInGame("Test1"); - // game.AddPlayerInGame(playerstest); - // - // game.StartGame(); - // game.SetNextPlayer(); - // - // Assert.True(game.DrawTiles(game.GetPlayingPlayer())); - // - // /*test*/ - // TileBag bag = new TileBag(0); - // Assert.False(game.DrawTiles(game.GetPlayingPlayer())); - // return; - // - // } - [Theory] [InlineData(true)] [InlineData(false)] @@ -342,6 +323,48 @@ public class TestGame Assert.Equal(p, events.Player); } + [Fact] + public void Test_IsTilePlacementCorrect() + { + var game = new Game(); + var board = new Board(17, 14); + var tile = new Tile(Shape.Club, Color.Red); + + board.AddTileInCell(0, 1, new Tile(Shape.Club, Color.Blue)); + + var x = 1; + var y = 1; + + var surroundingCells = new List + { + board.GetCell(x + 1, y), + board.GetCell(x - 1, y), + board.GetCell(x, y + 1), + board.GetCell(x, y - 1) + }; + + bool result = game.IsTilePlacementCorrect(tile, x, y, board, surroundingCells); + + Assert.True(result); + } + + [Fact] + public void Test_IsMoveCorrect() + { + var game = new Game(); + var board = new Board(17, 14); + var tile = new Tile(Shape.Club, Color.Red); + + board.AddTileInCell(0, 1, new Tile(Shape.Club, Color.Blue)); + + var x = 2; + var y = 1; + + bool result = game.IsMoveCorrect(tile, x, y, board); + + Assert.False(result); + } + [Fact] public void Test_IsMoveCorrectSixLine() { @@ -381,6 +404,41 @@ public class TestGame } + [Fact] + public void Test_CheckTileInCompletedLines() + { + int nbTiles = 0; + var checkdoubles = new List() + { + new(Shape.Club, Color.Blue), + new(Shape.Club, Color.Red), + new(Shape.Club, Color.Green), + }; + + var t1 = new Tile(Shape.Club, Color.Green); + + Assert.False(Game.CheckTileInCompletedLines(t1, ref nbTiles, ref checkdoubles)); + } + + [Fact] + public void Test_CheckWrongCompletedLines() + { + var board = new Board(17, 14); + var checkDoubles = new List(); + int x = 4, y = 1, dx = 1, dy = 0; + + board.AddTileInCell(1, 1, new Tile(Shape.Club, Color.Red)); + board.AddTileInCell(2, 1, new Tile(Shape.Square, Color.Red)); + board.AddTileInCell(3, 1, new Tile(Shape.Star, Color.Red)); + board.AddTileInCell(5, 1, new Tile(Shape.Round, Color.Red)); + board.AddTileInCell(6, 1, new Tile(Shape.Shuriken, Color.Red)); + board.AddTileInCell(7, 1, new Tile(Shape.Rhombus, Color.Red)); + + bool result = Game.CheckWrongCompletedLines(x, y, dx, dy, board, ref checkDoubles); + + Assert.False(result); + } + [Theory] [InlineData(3, 1, 4, 1, 5, 1, 5)] [InlineData(2, 2, 3, 2, 4, 2, 5)] @@ -389,7 +447,7 @@ public class TestGame { var game = new Game(); var player = new Player("TestPlayer"); - var board = new Board(8, 8); + var board = game.GetBoard(); board.AddTileInCell(1, 1, new Tile(Shape.Club, Color.Red)); board.AddTileInCell(2, 1, new Tile(Shape.Square, Color.Red)); @@ -413,6 +471,14 @@ public class TestGame Assert.Equal(expectedScore, score); } + + [Theory] + [InlineData(0, -1, -1, 6)] + [InlineData(1, 0, 4, -1)] + public void Test_ShouldIncreaseScore(int dx, int dy, int cellsX, int cellsY) + { + Assert.True(Game.ShouldIncreaseScore(new Tuple(dx, dy), new Tuple(cellsX, cellsY))); + } [Fact] public void Test_EndOfGame()