Created
March 28, 2017 14:14
-
-
Save Nagasaki45/f2216bde319b8e3d0f9a31e3f3c59c24 to your computer and use it in GitHub Desktop.
Elixir solution to the UdiMaze
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule UdiMaze do | |
@moduledoc """ | |
A solver for UdiMaze pazzle. | |
Issues: | |
- I get 404 if omitting the last slash. | |
- Took me some time to understand the task. It can be documented better. | |
- Didn't use the `x` and `y` values at all. Without knowing the size of the | |
maze I can't think of an algorithm that can use them. | |
Run this from the terminal with: | |
mix run -e UdiMaze.run | |
""" | |
@base_url 'http://139.59.154.221' | |
defstruct( | |
maze_id: "", | |
path_heads: [], # codes | |
rooms: Map.new, # code to score | |
) | |
@doc """ | |
Go to the server to create a new UdiMaze. | |
""" | |
def new do | |
{:ok, %{body: body}} = HTTPoison.post(@base_url, "{}") | |
{:ok, json} = Poison.decode(body) | |
%__MODULE__{ | |
maze_id: json["maze_id"], | |
path_heads: [json["start"]], | |
} | |
end | |
@doc """ | |
Traverse the UdiMaze. | |
""" | |
def traverse(maze) do | |
new_maze = step_all_paths(maze) | |
# Couldn't find more rooms in the last step | |
if new_maze.rooms == maze.rooms do | |
maze | |
else | |
traverse(new_maze) | |
end | |
end | |
defp step_all_paths(maze) do | |
discoveries = | |
maze.path_heads | |
|> Task.async_stream(&(discover_room(maze.maze_id, &1))) | |
|> Enum.map(fn {:ok, value} -> value end) | |
%__MODULE__{ | |
maze | | |
rooms: | |
maze.path_heads | |
|> Stream.zip(for x <- discoveries, do: x["score"]) | |
|> Enum.into(Map.new) | |
|> Map.merge(maze.rooms), | |
path_heads: | |
discoveries | |
|> Stream.flat_map(&(&1["exits"])) | |
|> Stream.map(&(&1["code"])) | |
|> Enum.filter(&(!Map.has_key?(maze.rooms, &1))), | |
} | |
end | |
defp discover_room(maze_id, room) do | |
url = "#{@base_url}/#{maze_id}/#{room}/" | |
{:ok, %{body: body}} = HTTPoison.get(url) | |
{:ok, json} = Poison.decode(body) | |
json | |
end | |
@doc """ | |
Check the solution. | |
""" | |
def check_result(maze) do | |
score = | |
maze.rooms | |
|> Map.values() | |
|> Enum.sum() | |
url = "#{@base_url}/solve/#{maze.maze_id}/#{score}/" | |
{:ok, %{body: body}} = HTTPoison.post(url, "{}") | |
{:ok, json} = Poison.decode(body) | |
json | |
end | |
@doc """ | |
A runner for the UdiMaze. It gets new maze from the server, | |
traverse (async), and print the results. | |
""" | |
def run do | |
new() | |
|> traverse() | |
|> check_result() | |
|> IO.inspect() | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment