Skip to content

Commit 1f44d11

Browse files
committed
Probable final build. Got the result I'm looking for.
1 parent 0b0243f commit 1f44d11

File tree

8 files changed

+128
-34
lines changed

8 files changed

+128
-34
lines changed

MattEland.FSharpGeneticAlgorithm.Logic/Fitness.fs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,30 @@ let standardFitnessFunction (gameStates: GameState[]): float =
1616

1717
let finalStateBonus =
1818
match lastState.SimState with
19-
| SimulationState.Won -> 500.0 - gameLength // Reward quick wins
20-
| SimulationState.Lost -> -50.0 + gameLength
21-
| _ -> 0.0 + gameLength
19+
| SimulationState.Won -> 1000.0 - (gameLength * 10.0) // Reward quick wins
20+
| _ -> -50.0 + gameLength
2221

2322
gotAcornBonus + finalStateBonus
2423

2524
let killRabbitFitnessFunction (gameStates: GameState[]): float =
26-
let rabbitBonus = Seq.map (fun s -> match s.World.Rabbit.IsActive with
27-
| false -> 10.0
28-
| _ -> 0.0) gameStates |> Seq.sum
25+
let lastState: GameState = Seq.last gameStates
26+
27+
let gameLength = float(gameStates.Length)
2928

30-
rabbitBonus + standardFitnessFunction gameStates
29+
let gotAcornBonus =
30+
match lastState.World.Acorn.IsActive with
31+
| true -> 100.0
32+
| false -> 0.0
33+
34+
let isRabbitAlive = lastState.World.Rabbit.IsActive
35+
36+
let finalStateBonus =
37+
match lastState.SimState with
38+
| SimulationState.Won -> match isRabbitAlive with
39+
| false -> 1000.0 // Heavily reward dead rabbits
40+
| true -> 250.0 - (gameLength * 10.0) // Reward quick wins
41+
| _ -> match isRabbitAlive with
42+
| true -> -50.0 + gameLength
43+
| false -> gameLength
44+
45+
gotAcornBonus + finalStateBonus

MattEland.FSharpGeneticAlgorithm.Logic/Genetics.fs

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
open MattEland.FSharpGeneticAlgorithm.Logic.World
66
open MattEland.FSharpGeneticAlgorithm.Logic.States
77

8-
type ActorGeneIndex = Doggo = 0| Acorn = 1| Rabbit = 2| Tree = 3| Squirrel = 4| NextToDoggo = 5| NextToRabbit = 6| Random = 7
8+
type ActorGeneIndex = Doggo = 0| Acorn = 1| Rabbit = 2| Tree = 3| Squirrel = 4| NextToDoggo = 5| NextToRabbit = 6
99

