add stuff, try to fix bad behaviour
This commit is contained in:
parent
c213507aec
commit
c1fbe9cd80
@ -55,7 +55,6 @@ defmodule Diamondtail.Brain do
|
||||
|> Map.update(:snakes, nil, fn snakes ->
|
||||
Map.update(snakes, state.self, nil, &apply_action_to_snake(&1, move))
|
||||
end)
|
||||
# |> resolve_state()
|
||||
end
|
||||
|
||||
def apply_actions(%GameState{type: :q} = state, moves) do
|
||||
@ -84,17 +83,22 @@ defmodule Diamondtail.Brain do
|
||||
end
|
||||
end
|
||||
|
||||
def valid_actions(%GameState{type: :q, snakes: snakes, self: self}) do
|
||||
def valid_actions(%GameState{type: :q, snakes: snakes, self: self} = state) do
|
||||
non_self_snakes = Map.delete(snakes, self)
|
||||
for i <- 0..(4 ** map_size(non_self_snakes)) - 1 do
|
||||
Enum.with_index(non_self_snakes)
|
||||
|> Enum.map(fn {{id, _}, j} ->
|
||||
{id, Enum.at([:up, :down, :left, :right], rem(floor(i / (4 ** j)), 4))}
|
||||
end)
|
||||
|> Enum.filter(fn {id, action} ->
|
||||
result = apply_actions(state, %{id => action})
|
||||
!snake_dies?(result, id)
|
||||
end)
|
||||
|> Map.new()
|
||||
end
|
||||
end
|
||||
|
||||
@spec evaluate_state(Genome.t(), GameState.t(), non_neg_integer(), float() | nil, float() | nil) :: float()
|
||||
def evaluate_state(genome, state, depth, alpha \\ Float.min_finite, beta \\ Float.max_finite)
|
||||
def evaluate_state(genome, %GameState{type: :v} = state, 0, _, _) do
|
||||
# If we're dead, the result is always super duper negative
|
||||
@ -104,11 +108,14 @@ defmodule Diamondtail.Brain do
|
||||
self = state.snakes[state.self]
|
||||
|
||||
Enum.count(enemies) * genome.enemy_alive_weight +
|
||||
Enum.count(enemies, &(&1.length >= self.length)) * genome.enemy_longer_weight +
|
||||
self.health * genome.own_health_weight +
|
||||
self.length * genome.own_length_weight +
|
||||
length(available_tiles_from(state, self.head)) * genome.own_accessible_tiles_weight +
|
||||
Enum.sum_by(enemies, &(&1.health)) * genome.enemy_health_weight +
|
||||
(Enum.sum_by(enemies, &(&1.length)) / (Enum.count(enemies) + 1)) * genome.enemy_length_weight +
|
||||
(Enum.map(enemies, &(abs(&1.head.x - self.head.x) + abs(&1.head.y - self.head.y))) |> Enum.min(&<=/2, fn -> 0 end)) * genome.enemy_head_distance_weight +
|
||||
(Enum.flat_map(enemies, &(if &1.length >= self.length, do: [abs(&1.head.x - self.head.x) + abs(&1.head.y - self.head.y)], else: [])) |> Enum.min(&<=/2, fn -> 0 end)) * genome.longer_enemy_head_distance_weight +
|
||||
(Enum.flat_map(enemies, &(if &1.length < self.length, do: [abs(&1.head.x - self.head.x) + abs(&1.head.y - self.head.y)], else: [])) |> Enum.min(&<=/2, fn -> 0 end)) * genome.shorter_enemy_head_distance_weight +
|
||||
(Enum.map(food, &(abs(&1.x - self.head.x) + abs(&1.y - self.head.y))) |> Enum.min(&<=/2, fn -> 0 end)) * genome.food_distance_weight
|
||||
else
|
||||
Float.min_finite()
|
||||
@ -130,9 +137,10 @@ defmodule Diamondtail.Brain do
|
||||
valid_actions = valid_actions(state)
|
||||
if valid_actions == [] do
|
||||
# Terminal state
|
||||
# We only win if this is a Q state AND we're still alive, this might still be a draw
|
||||
case state.type do
|
||||
:v -> Float.min_finite()
|
||||
:q -> Float.max_finite()
|
||||
:q -> if snake_dies?(state, state.self), do: IO.inspect(Float.min_finite()), else: Float.max_finite()
|
||||
end
|
||||
else
|
||||
{score, _alpha, _beta} = valid_actions(state)
|
||||
@ -188,15 +196,19 @@ defmodule Diamondtail.Brain do
|
||||
defp snake_dies?(state, snake_id) do
|
||||
snake = state.snakes[snake_id]
|
||||
|
||||
# Die if health is less than or equal to 0
|
||||
snake.health <= 0 ||
|
||||
# Die if head is out of bounds
|
||||
snake.head.x < 0 || snake.head.x >= state.width ||
|
||||
snake.head.y < 0 || snake.head.y >= state.height ||
|
||||
# Die if head is in a tail
|
||||
Enum.any?(state.snakes, fn {_, %{body: body}} -> Enum.member?(body, snake.head) end) ||
|
||||
# Die if head is on head of a DIFFERENT snake of equal or greater length
|
||||
Enum.any?(state.snakes, fn {id, %{head: h, length: l}} -> snake.head == h && snake.length <= l && id != snake_id end)
|
||||
if snake == nil do
|
||||
true
|
||||
else
|
||||
# Die if health is less than or equal to 0
|
||||
snake.health <= 0 ||
|
||||
# Die if head is out of bounds
|
||||
snake.head.x < 0 || snake.head.x >= state.width ||
|
||||
snake.head.y < 0 || snake.head.y >= state.height ||
|
||||
# Die if head is in a tail
|
||||
Enum.any?(state.snakes, fn {_, %{body: body}} -> Enum.member?(body, snake.head) end) ||
|
||||
# Die if head is on head of a DIFFERENT snake of equal or greater length
|
||||
Enum.any?(state.snakes, fn {id, %{head: h, length: l}} -> snake.head == h && l >= snake.length && id != snake_id end)
|
||||
end
|
||||
end
|
||||
|
||||
defp apply_action_to_snake(snake, move) do
|
||||
@ -211,6 +223,22 @@ defmodule Diamondtail.Brain do
|
||||
|> Map.update(:body, nil, fn body -> List.delete_at(body, 0) ++ [snake.head] end)
|
||||
|> Map.update(:head, nil, fn %{x: x, y: y} -> %{x: x + delta.x, y: y + delta.y} end)
|
||||
end
|
||||
|
||||
def available_tiles_from(state, %{x: x, y: y} = base_pos, explored \\ []) do
|
||||
Enum.reduce([%{x: x + 1, y: y}, %{x: x - 1, y: y}, %{x: x, y: y + 1}, %{x: x, y: y - 1}], [base_pos | explored], fn pos, acc ->
|
||||
if Enum.member?(acc, pos) || in_solid_or_out_of_bounds?(state, pos) do
|
||||
acc
|
||||
else
|
||||
available_tiles_from(state, pos, acc)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
defp in_solid_or_out_of_bounds?(state, %{x: x, y: y} = pos) do
|
||||
x >= state.width || y >= state.height ||
|
||||
x < 0 || y < 0 ||
|
||||
Enum.any?(state.snakes, fn {_, %{body: b, head: h}} -> h == pos || Enum.member?(b, pos) end)
|
||||
end
|
||||
end
|
||||
|
||||
@spec determine_move(Genome.t(), map(), map()) :: %{move: :up | :down | :left | :right, shout: String.t()}
|
||||
|
||||
@ -15,12 +15,15 @@ defmodule Diamondtail.Population do
|
||||
field :mutation_max_amplitude, float()
|
||||
|
||||
field :enemy_alive_weight, float()
|
||||
field :enemy_longer_weight, float()
|
||||
field :own_health_weight, float()
|
||||
field :own_length_weight, float()
|
||||
field :enemy_health_weight, float()
|
||||
field :enemy_length_weight, float()
|
||||
field :enemy_head_distance_weight, float()
|
||||
field :longer_enemy_head_distance_weight, float()
|
||||
field :shorter_enemy_head_distance_weight, float()
|
||||
field :food_distance_weight, float()
|
||||
field :own_accessible_tiles_weight, float()
|
||||
|
||||
field :search_depth, float()
|
||||
field :value_discount, float()
|
||||
@ -61,17 +64,21 @@ defmodule Diamondtail.Population do
|
||||
mutation_chance: random_between(0.1, 0.2),
|
||||
mutation_max_amplitude: random_between(0.2, 0.05),
|
||||
enemy_alive_weight: random_between(-100.0, -200.0),
|
||||
enemy_longer_weight: random_between(-50.0, -30.0), # Try to stay longer than our enemies to avoid dying to head-to-head collisions
|
||||
own_health_weight: random_between(0.7, 1.0),
|
||||
own_length_weight: random_between(5, 10),
|
||||
enemy_health_weight: random_between(-0.8, -0.4), # Summed
|
||||
enemy_length_weight: random_between(-10, -5), # Averaged
|
||||
|
||||
# both of the following are compared to the nearest object, to avoid overrewarding when there are more enemies/foods
|
||||
enemy_head_distance_weight: random_between(1, 2), # maximize distance, reward staying away
|
||||
food_distance_weight: random_between(-2, -1), # minimize distance, reward staying near
|
||||
longer_enemy_head_distance_weight: random_between(0.3, 1), # maximize distance, reward staying away
|
||||
shorter_enemy_head_distance_weight: random_between(-1, -0.3), # minimize distance, reward staying near to try to go in for kills
|
||||
food_distance_weight: random_between(-0.5, -0.1), # minimize distance, reward staying near, don't just stick next to food though
|
||||
|
||||
search_depth: random_between(3.0, 7.0),
|
||||
value_discount: random_between(1.0, 10.0) # as percentage
|
||||
own_accessible_tiles_weight: random_between(0.7, 1),
|
||||
|
||||
search_depth: random_between(3.0, 5.0),
|
||||
value_discount: random_between(1.0, 20.0) # as percentage
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user