Skip to content

Commit 9e5cde8

Browse files
committed
Feature: Enhanced AI logic and stats tracking for Pong game.
1 parent 56d59f5 commit 9e5cde8

File tree

3 files changed

+40
-30
lines changed

3 files changed

+40
-30
lines changed

G33kShell.Desktop/Console/Screensavers/Pong/Brain.cs

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,40 +9,36 @@
99
//
1010
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND.
1111

12-
using System.Numerics;
12+
using System;
1313
using CSharp.Core;
1414
using G33kShell.Desktop.Console.Screensavers.AI;
1515

1616
namespace G33kShell.Desktop.Console.Screensavers.Pong;
1717

1818
public class Brain : AiBrainBase
1919
{
20-
public Brain() : base(GetInputSize(), [10], 6)
20+
public const int BrainInputCount = 8;
21+
22+
public Brain() : base(BrainInputCount, [16], 4)
2123
{
2224
}
2325

2426
private Brain(Brain brain) : base(brain)
2527
{
2628
}
27-
28-
private static int GetInputSize() =>
29-
new GameState([Vector2.One, Vector2.One], Vector2.One, Vector2.One, 1, 1).ToInputVector().Length;
30-
3129
public (Direction LeftBat, Direction RightBat) ChooseMoves(IAiGameState state)
3230
{
3331
var outputs = GetOutputs(state);
3432

3533
var leftBatDirection = Direction.Left; // No move.
36-
if (outputs[0] > outputs[1] && outputs[0] > outputs[2])
37-
leftBatDirection = Direction.Up;
38-
else if (outputs[2] > outputs[0] && outputs[2] > outputs[1])
39-
leftBatDirection = Direction.Down;
34+
var diff = outputs[0] - outputs[1];
35+
if (Math.Abs(diff) > 0.2) // Apply a threshold for a move.
36+
leftBatDirection = diff > 0 ? Direction.Up : Direction.Down;
4037

4138
var rightBatDirection = Direction.Left; // No move.
42-
if (outputs[3] > outputs[4] && outputs[3] > outputs[5])
43-
rightBatDirection = Direction.Up;
44-
else if (outputs[5] > outputs[3] && outputs[5] > outputs[4])
45-
rightBatDirection = Direction.Down;
39+
diff = outputs[2] - outputs[3];
40+
if (Math.Abs(diff) > 0.2)
41+
rightBatDirection = diff > 0 ? Direction.Up : Direction.Down;
4642

4743
return (leftBatDirection, rightBatDirection);
4844
}

G33kShell.Desktop/Console/Screensavers/Pong/Game.cs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public class Game : AiGameBase
2323
{
2424
private const int ScoreToWin = 10;
2525
private const float BatSpeed = 0.22f;
26+
private readonly int[] m_batMoves = new int[2];
2627
private Vector2 m_ballVelocity;
2728
private int m_ballMoves;
2829
private int m_rallies;
@@ -36,12 +37,11 @@ public override double Rating
3637
{
3738
get
3839
{
39-
if (Scores[0] + Scores[1] == 0)
40+
if (Scores[0] * Scores[1] == 0)
4041
return 0.0; // No score - rubbish game.
41-
return m_rallies * 0.2 // Reward rallies.
42-
+ m_ballMoves * 0.01 // ...and long games.
43-
+ (ScoreToWin - Math.Abs(Scores[0] - Scores[1])) // Reward balanced scores.
44-
+ (Scores[0] + Scores[1]) / (2.0 * ScoreToWin); // Reward high score. (Note: Might be small if game times-out.)
42+
if (Math.Min(m_batMoves[0], m_batMoves[1]) < 300)
43+
return 0.0; // No moves - rubbish game.
44+
return m_rallies * (Scores[0] + Scores[1]);
4545
}
4646
}
4747

@@ -50,7 +50,12 @@ public override double Rating
5050

5151
public override IEnumerable<(string Name, string Value)> ExtraGameStats()
5252
{
53-
yield break;
53+
yield return ("Ticks", m_ballMoves.ToString());
54+
yield return ("Score1", Scores[0].ToString());
55+
yield return ("Score2", Scores[1].ToString());
56+
yield return ("LeftMoves", m_batMoves[0].ToString());
57+
yield return ("RightMoves", m_batMoves[1].ToString());
58+
yield return ("Rallies", m_rallies.ToString());
5459
}
5560

5661
public Game(int arenaWidth, int arenaHeight) : base(arenaWidth, arenaHeight, new Brain())
@@ -65,6 +70,7 @@ public override AiGameBase ResetGame()
6570
Scores[0] = Scores[1] = 0;
6671
m_rallies = 0;
6772
m_ballMoves = 0;
73+
m_batMoves[0] = m_batMoves[1] = 0;
6874

6975
return this;
7076
}
@@ -139,15 +145,21 @@ public override void Tick()
139145
_ => 0
140146
};
141147
if (nextY >= BatHeight / 2.0f && nextY < ArenaHeight - BatHeight / 2.0f)
148+
{
142149
BatPositions[0].Y = nextY;
150+
m_batMoves[0]++;
151+
}
143152
nextY = BatPositions[1].Y + BatSpeed * newDirections.RightBat switch
144153
{
145154
Direction.Up => -1,
146155
Direction.Down => 1,
147156
_ => 0
148157
};
149158
if (nextY >= BatHeight / 2.0f && nextY < ArenaHeight - BatHeight / 2.0f)
159+
{
150160
BatPositions[1].Y = nextY;
161+
m_batMoves[1]++;
162+
}
151163
}
152164