1010
type ActorChromosome =
1111
{
@@ -18,7 +18,7 @@
1818
let getRandomChromosome (random: System.Random) =
1919
{
2020
age = 0
21-
genes = Seq.init 8 (fun _ -> getRandomGene random) |> Seq.toArray
21+
genes = Seq.init 7 (fun _ -> getRandomGene random) |> Seq.toArray
2222
}
2323

2424
let mutate (random: System.Random, magnitude, value) =
@@ -56,19 +56,19 @@
5656

5757
let evaluateProximity actor pos weight =
5858
if actor.IsActive then
59-
let maxDistance = 1000.0
59+
let maxDistance = 225.0
6060
let distance = getDistance(actor.Pos, pos)
6161
if distance < maxDistance then
62-
(maxDistance - distance/maxDistance) * weight
62+
((maxDistance - distance)/maxDistance) * weight
6363
else
6464
0.0
6565
else
6666
0.0
6767

6868
let evaluateAdjacentTo actor pos weight =
6969
if actor.IsActive && actor.Pos <> pos then
70-
if getDistance(actor.Pos, pos) <= 0.0 then
71-
1.0
70+
if getDistance(actor.Pos, pos) <= 1.5 then
71+
0.05 * weight
7272
else
7373
0.0
7474
else
@@ -77,16 +77,18 @@
7777
let getGene (geneIndex: ActorGeneIndex) (genes: double[]) =
7878
genes.[int geneIndex]
7979

80-
let evaluateTile brain world pos (random: System.Random) =
80+
let evaluateTile brain world pos =
8181
let genes = brain.genes
82-
evaluateProximity world.Squirrel pos (getGene ActorGeneIndex.Squirrel genes) +
83-
evaluateProximity world.Rabbit pos (getGene ActorGeneIndex.Rabbit genes) +
84-
evaluateProximity world.Doggo pos (getGene ActorGeneIndex.Doggo genes) +
85-
evaluateProximity world.Acorn pos (getGene ActorGeneIndex.Acorn genes) +
86-
evaluateProximity world.Tree pos (getGene ActorGeneIndex.Tree genes) +
87-
evaluateAdjacentTo world.Doggo pos (getGene ActorGeneIndex.NextToDoggo genes) +
88-
evaluateAdjacentTo world.Rabbit pos (getGene ActorGeneIndex.NextToRabbit genes) +
89-
(random.NextDouble() * (getGene ActorGeneIndex.Random genes))
82+
83+
let proxSquirrel = evaluateProximity world.Squirrel pos (getGene ActorGeneIndex.Squirrel genes)
84+
let proxRabbit = evaluateProximity world.Rabbit pos (getGene ActorGeneIndex.Rabbit genes)
85+
let proxDoggo = evaluateProximity world.Doggo pos (getGene ActorGeneIndex.Doggo genes)
86+
let proxAcorn = evaluateProximity world.Acorn pos (getGene ActorGeneIndex.Acorn genes)
87+
let proxTree = evaluateProximity world.Tree pos (getGene ActorGeneIndex.Tree genes)
88+
let adjDoggo = evaluateAdjacentTo world.Doggo pos (getGene ActorGeneIndex.NextToDoggo genes)
89+
let adjRabbit = evaluateAdjacentTo world.Rabbit pos (getGene ActorGeneIndex.NextToRabbit genes)
90+
91+
proxSquirrel + proxRabbit + proxDoggo + proxAcorn + proxTree + adjDoggo + adjRabbit
9092

9193
type IndividualWorldResult = {
9294
score: float

MattEland.FSharpGeneticAlgorithm.Logic/Simulator.fs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,19 +120,19 @@ let simulateActors (state: GameState, getRandomNumber) =
120120
|> simulateDoggo
121121
|> decreaseTimer
122122

123-
let handleChromosomeMove random chromosome state =
123+
let handleChromosomeMove (random: System.Random) chromosome state =
124124
if state.SimState = SimulationState.Simulating then
125125
let current = state.World.Squirrel.Pos
126126
let movedPos = getCandidates(current, state.World, true)
127-
|> Seq.sortBy(fun pos -> evaluateTile chromosome state.World pos random)
127+
|> Seq.sortBy(fun pos -> evaluateTile chromosome state.World pos)
128128
|> Seq.head
129129
let newState = moveActor state state.World.Squirrel movedPos
130130
simulateActors(newState, random.Next)
131131
else
132132
state
133133

134134
let buildStartingStateForWorld world =
135-
{ World = world; SimState = SimulationState.Simulating; TurnsLeft = 80}
135+
{ World = world; SimState = SimulationState.Simulating; TurnsLeft = 100}
136136

137137
let buildStartingState (random: System.Random) =
138138
makeWorld 15 15 random.Next |> buildStartingStateForWorld
@@ -160,4 +160,4 @@ let simulateGame random brain fitnessFunction states =
160160
let simulate brain worlds =
161161
let states = Seq.map (fun w -> buildStartingStateForWorld w) worlds
162162
let random = new System.Random(42)
163-
simulateGame random brain standardFitnessFunction states
163+
simulateGame random brain killRabbitFitnessFunction states

MattEland.FSharpGeneticAlgorithm.WindowsClient/BrainInfoControl.xaml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,5 @@
2323
<ProgressBar Minimum="-1" Maximum="1" Value="{Binding SquirrelPriority, Mode=OneWay}"></ProgressBar>
2424
<TextBlock Margin="0,10,0,0">Tree</TextBlock>
2525
<ProgressBar Minimum="-1" Maximum="1" Value="{Binding TreePriority, Mode=OneWay}"></ProgressBar>
26-
<TextBlock Margin="0,10,0,0">Random</TextBlock>
27-
<ProgressBar Minimum="-1" Maximum="1" Value="{Binding RandomPriority, Mode=OneWay}"></ProgressBar>
2826
</StackPanel>
2927
</UserControl>

MattEland.FSharpGeneticAlgorithm.WindowsClient/MainWindow.xaml

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@
4444
<Grid Margin="10" Background="Green" DataContext="{Binding SelectedState}">
4545
<Image Source="Images/Grass.png" Stretch="Fill" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"></Image>
4646
<Viewbox Stretch="Uniform">
47-
<Border>
48-
<ItemsControl ItemsSource="{Binding Actors}" Width="150" Height="150">
47+
<Grid>
48+
<ItemsControl ItemsSource="{Binding Actors}" Width="150" Height="150" Panel.ZIndex="1">
4949
<ItemsControl.ItemTemplate>
5050
<ItemContainerTemplate>
5151
<Border BorderBrush="Black" BorderThickness="1">
@@ -65,7 +65,26 @@
6565
</Style>
6666
</ItemsControl.ItemContainerStyle>
6767
</ItemsControl>
68-
</Border>
68+
<ItemsControl ItemsSource="{Binding HeatMap}" Width="150" Height="150">
69+
<ItemsControl.ItemTemplate>
70+
<ItemContainerTemplate>
71+
<Border Background="{Binding Fill}" ToolTip="{Binding Text}" Opacity="0.5" Width="10" Height="10">
72+
</Border>
73+
</ItemContainerTemplate>
74+
</ItemsControl.ItemTemplate>
75+
<ItemsControl.ItemsPanel>
76+
<ItemsPanelTemplate>
77+
<Canvas></Canvas>
78+
</ItemsPanelTemplate>
79+
</ItemsControl.ItemsPanel>
80+
<ItemsControl.ItemContainerStyle>
81+
<Style TargetType="ContentPresenter">
82+
<Setter Property="Canvas.Left" Value="{Binding PosX}" />
83+
<Setter Property="Canvas.Top" Value="{Binding PosY}" />
84+
</Style>
85+
</ItemsControl.ItemContainerStyle>
86+
</ItemsControl>
87+
</Grid>
6988
</Viewbox>
7089
</Grid>
7190
</DockPanel>

MattEland.FSharpGeneticAlgorithm.WindowsClient/ViewModels/BrainInfoViewModel.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ public BrainInfoViewModel([NotNull] Genes.ActorChromosome brain)
2020
public double TreePriority => GetGene(Genes.ActorGeneIndex.Tree);
2121
public double NextToDoggoPriority => GetGene(Genes.ActorGeneIndex.NextToDoggo);
2222
public double NextToRabbitPriority => GetGene(Genes.ActorGeneIndex.NextToRabbit);
23-
public double RandomPriority => GetGene(Genes.ActorGeneIndex.Random);
2423

2524
public Genes.ActorChromosome Model { get; }
2625
}

MattEland.FSharpGeneticAlgorithm.WindowsClient/ViewModels/GameStateViewModel.cs

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Linq;
44
using System.Windows.Media;
55
using JetBrains.Annotations;
6+
using MattEland.FSharpGeneticAlgorithm.Genetics;
67
using MattEland.FSharpGeneticAlgorithm.Logic;
78

89
namespace MattEland.FSharpGeneticAlgorithm.WindowsClient.ViewModels
@@ -14,17 +15,37 @@ public class GameStateViewModel : NotifyPropertyChangedBase
1415
{
1516
private readonly States.GameState _state;
1617

17-
public GameStateViewModel([NotNull] States.GameState state)
18+
public GameStateViewModel([NotNull] States.GameState state, Genes.ActorChromosome brain)
1819
{
1920
_state = state ?? throw new ArgumentNullException(nameof(state));
2021

2122
foreach (var actor in _state.World.Actors.Where(a => a.IsActive))
2223
{
2324
Actors.Add(new ActorViewModel(actor));
2425
}
26+
27+
var values = new Dictionary<WorldPos.WorldPos, double>();
28+
29+
for (int y = 1; y <= state.World.MaxY; y++)
30+
{
31+
for (int x = 1; x <= state.World.MaxX; x++)
32+
{
33+
var pos = new WorldPos.WorldPos(x, y);
34+
values[pos] = Genes.evaluateTile(brain, state.World, pos);
35+
}
36+
}
37+
38+
var min = values.Values.Min();
39+
var max = values.Values.Max();
40+
41+
foreach (var (pos, value) in values)
42+
{
43+
HeatMap.Add(new HeatMapViewModel(pos, value, min, max));
44+
}
2545
}
2646

2747
public ICollection<ActorViewModel> Actors { get; } = new List<ActorViewModel>();
48+
public ICollection<HeatMapViewModel> HeatMap { get; } = new List<HeatMapViewModel>();
2849

2950
public string GameStatusText => _state.SimState switch
3051
{
@@ -44,4 +65,44 @@ public GameStateViewModel([NotNull] States.GameState state)
4465
? "1 Turn Left"
4566
: $"{_state.TurnsLeft} Turns Left";
4667
}
68+
69+
public class HeatMapViewModel : NotifyPropertyChangedBase
70+
{
71+
private readonly double _min;
72+
private readonly double _max;
73+
74+
public HeatMapViewModel(WorldPos.WorldPos pos, double value, double min, double max)
75+
{
76+
Pos = pos;
77+
Value = value;
78+
_min = min;
79+
_max = max;
80+
}
81+
82+
public WorldPos.WorldPos Pos { get; }
83+
public double Value { get; }
84+
public string Text => $"{Pos.X}, {Pos.Y} = {Value:F2}";
85+
// Subtract 1 since my data's indexes start at 1 instead of 0
86+
public int PosX => (Pos.X - 1) * 10;
87+
public int PosY => (Pos.Y - 1) * 10;
88+
public Brush Fill
89+
{
90+
get
91+
{
92+
var val = Value;
93+
var min = _min;
94+
var max = _max;
95+
96+
if (min < 0)
97+
{
98+
max -= min;
99+
val -= min;
100+
}
101+
102+
byte rgb = (byte) Math.Round((val / max) * 255);
103+
var color = Color.FromRgb(rgb, rgb, rgb);
104+
return new SolidColorBrush(color);
105+
}
106+
}
107+
}
47108
}

MattEland.FSharpGeneticAlgorithm.WindowsClient/ViewModels/SimulationResultViewModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public SimulationResultViewModel(Genes.SimulationResult result)
1616
_states = new ObservableCollection<GameStateViewModel>();
1717
foreach (var state in Model.results.SelectMany(r => r.states))
1818
{
19-
_states.Add(new GameStateViewModel(state));
19+
_states.Add(new GameStateViewModel(state, result.brain));
2020
}
2121
Brain = new BrainInfoViewModel(result.brain);
2222
}

0 commit comments

Comments
 (0)