diff --git a/airesources/Elixir/config/config.exs b/airesources/Elixir/config/config.exs new file mode 100644 index 000000000..f6b4a35f6 --- /dev/null +++ b/airesources/Elixir/config/config.exs @@ -0,0 +1,30 @@ +# This file is responsible for configuring your application +# and its dependencies with the aid of the Mix.Config module. +use Mix.Config + +# This configuration is loaded before any dependency and is restricted +# to this project. If another project depends on this project, this +# file won't be loaded nor affect the parent project. For this reason, +# if you want to provide default values for your application for +# 3rd-party users, it should be done in your "mix.exs" file. + +# You can configure for your application as: +# +# config :halite_elixir_starter_pack, key: :value +# +# And access this configuration in your application as: +# +# Application.get_env(:halite_elixir_starter_pack, :key) +# +# Or configure a 3rd-party app: +# +# config :logger, level: :info +# + +# It is also possible to import configuration files, relative to this +# directory. For example, you can emulate configuration per environment +# by uncommenting the line below and defining dev.exs, test.exs and such. +# Configuration from the imported file will override the ones defined +# here (which is why it is important to import them last). +# +# import_config "#{Mix.env}.exs" diff --git a/airesources/Elixir/lib/MyBot.ex b/airesources/Elixir/lib/MyBot.ex new file mode 100644 index 000000000..f171e9b6d --- /dev/null +++ b/airesources/Elixir/lib/MyBot.ex @@ -0,0 +1,15 @@ +defmodule MyBot do + defp loop(id, game_map) do + GameMap.locations(game_map) + |> Enum.filter(&(GameMap.get_site(game_map, &1).owner == id)) + |> Enum.map(fn(location) -> {location, Enum.random(Direction.directions)} end) + |> Networking.send_frame + loop(id, Networking.get_frame(game_map)) + end + + def main do + {id, game_map} = Networking.get_init + Networking.send_init "ElixirBot" + loop(id, Networking.get_frame(game_map)) + end +end \ No newline at end of file diff --git a/airesources/Elixir/lib/RandomBot.ex b/airesources/Elixir/lib/RandomBot.ex new file mode 100644 index 000000000..897ecd727 --- /dev/null +++ b/airesources/Elixir/lib/RandomBot.ex @@ -0,0 +1,15 @@ +defmodule RandomBot do + defp loop(id, game_map) do + GameMap.locations(game_map) + |> Enum.filter(&(GameMap.get_site(game_map, &1).owner == id)) + |> Enum.map(fn(location) -> {location, Enum.random(Direction.directions)} end) + |> Networking.send_frame + loop(id, Networking.get_frame(game_map)) + end + + def main do + {id, game_map} = Networking.get_init + Networking.send_init "ElixirBot" + loop(id, Networking.get_frame(game_map)) + end +end \ No newline at end of file diff --git a/airesources/Elixir/lib/direction.ex b/airesources/Elixir/lib/direction.ex new file mode 100644 index 000000000..0659c480e --- /dev/null +++ b/airesources/Elixir/lib/direction.ex @@ -0,0 +1,10 @@ +defmodule Direction do + def still, do: 0 + def north, do: 1 + def east, do: 2 + def south, do: 3 + def west, do: 4 + + def directions, do: 0..4 + def cardinals, do: 1..4 +end \ No newline at end of file diff --git a/airesources/Elixir/lib/game_map.ex b/airesources/Elixir/lib/game_map.ex new file mode 100644 index 000000000..5262f040b --- /dev/null +++ b/airesources/Elixir/lib/game_map.ex @@ -0,0 +1,71 @@ +defmodule GameMap do + defstruct [:width, :height, :map] + + def locations(width, height) do + for y <- 0..height-1, x <- 0..width-1, do: %Location{x: x, y: y} + end + + def locations(game_map) do + locations(game_map.width, game_map.height) + end + + def in_bounds(game_map, location) do + location.x in 0..game_map.width-1 and + location.y in 0..game_map.height-1 + end + + def get_distance(game_map, loc_a, loc_b) do + dx = abs(loc_a.x - loc_b.x) + dy = abs(loc_a.y - loc_b.y) + dx = if dx > game_map.width / 2, do: game_map.width - dx, else: dx + dy = if dy > game_map.height / 2, do: game_map.height - dy, else: dy + dx + dy + end + + def get_angle(game_map, loc_a, loc_b) do + dx = loc_a.x - loc_b.x + dy = loc_a.y - loc_b.y + dx = cond do + dx > game_map.width - dx -> dx - game_map.width + -dx > game_map.width + dx -> dx + game_map.width + end + dy = cond do + dy > game_map.height - dy -> dy - game_map.height + -dy > game_map.height + dy -> dy + game_map.height + end + :math.atan2(dy, dx) + end + + defp wrap(a, b) do + rem(a + b, b) + end + + + def get_location(game_map, location, direction) + #still + def get_location(game_map, location, 0), do: location + + # north + def get_location(game_map, location, 1) do + %Location{x: location.x, y: wrap(location.y - 1, game_map.height)} + end + + # east + def get_location(game_map, location, 2) do + %Location{x: wrap(location.x + 1, game_map.width), y: location.y} + end + + # south + def get_location(game_map, location, 3) do + %Location{x: location.x, y: wrap(location.y + 1, game_map.height)} + end + + # west + def get_location(game_map, location, 4) do + %Location{x: wrap(location.x - 1, game_map.width), y: location.y} + end + + def get_site(game_map, location, direction \\ 0) do + game_map.map[get_location(game_map, location, direction)] + end +end \ No newline at end of file diff --git a/airesources/Elixir/lib/location.ex b/airesources/Elixir/lib/location.ex new file mode 100644 index 000000000..8ceb1cac4 --- /dev/null +++ b/airesources/Elixir/lib/location.ex @@ -0,0 +1,3 @@ +defmodule Location do + defstruct [:x, :y] +end \ No newline at end of file diff --git a/airesources/Elixir/lib/networking.ex b/airesources/Elixir/lib/networking.ex new file mode 100644 index 000000000..9b80b92e6 --- /dev/null +++ b/airesources/Elixir/lib/networking.ex @@ -0,0 +1,78 @@ +defmodule Networking do + defp get_string do + IO.gets("") + |> String.strip + end + + defp send_string(string) do + IO.puts string + end + + defp int_split(string) do + String.split(string) + |> Enum.map(fn(s) -> + Integer.parse(s) + |> elem(0) + end) + end + + defp serialize_move_set(moves) do + Enum.map(moves, fn({l, d}) -> + "#{l.x} #{l.y} #{d}" + end) + |> Enum.join(" ") + end + + defp deserialize_game_map_size(string) do + int_split(string) + |> List.to_tuple + end + + defp deserialize_productions(string, width, height) do + locations = GameMap.locations(width, height) + productions = int_split(string) + map = Enum.zip(locations, productions) + |> Map.new(fn({location, production}) -> + {location, %Site{production: production}} + end) + %GameMap{width: width, height: height, map: map} + end + + defp deserialize_game_map(string, game_map) do + split = int_split(string) + idx = length(split) - game_map.width * game_map.height + {owners, strengths} = Enum.split(split, idx) + owners = Enum.chunk(owners, 2) + |> Enum.flat_map(fn([count, tag]) -> + List.duplicate(tag, count) + end) + locations = GameMap.locations(game_map) + map = List.zip([locations, owners, strengths]) + |> Enum.reduce(game_map.map, fn({location, owner, strength}, acc) -> + Map.update!(acc, location, fn(site) -> + %Site{site | owner: owner, strength: strength} + end) + end) + %GameMap{game_map | map: map} + end + + def get_init do + {player_tag, _} = Integer.parse(get_string) + {width, height} = deserialize_game_map_size(get_string) + game_map = deserialize_productions(get_string, width, height) + game_map = deserialize_game_map(get_string, game_map) + {player_tag, game_map} + end + + def send_init(name) do + send_string(name) + end + + def get_frame(game_map) do + deserialize_game_map(get_string, game_map) + end + + def send_frame(moves) do + send_string(serialize_move_set(moves)) + end +end \ No newline at end of file diff --git a/airesources/Elixir/lib/site.ex b/airesources/Elixir/lib/site.ex new file mode 100644 index 000000000..1ed030c81 --- /dev/null +++ b/airesources/Elixir/lib/site.ex @@ -0,0 +1,3 @@ +defmodule Site do + defstruct [:owner, :strength, :production] +end \ No newline at end of file diff --git a/airesources/Elixir/mix.exs b/airesources/Elixir/mix.exs new file mode 100644 index 000000000..dcf879b02 --- /dev/null +++ b/airesources/Elixir/mix.exs @@ -0,0 +1,32 @@ +defmodule Halite.Mixfile do + use Mix.Project + + def project do + [app: :elixirbot, + version: "0.1.0", + elixir: "~> 1.3", + build_embedded: Mix.env == :prod, + start_permanent: Mix.env == :prod, + deps: deps()] + end + + # Configuration for the OTP application + # + # Type "mix help compile.app" for more information + def application do + [applications: [:logger]] + end + + # Dependencies can be Hex packages: + # + # {:mydep, "~> 0.3.0"} + # + # Or git/path repositories: + # + # {:mydep, git: "https://github.com/elixir-lang/mydep.git", tag: "0.1.0"} + # + # Type "mix help deps" for more examples and options + defp deps do + [] + end +end diff --git a/airesources/Elixir/runGame.bat b/airesources/Elixir/runGame.bat new file mode 100644 index 000000000..bbbe5bceb --- /dev/null +++ b/airesources/Elixir/runGame.bat @@ -0,0 +1,2 @@ +mix compile +./halite -d "30 30" "mix run -e MyBot.main" "mix run -e RandomBot.main" diff --git a/airesources/Elixir/runGame.sh b/airesources/Elixir/runGame.sh new file mode 100755 index 000000000..42986e4e5 --- /dev/null +++ b/airesources/Elixir/runGame.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +mix compile +./halite -d "30 30" "mix run -e MyBot.main" "mix run -e RandomBot.main"