|
|
|
@ -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
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns>Board</returns>
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Check that there isn't any same tile on a said line when a tile is forming a line
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="t1"></param>
|
|
|
|
|
/// <param name="nbTiles"></param>
|
|
|
|
|
/// <param name="checkdoubles"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public static bool CheckTileInCompletedLines(Tile? t1, ref int nbTiles, ref List<Tile> 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<Tile> checkdoubles)
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Check if the line is completed with the tile placed
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="tile"></param>
|
|
|
|
|
/// <param name="x"></param>
|
|
|
|
|
/// <param name="y"></param>
|
|
|
|
|
/// <param name="dx"></param>
|
|
|
|
|
/// <param name="dy"></param>
|
|
|
|
|
/// <param name="b"></param>
|
|
|
|
|
/// <param name="checkdoubles"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public static bool CheckWrongCompletedLines(int x, int y, int dx, int dy, Board b, ref List<Tile> 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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Main method to check if the move the player is trying to make is correct
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="t"></param>
|
|
|
|
|
/// <param name="x"></param>
|
|
|
|
|
/// <param name="y"></param>
|
|
|
|
|
/// <param name="b"></param>
|
|
|
|
|
/// <returns>bool</returns>
|
|
|
|
|
public bool IsMoveCorrect(Tile t, int x, int y, Board b)
|
|
|
|
|
{
|
|
|
|
|
bool previousTilesFound = false;
|
|
|
|
|
|
|
|
|
|
var checkDoubles = new List<Tile>();
|
|
|
|
|
|
|
|
|
|
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<Cell?>
|
|
|
|
@ -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<Cell?> surroundingCells)
|
|
|
|
|
{
|
|
|
|
|
bool previousTilesFound = false;
|
|
|
|
|
|
|
|
|
|
var checkDoubles = new List<Tile>();
|
|
|
|
|
|
|
|
|
|
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<Cell>();
|
|
|
|
|
|
|
|
|
|
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<int, int>(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
|
|
|
|
|
/// <param name="cell"></param>
|
|
|
|
|
/// <param name="b"></param>
|
|
|
|
|
/// <param name="cellsPlayed"></param>
|
|
|
|
|
/// <param name="cellsX"></param>
|
|
|
|
|
/// <param name="cellsY"></param>
|
|
|
|
|
/// <param name="orientation"></param>
|
|
|
|
|
/// <param name="nbCellsInPerpLine"></param>
|
|
|
|
|
/// <param name="checkedCells"></param>
|
|
|
|
|
/// <param name="nbCellsInLine"></param>
|
|
|
|
|
/// <returns>int</returns>
|
|
|
|
|
public int CalculateAdjacentScore(Cell cell, Board b, ReadOnlyCollection<Cell> cellsPlayed, int cellsX,
|
|
|
|
|
int cellsY, ref int nbCellsInLine)
|
|
|
|
|
public int CalculateAdjacentScore(Cell cell, Board b, ReadOnlyCollection<Cell> cellsPlayed, Tuple<int, int> orientation, ref int nbCellsInLine, ref int nbCellsInPerpLine, ref List<Cell> checkedCells)
|
|
|
|
|
{
|
|
|
|
|
int score = 0;
|
|
|
|
|
|
|
|
|
@ -779,12 +784,10 @@ namespace QwirkleClassLibrary.Games
|
|
|
|
|
b.GetCell(cell.GetX, cell.GetY - 1)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
var checkedSurroundingCells = new List<Cell>();
|
|
|
|
|
|
|
|
|
|
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<int, int>(dx, dy), b,
|
|
|
|
|
new Tuple<int, int>(cellsX, cellsY), ref nbCellsInLine);
|
|
|
|
|
score += CalculateLineScore(cellsPlayed, cell, new Tuple<int, int>(dx, dy),
|
|
|
|
|
new Tuple<int, int>(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
|
|
|
|
|
/// <param name="cellsPlayed"></param>
|
|
|
|
|
/// <param name="cell"></param>
|
|
|
|
|
/// <param name="direction"></param>
|
|
|
|
|
/// <param name="b"></param>
|
|
|
|
|
/// <param name="orientation"></param>
|
|
|
|
|
/// <param name="nbCellsInLine"></param>
|
|
|
|
|
/// <param name="nbCellsInPerpLine"></param>
|
|
|
|
|
/// <param name="checkedCells"></param>
|
|
|
|
|
/// <returns>int</returns>
|
|
|
|
|
public int CalculateLineScore(ReadOnlyCollection<Cell> cellsPlayed, Cell cell, Tuple<int, int> direction,
|
|
|
|
|
Board b, Tuple<int, int> orientation, ref int nbCellsInLine)
|
|
|
|
|
public int CalculateLineScore(ReadOnlyCollection<Cell> cellsPlayed, Cell cell, Tuple<int, int> direction, Tuple<int, int> orientation, ref int nbCellsInLine, ref int nbCellsInPerpLine, ref List<Cell> 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<int, int> direction, Tuple<int, int> orientation)
|
|
|
|
|
{
|
|
|
|
|
return direction.Item1 == 0 && orientation.Item1 == -1 && orientation.Item2 != -1 ||
|
|
|
|
|
direction.Item2 == 0 && orientation.Item2 == -1 && orientation.Item1 != -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Returns the list of the positions of the players who still have tiles in their bag
|
|
|
|
|
/// </summary>
|
|
|
|
@ -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;
|
|
|
|
|