-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
v0.10.2 QLessDice - continuing route to functional programming style
Breaking changes on Place...() methods
- Loading branch information
Showing
6 changed files
with
214 additions
and
179 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
namespace Smab.DiceAndTiles.Games.QLess; | ||
|
||
public class DiceCollections | ||
{ | ||
public static readonly List<LetterDie> DefaultDiceSet = | ||
[ | ||
new([ "M", "M", "L", "L", "B", "Y" ]), | ||
new([ "V", "F", "G", "K", "P", "P" ]), | ||
new([ "H", "H", "N", "N", "R", "R" ]), | ||
new([ "D", "F", "R", "L", "L", "W" ]), | ||
new([ "R", "R", "D", "L", "G", "G" ]), | ||
new([ "X", "K", "B", "S", "Z", "N" ]), | ||
new([ "W", "H", "H", "T", "T", "P" ]), | ||
new([ "C", "C", "B", "T", "J", "D" ]), | ||
new([ "C", "C", "M", "T", "T", "S" ]), | ||
new([ "O", "I", "I", "N", "N", "Y" ]), | ||
new([ "A", "E", "I", "O", "U", "U" ]), | ||
new([ "A", "A", "E", "E", "O", "O" ]), | ||
]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
128 changes: 128 additions & 0 deletions
128
src/Smab.DiceAndTiles/Games/QLess/QLessDiceExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,133 @@ | ||
namespace Smab.DiceAndTiles.Games.QLess; | ||
public static class QLessDiceExtensions | ||
{ | ||
private const int ANY_COL = int.MinValue; | ||
|
||
public static QLessDiceStatus GameStatus(this QLessDice qLessDice) | ||
{ | ||
HashSet<PositionedDie> errorDice = []; | ||
ErrorReasons errorReasons = ErrorReasons.None; | ||
ScrabbleWordFinder swf = new(qLessDice.Board, qLessDice.dictionaryOfWords); | ||
List<string> words = swf.FindWords(); | ||
bool notFinished = false; | ||
|
||
if (qLessDice.Board.Count != qLessDice.Dice.Count) | ||
{ | ||
errorReasons |= ErrorReasons.MissingDice; | ||
notFinished = true; | ||
} | ||
|
||
if (swf.ValidWordsAsTiles.Concat(swf.InvalidWordsAsTiles).Any(t => t.Count == 2)) | ||
{ | ||
errorReasons |= ErrorReasons.TwoLetterWords; | ||
notFinished = true; | ||
errorDice = [.. errorDice, | ||
.. swf | ||
.ValidWordsAsTiles | ||
.Concat(swf.InvalidWordsAsTiles) | ||
.Where(t => t.Count == 2) | ||
.SelectMany(t => t) | ||
.Distinct() | ||
.Select(t => qLessDice.Board.SingleDieAt(t.Col, t.Row)) | ||
]; | ||
} | ||
|
||
if (swf.IsBlockInMoreThanOnePiece()) | ||
{ | ||
errorReasons |= ErrorReasons.MultipleBlocks; | ||
notFinished = true; | ||
errorDice = [.. errorDice, | ||
.. swf | ||
.Islands | ||
.OrderByDescending(i => i.Count) | ||
.Skip(1) | ||
.Where(i => i.Count != 0) | ||
.SelectMany(t => t) | ||
.Select(t => qLessDice.Board.SingleDieAt(t.Col, t.Row)) | ||
]; | ||
} | ||
|
||
if (qLessDice.dictionaryOfWords is not null && qLessDice.dictionaryOfWords.HasWords) | ||
{ | ||
if (notFinished is false && swf.InvalidWordsAsTiles.Count == 0) | ||
{ | ||
return new Win(); | ||
} | ||
|
||
if (swf.InvalidWordsAsTiles.Count != 0) | ||
{ | ||
errorReasons |= ErrorReasons.Misspelt; | ||
foreach (List<PositionedTile> tiles in swf.InvalidWordsAsTiles) | ||
{ | ||
tiles.ForEach(t => errorDice.Add(qLessDice.Board.SingleDieAt(t.Col, t.Row))); | ||
} | ||
} | ||
} | ||
else if (notFinished is false && errorDice.Count == 0) | ||
{ | ||
return new Win(); | ||
} | ||
|
||
return new Errors(errorDice, errorReasons); | ||
} | ||
|
||
public static (bool Success, QLessDice QLessDice) PlaceOnBoard(this QLessDice qLessDice, Die die, int col, int row) => qLessDice.PlaceOnBoard(die.Id, col, row); | ||
public static (bool Success, QLessDice QLessDice) PlaceOnBoard(this QLessDice qLessDice, DieId name, int col, int row) | ||
{ | ||
if (qLessDice.Board.Any(d => d.Row == row && d.Col == col)) | ||
{ | ||
return (false, qLessDice); | ||
} | ||
|
||
PositionedQLessDie positionedDie = qLessDice.DiceDictionary[name].PlaceOnBoard(col, row); | ||
Dictionary<DieId, PositionedQLessDie> newDiceDictionary = new(qLessDice.DiceDictionary) | ||
{ | ||
[name] = positionedDie | ||
}; | ||
return (true, qLessDice with { DiceDictionary = newDiceDictionary }); | ||
} | ||
|
||
public static (bool Success, QLessDice QLessDice) PlaceOnRack(this QLessDice qLessDice, Die die, int col = ANY_COL) => qLessDice.PlaceOnRack(die.Id, col); | ||
public static (bool Success, QLessDice QLessDice) PlaceOnRack(this QLessDice qLessDice, DieId dieId, int col = ANY_COL) | ||
{ | ||
if (col != ANY_COL && qLessDice.Rack.Any(p => p.Col == col)) | ||
{ | ||
return (false, qLessDice); | ||
} | ||
|
||
if (col == ANY_COL) | ||
{ | ||
col = Enumerable.Range(0, qLessDice.Dice.Count).Except(qLessDice.Rack.Select(d => d.Col)).Min(); | ||
} | ||
|
||
if (qLessDice.Rack.Any(p => p.Col == col)) | ||
{ | ||
return (false, qLessDice); | ||
} | ||
|
||
PositionedQLessDie positionedDie = qLessDice.DiceDictionary[dieId].PlaceOnRack(col); | ||
Dictionary<DieId, PositionedQLessDie> newDiceDictionary = new(qLessDice.DiceDictionary) | ||
{ | ||
[dieId] = positionedDie | ||
}; | ||
return (true, qLessDice with { DiceDictionary = newDiceDictionary }); | ||
} | ||
|
||
internal static Dictionary<DieId, PositionedQLessDie> ShakeAndFillRack(IEnumerable<LetterDie> dice, bool rollDice) | ||
{ | ||
Dictionary<DieId, PositionedQLessDie> diceDictionary = []; | ||
LetterDie[] bag = [.. dice]; | ||
Random.Shared.Shuffle(bag); | ||
|
||
for (int i = 0; i < bag.Length; i++) | ||
{ | ||
LetterDie die = bag[i]; | ||
if (rollDice) | ||
{ | ||
die = (LetterDie)die.Roll(); | ||
} | ||
diceDictionary.Add(die.Id, new PositionedQLessDie(die, i)); | ||
} | ||
return diceDictionary; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
namespace Smab.DiceAndTiles.Games.QLess; | ||
|
||
public abstract record class QLessDiceStatus(); | ||
|
||
public record Win() : QLessDiceStatus; | ||
|
||
public record Errors(IEnumerable<PositionedDie> DiceWithErrors, ErrorReasons ErrorReasons) : QLessDiceStatus; | ||
|
||
[Flags] | ||
public enum ErrorReasons | ||
{ | ||
None = 0, | ||
MultipleBlocks = 1, | ||
TwoLetterWords = 2, | ||
MissingDice = 4, | ||
Misspelt = 8, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
global using static Smab.DiceAndTiles.Games.QLess.BoardExtensions; | ||
global using static Smab.DiceAndTiles.Games.QLess.DiceCollections; | ||
global using static Smab.DiceAndTiles.Games.QLess.QLessDiceExtensions; | ||
global using static Smab.DiceAndTiles.Games.QLess.QLessDiceStatus; |
Oops, something went wrong.