some tweaks
This commit is contained in:
parent
31e179a74a
commit
c213507aec
@ -68,14 +68,17 @@ defmodule Diamondtail.Brain do
|
||||
else
|
||||
{id, s}
|
||||
end
|
||||
end)
|
||||
end) |> Map.new()
|
||||
end)
|
||||
|> resolve_state()
|
||||
end
|
||||
|
||||
def valid_actions(%GameState{type: :v, snakes: snakes, self: self}) do
|
||||
def valid_actions(%GameState{type: :v, snakes: snakes, self: self} = state) do
|
||||
if Map.has_key?(snakes, self) do
|
||||
[:up, :down, :left, :right]
|
||||
[:up, :down, :left, :right] |> Enum.filter(fn action ->
|
||||
result = apply_actions(state, action)
|
||||
!snake_dies?(result, self)
|
||||
end)
|
||||
else
|
||||
[]
|
||||
end
|
||||
@ -102,7 +105,9 @@ defmodule Diamondtail.Brain do
|
||||
|
||||
Enum.count(enemies) * genome.enemy_alive_weight +
|
||||
self.health * genome.own_health_weight +
|
||||
self.length * genome.own_length_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.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
|
||||
@ -124,10 +129,10 @@ defmodule Diamondtail.Brain do
|
||||
|
||||
valid_actions = valid_actions(state)
|
||||
if valid_actions == [] do
|
||||
if Map.has_key?(state.snakes, state.self) do
|
||||
Float.max_finite()
|
||||
else
|
||||
Float.min_finite()
|
||||
# Terminal state
|
||||
case state.type do
|
||||
:v -> Float.min_finite()
|
||||
:q -> Float.max_finite()
|
||||
end
|
||||
else
|
||||
{score, _alpha, _beta} = valid_actions(state)
|
||||
@ -174,20 +179,26 @@ defmodule Diamondtail.Brain do
|
||||
end)
|
||||
# Eliminate snakes
|
||||
|> Map.update(:snakes, nil, fn snakes ->
|
||||
Enum.filter(snakes, fn {snake_id, snake} ->
|
||||
# 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)
|
||||
Enum.filter(snakes, fn {snake_id, _snake} ->
|
||||
!snake_dies?(state, snake_id)
|
||||
end) |> Map.new()
|
||||
end)
|
||||
end
|
||||
|
||||
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)
|
||||
end
|
||||
|
||||
defp apply_action_to_snake(snake, move) do
|
||||
delta = case move do
|
||||
:up -> %{x: 0, y: 1}
|
||||
@ -211,6 +222,12 @@ defmodule Diamondtail.Brain do
|
||||
{action, GameState.evaluate_state(genome, qstate, ceil(genome.search_depth))}
|
||||
end, ordered: false)
|
||||
|
||||
if Enum.empty?(options) do
|
||||
%{
|
||||
move: :left,
|
||||
shout: "I'm dead, good game!"
|
||||
}
|
||||
else
|
||||
{:ok, {action, score}} = Enum.max_by(options, fn {:ok, {_, s}} -> s end)
|
||||
|
||||
%{
|
||||
@ -219,3 +236,4 @@ defmodule Diamondtail.Brain do
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -16,7 +16,9 @@ defmodule Diamondtail.Population do
|
||||
|
||||
field :enemy_alive_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 :food_distance_weight, float()
|
||||
|
||||
@ -57,10 +59,12 @@ defmodule Diamondtail.Population do
|
||||
def random() do
|
||||
%Genome{
|
||||
mutation_chance: random_between(0.1, 0.2),
|
||||
mutation_max_amplitude: random_between(0.1, 0.05),
|
||||
mutation_max_amplitude: random_between(0.2, 0.05),
|
||||
enemy_alive_weight: random_between(-100.0, -200.0),
|
||||
own_health_weight: random_between(0.7, 1.0),
|
||||
enemy_health_weight: random_between(-0.8, -0.4),
|
||||
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
|
||||
|
||||
@ -18,7 +18,7 @@ defmodule Diamondtail.Router do
|
||||
|> send_resp(200, JSON.encode!(%{
|
||||
apiversion: "1",
|
||||
author: "kodicraft",
|
||||
color: "#8cd9ff",
|
||||
color: "#4684ff",
|
||||
head: "trans-rights-scarf",
|
||||
tail: "hook",
|
||||
version: Mix.Project.config()[:version]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user