Changed nearly everything, minor fixes and renames
Signed-off-by: Pablu23 <43807157+Pablu23@users.noreply.github.com>
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 89 KiB |
@@ -86,7 +86,7 @@
|
|||||||
</ShowAsCollectionAssociation>
|
</ShowAsCollectionAssociation>
|
||||||
</Class>
|
</Class>
|
||||||
<Class Name="TicTacToe.Program" Collapsed="true">
|
<Class Name="TicTacToe.Program" Collapsed="true">
|
||||||
<Position X="19.75" Y="7.5" Width="1.5" />
|
<Position X="19.25" Y="6.25" Width="1.5" />
|
||||||
<TypeIdentifier>
|
<TypeIdentifier>
|
||||||
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=</HashCode>
|
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA=</HashCode>
|
||||||
<FileName>Program.cs</FileName>
|
<FileName>Program.cs</FileName>
|
||||||
@@ -105,12 +105,9 @@
|
|||||||
<Class Name="TicTacToe.TicTacToeBoard">
|
<Class Name="TicTacToe.TicTacToeBoard">
|
||||||
<Position X="10.25" Y="4" Width="1.5" />
|
<Position X="10.25" Y="4" Width="1.5" />
|
||||||
<TypeIdentifier>
|
<TypeIdentifier>
|
||||||
<HashCode>AAAAAEAAAABIAAAAAECAEEIAAAAAAAAQAQAAAAARAAA=</HashCode>
|
<HashCode>AAAAAEAAAABAAAAAAEAAAEIAAAAAAAAQAQAAAAARgAA=</HashCode>
|
||||||
<FileName>TicTacToeBoard.cs</FileName>
|
<FileName>TicTacToeBoard.cs</FileName>
|
||||||
</TypeIdentifier>
|
</TypeIdentifier>
|
||||||
<ShowAsAssociation>
|
|
||||||
<Field Name="_fields" />
|
|
||||||
</ShowAsAssociation>
|
|
||||||
</Class>
|
</Class>
|
||||||
<Enum Name="TicTacToe.FieldState">
|
<Enum Name="TicTacToe.FieldState">
|
||||||
<Position X="15" Y="4.75" Width="1.5" />
|
<Position X="15" Y="4.75" Width="1.5" />
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -44,7 +44,7 @@ namespace TicTacToe.Players
|
|||||||
//TODO: Save Board history somehow
|
//TODO: Save Board history somehow
|
||||||
public class LearningAiPlayer : Player
|
public class LearningAiPlayer : Player
|
||||||
{
|
{
|
||||||
private string _pathToLearningDir = @"E:\Programieren\csharp\TicTacToe\TicTacToe\Players\LearningAiDir\ai.json";
|
private string _pathToLearningDir = @"C:\Users\zam.k\source\repos\TicTacToe\TicTacToe\Players\LearningAiDir\ai.json";
|
||||||
private int _round;
|
private int _round;
|
||||||
private AiBrain _brain;
|
private AiBrain _brain;
|
||||||
private Random _random;
|
private Random _random;
|
||||||
@@ -104,14 +104,14 @@ namespace TicTacToe.Players
|
|||||||
return move;
|
return move;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_brain is not null)
|
if (_brain != null)
|
||||||
{
|
{
|
||||||
var allPlayedRounds = _brain.AllOutcomes.FindAll(x =>
|
var allPlayedRounds = _brain.AllOutcomes.FindAll(x =>
|
||||||
Equals(x.GetBoardAtTime(_round), copyOfBoard));
|
Equals(x.GetBoardAtTime(_round), copyOfBoard));
|
||||||
if (_round == 0)
|
if (_round == 0)
|
||||||
{
|
{
|
||||||
var bestOption = _brain.AllOutcomes.Aggregate((i, j) => i.Weight > j.Weight ? i : j);
|
var bestOption = _brain.AllOutcomes.Aggregate((i, j) => i.Weight > j.Weight ? i : j);
|
||||||
if (bestOption is not null)
|
if (bestOption != null)
|
||||||
{
|
{
|
||||||
move = bestOption.GetNextMove(_round);
|
move = bestOption.GetNextMove(_round);
|
||||||
}
|
}
|
||||||
@@ -119,7 +119,7 @@ namespace TicTacToe.Players
|
|||||||
if (allPlayedRounds.Count != 0)
|
if (allPlayedRounds.Count != 0)
|
||||||
{
|
{
|
||||||
var bestOption = allPlayedRounds.Aggregate((i, j) => i.Weight > j.Weight ? i : j);
|
var bestOption = allPlayedRounds.Aggregate((i, j) => i.Weight > j.Weight ? i : j);
|
||||||
if (bestOption is not null)
|
if (bestOption != null)
|
||||||
{
|
{
|
||||||
move = bestOption.GetNextMove(_round);
|
move = bestOption.GetNextMove(_round);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,24 +5,183 @@ namespace TicTacToe
|
|||||||
{
|
{
|
||||||
class Program
|
class Program
|
||||||
{
|
{
|
||||||
static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
TicTacToe ticTacToe = new TicTacToe();
|
MainMenu();
|
||||||
Player player1 = new LearningAiPlayer("Learning", FieldState.PlayerX);
|
|
||||||
Player player2 = new AdvancedAiPlayer("MinMax", FieldState.PlayerO);
|
|
||||||
Player player3 = new BasicAiPlayer("Basic", FieldState.PlayerO);
|
|
||||||
Player player4 = new HumanPlayer("Human", FieldState.PlayerO);
|
|
||||||
|
|
||||||
ticTacToe.AddPlayer(player1);
|
|
||||||
ticTacToe.AddPlayer(player4);
|
|
||||||
|
|
||||||
//TODO: Menu
|
|
||||||
//TODO: Learning Players properties, dont reset, after more than one round = crash
|
|
||||||
|
|
||||||
ticTacToe.StartGame();
|
|
||||||
ticTacToe.DrawScore();
|
|
||||||
|
|
||||||
Console.ReadKey(true);
|
Console.ReadKey(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void MainMenu()
|
||||||
|
{
|
||||||
|
TicTacToe ticTacToe = new TicTacToe();
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
Console.Clear();
|
||||||
|
Console.WriteLine("Welcome to TicTacToe");
|
||||||
|
Console.WriteLine("[C]onfig Players");
|
||||||
|
//Console.WriteLine("[N]ew Game");
|
||||||
|
Console.WriteLine("[S]tart Game");
|
||||||
|
Console.WriteLine("[E]nd");
|
||||||
|
|
||||||
|
char input = GetCharInput(new[] { 'c', 's', 'e', 'n' });
|
||||||
|
|
||||||
|
switch (input)
|
||||||
|
{
|
||||||
|
case 'c':
|
||||||
|
ConfigPlayers(ticTacToe);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
if(ticTacToe.GetPlayerCount() < 2)
|
||||||
|
{
|
||||||
|
Console.WriteLine("There are not enough Players to start the game");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ticTacToe.StartGame();
|
||||||
|
ticTacToe.DrawScore();
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
Environment.Exit(0);
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
ticTacToe = new TicTacToe();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("To continue press any Key...");
|
||||||
|
Console.ReadKey(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ConfigPlayers(TicTacToe ticTacToe)
|
||||||
|
{
|
||||||
|
|
||||||
|
//Show Players if any exist
|
||||||
|
Console.Clear();
|
||||||
|
if(ticTacToe.GetPlayerCount() == 0)
|
||||||
|
{
|
||||||
|
Player p1 = CreatePlayer();
|
||||||
|
Player p2 = CreatePlayer(p1.Symbol);
|
||||||
|
|
||||||
|
ticTacToe.AddPlayer(p1);
|
||||||
|
ticTacToe.AddPlayer(p2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine("Which Player to edit");
|
||||||
|
ticTacToe.ShowPlayers();
|
||||||
|
|
||||||
|
Console.WriteLine("[E]xit");
|
||||||
|
|
||||||
|
bool correctInput = false;
|
||||||
|
int playerToEdit = 0;
|
||||||
|
while (!correctInput)
|
||||||
|
{
|
||||||
|
string input = Console.ReadLine();
|
||||||
|
if (input?.ToLower() == "e") return;
|
||||||
|
correctInput = int.TryParse(input, out playerToEdit);
|
||||||
|
playerToEdit -= 1;
|
||||||
|
if (correctInput) correctInput = playerToEdit <= ticTacToe.GetPlayerCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
ticTacToe.ReplacePlayer(playerToEdit, CreatePlayer(ticTacToe.GetOpponentSymbol(playerToEdit == 0 ? 1 : 0)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static Player CreatePlayer(FieldState otherPlayer = FieldState.Empty)
|
||||||
|
{
|
||||||
|
Console.Clear();
|
||||||
|
Console.WriteLine("Create new Player\n----------------");
|
||||||
|
Console.WriteLine("Name of the Player:");
|
||||||
|
string name = Console.ReadLine();
|
||||||
|
|
||||||
|
FieldState sym = FieldState.Empty;
|
||||||
|
|
||||||
|
if (otherPlayer == FieldState.Empty)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Symbole of the Player");
|
||||||
|
string symbol = Console.ReadLine();
|
||||||
|
|
||||||
|
switch (symbol?.ToUpper())
|
||||||
|
{
|
||||||
|
case "X":
|
||||||
|
sym = FieldState.PlayerX;
|
||||||
|
break;
|
||||||
|
case "O":
|
||||||
|
sym = FieldState.PlayerO;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("Symbol was not recognised");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (otherPlayer)
|
||||||
|
{
|
||||||
|
case FieldState.PlayerO:
|
||||||
|
sym = FieldState.PlayerX;
|
||||||
|
break;
|
||||||
|
case FieldState.PlayerX:
|
||||||
|
sym = FieldState.PlayerO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("Type of Player");
|
||||||
|
Console.WriteLine("[1] Human");
|
||||||
|
Console.WriteLine("[2] Basic (Random)");
|
||||||
|
Console.WriteLine("[3] Advanced (Unbeatable)");
|
||||||
|
Console.WriteLine("[4] Learning (Stupid)");
|
||||||
|
|
||||||
|
int ki = int.Parse(Console.ReadLine());
|
||||||
|
|
||||||
|
Player player;
|
||||||
|
|
||||||
|
switch (ki)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
player = new HumanPlayer(name, sym);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
player = new BasicAiPlayer(name, sym);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
player = new AdvancedAiPlayer(name, sym);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
player = new LearningAiPlayer(name, sym);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("The given Number was wrong");
|
||||||
|
}
|
||||||
|
|
||||||
|
return player;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static char GetCharInput(char[] acceptedChars, string message = null)
|
||||||
|
{
|
||||||
|
if (message != null)
|
||||||
|
Console.WriteLine(message);
|
||||||
|
|
||||||
|
char result;
|
||||||
|
bool loop = true;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
|
||||||
|
// This is because the highest number is 9 so we always only need one Key to play
|
||||||
|
var key = Console.ReadKey(true);
|
||||||
|
result = key.KeyChar;
|
||||||
|
foreach (var item in acceptedChars)
|
||||||
|
{
|
||||||
|
if (result == item)
|
||||||
|
loop = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (loop);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,7 +9,20 @@ namespace TicTacToe
|
|||||||
private TicTacToeBoard _board;
|
private TicTacToeBoard _board;
|
||||||
|
|
||||||
private bool _gameFinished;
|
private bool _gameFinished;
|
||||||
|
|
||||||
|
private void RemovePlayer(Player player)
|
||||||
|
{
|
||||||
|
if (Players.Count <= 0) throw new Exception("No Players found cant remove Player");
|
||||||
|
Players.Remove(player);
|
||||||
|
Scores.Remove(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReplacePlayer(int oldPlayerIndex, Player newPlayer)
|
||||||
|
{
|
||||||
|
RemovePlayer(Players[oldPlayerIndex]);
|
||||||
|
AddPlayer(newPlayer);
|
||||||
|
}
|
||||||
|
|
||||||
public override void AddPlayer(Player player)
|
public override void AddPlayer(Player player)
|
||||||
{
|
{
|
||||||
if (Players.Count >= 2) throw new Exception("Trying to add too many Players");
|
if (Players.Count >= 2) throw new Exception("Trying to add too many Players");
|
||||||
@@ -17,6 +30,24 @@ namespace TicTacToe
|
|||||||
Scores.Add(player, 0);
|
Scores.Add(player, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int GetPlayerCount()
|
||||||
|
{
|
||||||
|
return Players.Count();
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldState GetOpponentSymbol(int playerIndex)
|
||||||
|
{
|
||||||
|
return Players[playerIndex].Symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ShowPlayers()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Players.Count; i++)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"[{i+1}] Name: {Players[i].Name} | Symbol: {Players[i].Symbol} | Type: {Players[i].GetType().ToString().Substring(18)}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override void AddScore(Player player)
|
public override void AddScore(Player player)
|
||||||
{
|
{
|
||||||
if (Players.Contains(player))
|
if (Players.Contains(player))
|
||||||
@@ -49,14 +80,14 @@ namespace TicTacToe
|
|||||||
|
|
||||||
// Get the winner (Player? <- ? because the player could be null)
|
// Get the winner (Player? <- ? because the player could be null)
|
||||||
var winner = Players.FirstOrDefault(x => x.Symbol == winnerState);
|
var winner = Players.FirstOrDefault(x => x.Symbol == winnerState);
|
||||||
if (winner is not null)
|
if (winner != null)
|
||||||
{
|
{
|
||||||
AddScore(winner);
|
AddScore(winner);
|
||||||
|
|
||||||
//If one of the Players was a LearningAiPlayer add the Match to the Ai Brain
|
//If one of the Players was a LearningAiPlayer add the Match to the Ai Brain
|
||||||
var player = Players.FirstOrDefault(x => x.GetType() == typeof(LearningAiPlayer));
|
var player = Players.FirstOrDefault(x => x.GetType() == typeof(LearningAiPlayer));
|
||||||
var learningAiPlayer = player as LearningAiPlayer;
|
var learningAiPlayer = player as LearningAiPlayer;
|
||||||
if (learningAiPlayer is not null)
|
if (learningAiPlayer != null)
|
||||||
learningAiPlayer.SaveToJson(_board);
|
learningAiPlayer.SaveToJson(_board);
|
||||||
}
|
}
|
||||||
CleanUp();
|
CleanUp();
|
||||||
@@ -72,7 +103,7 @@ namespace TicTacToe
|
|||||||
_gameFinished = false;
|
_gameFinished = false;
|
||||||
int round = 0;
|
int round = 0;
|
||||||
|
|
||||||
while (_gameFinished is not true)
|
while (_gameFinished != true)
|
||||||
{
|
{
|
||||||
// For both Players
|
// For both Players
|
||||||
for (int i = 0; i < 2; i++)
|
for (int i = 0; i < 2; i++)
|
||||||
|
|||||||
@@ -12,25 +12,35 @@ namespace TicTacToe
|
|||||||
for (int i = 0; i < Fields.Length; i++)
|
for (int i = 0; i < Fields.Length; i++)
|
||||||
{
|
{
|
||||||
//Initialise all Fields and give them the Symbol on which Position they are
|
//Initialise all Fields and give them the Symbol on which Position they are
|
||||||
Fields[i] = new Field(Convert.ToChar((i+1).ToString()));
|
Fields[i] = new Field(Convert.ToChar((i + 1).ToString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DrawBoard()
|
public void DrawBoard()
|
||||||
{
|
{
|
||||||
Console.Clear();
|
Console.Clear();
|
||||||
Console.WriteLine(
|
|
||||||
$"{Fields[0].Symbol} | " +
|
for (int i = 0; i < 9; i++)
|
||||||
$"{Fields[1].Symbol} | " +
|
{
|
||||||
$"{Fields[2].Symbol}\n--------\n" +
|
if (Fields[i].State == FieldState.PlayerO)
|
||||||
$"{Fields[3].Symbol} | " +
|
Console.ForegroundColor = ConsoleColor.Green;
|
||||||
$"{Fields[4].Symbol} | " +
|
if (Fields[i].State == FieldState.PlayerX)
|
||||||
$"{Fields[5].Symbol}\n--------\n" +
|
Console.ForegroundColor = ConsoleColor.Red;
|
||||||
$"{Fields[6].Symbol} | " +
|
if (Fields[i].State == FieldState.Empty)
|
||||||
$"{Fields[7].Symbol} | " +
|
Console.ForegroundColor = ConsoleColor.Gray;
|
||||||
$"{Fields[8].Symbol}");
|
|
||||||
|
Console.Write(Fields[i].Symbol);
|
||||||
|
Console.ForegroundColor = ConsoleColor.Gray;
|
||||||
|
|
||||||
|
if ((i + 1) % 3 == 0 && i != 8)
|
||||||
|
Console.Write("\n--------\n");
|
||||||
|
else if (i == 8)
|
||||||
|
Console.WriteLine();
|
||||||
|
else
|
||||||
|
Console.Write(" | ");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Tries to mark a position, if the position is not free it returns a false
|
//Tries to mark a position, if the position is not free it returns a false
|
||||||
public bool TryPlace(int pos, Player player, int round)
|
public bool TryPlace(int pos, Player player, int round)
|
||||||
{
|
{
|
||||||
@@ -63,7 +73,7 @@ namespace TicTacToe
|
|||||||
{
|
{
|
||||||
history[i] = -1;
|
history[i] = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
foreach (var field in Fields)
|
foreach (var field in Fields)
|
||||||
{
|
{
|
||||||
@@ -76,7 +86,7 @@ namespace TicTacToe
|
|||||||
|
|
||||||
return history;
|
return history;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsBoardFull()
|
private bool IsBoardFull()
|
||||||
{
|
{
|
||||||
bool isBoardFull = true;
|
bool isBoardFull = true;
|
||||||
@@ -141,14 +151,14 @@ namespace TicTacToe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool Diagonal(out FieldState winner)
|
private bool Diagonal(out FieldState winner)
|
||||||
{
|
{
|
||||||
winner = Fields[4].State;
|
winner = Fields[4].State;
|
||||||
return Fields[4].State != FieldState.Empty &&
|
return Fields[4].State != FieldState.Empty &&
|
||||||
(Fields[0].State == Fields[4].State && Fields[4].State == Fields[8].State ||
|
(Fields[0].State == Fields[4].State && Fields[4].State == Fields[8].State ||
|
||||||
Fields[2].State == Fields[4].State && Fields[4].State == Fields[6].State);
|
Fields[2].State == Fields[4].State && Fields[4].State == Fields[6].State);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user