153165
private void NormalizeBallVelocity() =>

G33kShell.Desktop/Console/Screensavers/Pong/GameState.cs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
// about your modifications. Your contributions are valued!
99
//
1010
// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND.
11-
using System.Collections.Generic;
1211
using System.Numerics;
1312
using CSharp.Core.Extensions;
1413
using G33kShell.Desktop.Console.Screensavers.AI;
@@ -37,18 +36,21 @@ public GameState(Vector2[] bats, Vector2 ballPosition, Vector2 ballVelocity, int
3736

3837
public double[] ToInputVector()
3938
{
40-
var inputVector = new List<double>();
39+
var inputVector = new double[Brain.BrainInputCount];
4140

4241
// Encode bat positions.
43-
inputVector.Add(m_bats[0].Y / m_arenaHeight * 2.0f - 1.0f);
44-
inputVector.Add(m_bats[1].Y / m_arenaHeight * 2.0f - 1.0f);
45-
42+
inputVector[0] = m_bats[0].Y / m_arenaHeight * 2.0f - 1.0f;
43+
inputVector[1] = m_bats[1].Y / m_arenaHeight * 2.0f - 1.0f;
44+
45+
inputVector[2] = (m_bats[0].Y - m_ballPosition.Y) / m_arenaHeight * 2.0f;
46+
inputVector[3] = (m_bats[1].Y - m_ballPosition.Y) / m_arenaHeight * 2.0f;
47+
4648
// Encode ball state.
47-
inputVector.Add(m_ballPosition.X / m_arenaWidth * 2.0f - 1.0f);
48-
inputVector.Add(m_ballPosition.Y / m_arenaHeight * 2.0f - 1.0f);
49-
inputVector.Add(m_ballVelocity.X.Clamp(-1.0f, 1.0f));
50-
inputVector.Add(m_ballVelocity.Y.Clamp(-1.0f, 1.0f));
49+
inputVector[4] = m_ballPosition.X / m_arenaWidth * 2.0f - 1.0f;
50+
inputVector[5] = m_ballPosition.Y / m_arenaHeight * 2.0f - 1.0f;
51+
inputVector[6] = m_ballVelocity.X.Clamp(-1.0f, 1.0f);
52+
inputVector[7] = m_ballVelocity.Y.Clamp(-1.0f, 1.0f);
5153

52-
return inputVector.ToArray();
54+
return inputVector;
5355
}
5456
}

0 commit comments

Comments
 (0)