diff --git a/GameHandler.UnitTests/GameServiceTests.cs b/GameHandler.UnitTests/GameServiceTests.cs
new file mode 100644
index 0000000..cececd7
--- /dev/null
+++ b/GameHandler.UnitTests/GameServiceTests.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GameHandler.UnitTests
+{
+ [TestFixture]
+ internal class GameServiceTests
+ {
+ [Test]
+ public void Start_StartsANewGame()
+ {
+ GameService service = new GameService();
+ service.Start();
+ }
+ }
+}
diff --git a/GameHandler/DeathGame/DeathGameHandler.cs b/GameHandler/DeathGame/DeathGameHandler.cs
index 8380c63..d2772bc 100644
--- a/GameHandler/DeathGame/DeathGameHandler.cs
+++ b/GameHandler/DeathGame/DeathGameHandler.cs
@@ -172,9 +172,6 @@ namespace GameHandler.DeathGame
coffins.Insert(idx, previousUpdated);
}
-
-
-
var result = gm with { Coffins = coffins.ToArray(), Id = gm.Id + 1 };
return result;
diff --git a/GameHandler/GameService.cs b/GameHandler/GameService.cs
new file mode 100644
index 0000000..bb219e9
--- /dev/null
+++ b/GameHandler/GameService.cs
@@ -0,0 +1,54 @@
+using GameModel;
+using GameModel.Exceptions;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GameHandler
+{
+ public class GameService
+ {
+ private bool _isStarted = false;
+ private ThrowHandler _th;
+ private BoardState _lastState;
+
+ public BoardState Start()
+ {
+ if (_isStarted)
+ {
+ throw new InvalidGameStateExcpetion("Game already started");
+ }
+ if (!_isStarted)
+ {
+ _isStarted = true;
+ }
+
+ _th = new ThrowHandler();
+
+ _lastState = BoardState.Create(ThrowMode.Decrease);
+ return _lastState;
+ }
+
+ public BoardState HandleThrow(PinThrow pinThrow)
+ {
+ if (!_isStarted)
+ {
+ throw new InvalidGameStateExcpetion("Game not started");
+ }
+
+ _lastState = _th.Update(_lastState, pinThrow);
+ return _lastState;
+ }
+
+ public void Stop()
+ {
+ if (!_isStarted)
+ {
+ throw new InvalidGameStateExcpetion("Game not started");
+ }
+ _isStarted = false;
+ }
+ }
+}
diff --git a/GameHandler/MainHandler.cs b/GameHandler/MainHandler.cs
deleted file mode 100644
index d29c5f5..0000000
--- a/GameHandler/MainHandler.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace GameHandler
-{
- internal class MainHandler
- {
-
- }
-}
diff --git a/GameModel.UnitTests/GameModel.UnitTests.csproj b/GameModel.UnitTests/GameModel.UnitTests.csproj
new file mode 100644
index 0000000..f7e431d
--- /dev/null
+++ b/GameModel.UnitTests/GameModel.UnitTests.csproj
@@ -0,0 +1,30 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+ false
+ true
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
diff --git a/GameModel.UnitTests/GlobalUsings.cs b/GameModel.UnitTests/GlobalUsings.cs
new file mode 100644
index 0000000..cefced4
--- /dev/null
+++ b/GameModel.UnitTests/GlobalUsings.cs
@@ -0,0 +1 @@
+global using NUnit.Framework;
\ No newline at end of file
diff --git a/GameModel.UnitTests/Helper/IEnumerableExtension.cs b/GameModel.UnitTests/Helper/IEnumerableExtension.cs
new file mode 100644
index 0000000..307a7b2
--- /dev/null
+++ b/GameModel.UnitTests/Helper/IEnumerableExtension.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GameModel.UnitTests.Helper
+{
+ public static class IEnumerableExtension
+ {
+ public static IEnumerable AsWeakEnumerable(this IEnumerable source)
+ {
+ foreach (object o in source)
+ {
+ yield return o;
+ }
+ }
+ }
+}
diff --git a/GameHandler.UnitTests/PinPictureTests.cs b/GameModel.UnitTests/PinPictureTests.cs
similarity index 99%
rename from GameHandler.UnitTests/PinPictureTests.cs
rename to GameModel.UnitTests/PinPictureTests.cs
index 32b5fb2..b71a2fc 100644
--- a/GameHandler.UnitTests/PinPictureTests.cs
+++ b/GameModel.UnitTests/PinPictureTests.cs
@@ -1,4 +1,4 @@
-using GameHandler.UnitTests.Helper;
+using GameModel.UnitTests.Helper;
using GameModel;
using GameModel.Exceptions;
using NuGet.Frameworks;
@@ -6,7 +6,7 @@ using NUnit.Framework.Legacy;
using System.Collections;
using System.Numerics;
-namespace GameHandler.UnitTests
+namespace GameModel.UnitTests
{
[TestFixture]
internal class PinPictureTests
diff --git a/GameHandler.UnitTests/PinThrowTests.cs b/GameModel.UnitTests/PinThrowTests.cs
similarity index 98%
rename from GameHandler.UnitTests/PinThrowTests.cs
rename to GameModel.UnitTests/PinThrowTests.cs
index 9787604..047b38f 100644
--- a/GameHandler.UnitTests/PinThrowTests.cs
+++ b/GameModel.UnitTests/PinThrowTests.cs
@@ -5,7 +5,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
-namespace GameHandler.UnitTests
+namespace GameModel.UnitTests
{
[TestFixture]
internal class PinThrowTests
diff --git a/GameModel/Exceptions/InvalidGameStateExcpetion.cs b/GameModel/Exceptions/InvalidGameStateExcpetion.cs
new file mode 100644
index 0000000..a4e5926
--- /dev/null
+++ b/GameModel/Exceptions/InvalidGameStateExcpetion.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GameModel.Exceptions
+{
+ public class InvalidGameStateExcpetion : KoogleException
+ {
+ public InvalidGameStateExcpetion(string message) : base(message, null)
+ {
+ }
+ }
+}
diff --git a/GameModel/PinPicture.cs b/GameModel/PinPicture.cs
index 2b1aae0..2008f3d 100644
--- a/GameModel/PinPicture.cs
+++ b/GameModel/PinPicture.cs
@@ -195,5 +195,27 @@ namespace GameModel
var states = new List(new[] { PinState.Down, PinState.Down, PinState.Down, PinState.Down, PinState.Up, PinState.Down, PinState.Down, PinState.Down, PinState.Down }).ToArray();
return PinPicture.Create(states);
}
+
+ internal static PinPicture Create(string pindata)
+ {
+ if (!int.TryParse(pindata, out int dummy))
+ {
+ throw new InvalidDataException($"{pindata} cannot be parsed as throw");
+ }
+
+ var states = new[] {
+ pindata.Contains("1") ? PinState.Down : PinState.Up,
+ pindata.Contains("2") ? PinState.Down : PinState.Up,
+ pindata.Contains("3") ? PinState.Down : PinState.Up,
+ pindata.Contains("4") ? PinState.Down : PinState.Up,
+ pindata.Contains("5") ? PinState.Down : PinState.Up,
+ pindata.Contains("6") ? PinState.Down : PinState.Up,
+ pindata.Contains("7") ? PinState.Down : PinState.Up,
+ pindata.Contains("8") ? PinState.Down : PinState.Up,
+ pindata.Contains("9") ? PinState.Down : PinState.Up,
+ };
+
+ return PinPicture.Create(states);
+ }
}
}
diff --git a/GameModel/PinThrow.cs b/GameModel/PinThrow.cs
index 5319539..f6cdd63 100644
--- a/GameModel/PinThrow.cs
+++ b/GameModel/PinThrow.cs
@@ -19,9 +19,9 @@ namespace GameModel
public bool IsNoWood => PicPicture.DownCount == 0 && !IsSink;
- public static PinThrow Create(int PlayerId, PinPicture PicPicture, bool IsBell, bool IsSink)
+ public static PinThrow Create(int playerId, PinPicture picPicture, bool isBell, bool isSink)
{
- return new PinThrow(PlayerId, PicPicture, IsBell, IsSink);
+ return new PinThrow(playerId, picPicture, isBell, isSink);
}
public static PinThrow Create(int PlayerId, bool IsBell, bool IsSink)
@@ -29,5 +29,16 @@ namespace GameModel
var p = PinPicture.Create();
return Create(PlayerId, p, IsBell, IsSink);
}
+
+ public static PinThrow Create(string pindata, bool isBell, bool isSink, int playerId)
+ {
+ if (!int.TryParse(pindata, out int dummy))
+ {
+ throw new InvalidDataException($"{pindata} cannot be parsed as throw");
+ }
+
+ var pic = PinPicture.Create(pindata);
+ return PinThrow.Create(playerId, pic, isBell, isSink);
+ }
}
}
diff --git a/KoogleCli/KoogleCli.csproj b/KoogleCli/KoogleCli.csproj
new file mode 100644
index 0000000..a502f8c
--- /dev/null
+++ b/KoogleCli/KoogleCli.csproj
@@ -0,0 +1,20 @@
+
+
+
+ Exe
+ net7.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/KoogleCli/Model/Option.cs b/KoogleCli/Model/Option.cs
new file mode 100644
index 0000000..e5d5041
--- /dev/null
+++ b/KoogleCli/Model/Option.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace KoogleCli.Model
+{
+ internal record Option(string Name,Action Action)
+ {
+ public override string ToString()
+ {
+ return Name;
+ }
+ }
+}
diff --git a/KoogleCli/Model/ThrowData.cs b/KoogleCli/Model/ThrowData.cs
new file mode 100644
index 0000000..bb4161e
--- /dev/null
+++ b/KoogleCli/Model/ThrowData.cs
@@ -0,0 +1,13 @@
+using CommandLine;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace KoogleCli.Model
+{
+ public record ThrowData(int PlayerId, string Pindata, bool Bell, bool Sink, bool Abort)
+ {
+ }
+}
diff --git a/KoogleCli/Parser/ThrowDataParser.cs b/KoogleCli/Parser/ThrowDataParser.cs
new file mode 100644
index 0000000..c09c6bf
--- /dev/null
+++ b/KoogleCli/Parser/ThrowDataParser.cs
@@ -0,0 +1,25 @@
+using KoogleCli.Model;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using static System.Runtime.InteropServices.JavaScript.JSType;
+
+namespace KoogleCli.Parser
+{
+ public static class ThrowDataParser
+ {
+ public static ThrowData Parse(string data)
+ {
+ if (string.IsNullOrEmpty(data))
+ throw new ArgumentNullException("data");
+
+ var player = data.Substring(0, 1);
+ var playerId = int.Parse(player);
+ var pindata = data.Substring(2, data.Length -2);
+ return new ThrowData(playerId, Regex.Match(pindata, @"\d+").Value, data.Contains("b"), data.Contains("s"), data.Contains("e"));
+ }
+ }
+}
diff --git a/KoogleCli/Program.cs b/KoogleCli/Program.cs
new file mode 100644
index 0000000..7044683
--- /dev/null
+++ b/KoogleCli/Program.cs
@@ -0,0 +1,176 @@
+// See https://aka.ms/new-console-template for more information
+using CommandLine;
+using GameHandler;
+using GameModel;
+using KoogleCli.Model;
+using KoogleCli.Parser;
+using Spectre.Console;
+using static System.Runtime.InteropServices.JavaScript.JSType;
+
+AnsiConsole.MarkupLine("Welcome to [green]koogle[/]");
+
+do
+{
+ var option = AnsiConsole.Prompt(
+ new SelectionPrompt