How to resolve the algorithm Solve a Hidato puzzle step by step in the Elixir programming language

Published on 12 May 2024 09:40 PM

How to resolve the algorithm Solve a Hidato puzzle step by step in the Elixir programming language

Table of Contents

Problem Statement

The task is to write a program which solves Hidato (aka Hidoku) puzzles. The rules are: For example the following problem has the following solution, with path marked on it:

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Solve a Hidato puzzle step by step in the Elixir programming language

Source code in the elixir programming language

# Solve a Hidato Like Puzzle with Warnsdorff like logic applied
#
defmodule HLPsolver do
  defmodule Cell do
    defstruct value: -1, used: false, adj: []
  end
  
  def solve(str, adjacent, print_out\\true) do
    board = setup(str)
    if print_out, do: print(board, "Problem:")
    {start, _} = Enum.find(board, fn {_,cell} -> cell.value==1 end)
    board = set_adj(board, adjacent)
    zbl = for %Cell{value: n} <- Map.values(board), into: %{}, do: {n, true}
    try do
      solve(board, start, 1, zbl, map_size(board))
      IO.puts "No solution"
    catch
      {:ok, result} -> if print_out, do: print(result, "Solution:"),
                                   else: result
    end
  end
  
  defp solve(board, position, seq_num, zbl, goal) do
    value = board[position].value
    cond do
      value > 0 and value != seq_num -> nil
      value == 0 and zbl[seq_num] -> nil
      true ->
        cell = %Cell{board[position] | value: seq_num, used: true}
        board = %{board | position => cell}
        if seq_num == goal, do: throw({:ok, board})
        Enum.each(wdof(board, cell.adj), fn pos ->
          solve(board, pos, seq_num+1, zbl, goal)
        end)
    end
  end
  
  defp setup(str) do
    lines = String.strip(str) |> String.split(~r/(\n|\r\n|\r)/) |> Enum.with_index
    for {line,i} <- lines, {char,j} <- Enum.with_index(String.split(line)),
        :error != Integer.parse(char), into: %{} do
          {n,_} = Integer.parse(char)
          {{i,j}, %Cell{value: n}}
        end
  end
  
  defp set_adj(board, adjacent) do
    Enum.reduce(Map.keys(board), board, fn {x,y},map ->
      adj = Enum.map(adjacent, fn {i,j} -> {x+i, y+j} end)
            |> Enum.reduce([], fn pos,acc -> if board[pos], do: [pos | acc], else: acc end)
      Map.update!(map, {x,y}, fn cell -> %Cell{cell | adj: adj} end)
    end)
  end
  
  defp wdof(board, adj) do              # Warnsdorf's rule
    Enum.reject(adj, fn pos -> board[pos].used end)
    |> Enum.sort_by(fn pos ->
         Enum.count(board[pos].adj, fn p -> not board[p].used end)
       end)
  end
  
  def print(board, title) do
    IO.puts "\n#{title}"
    {xmin, xmax} = Map.keys(board) |> Enum.map(fn {x,_} -> x end) |> Enum.min_max
    {ymin, ymax} = Map.keys(board) |> Enum.map(fn {_,y} -> y end) |> Enum.min_max
    len = map_size(board) |> to_char_list |> length
    space = String.duplicate(" ", len)
    Enum.each(xmin..xmax, fn x ->
      Enum.map_join(ymin..ymax, " ", fn y ->
        case Map.get(board, {x,y}) do
          nil  -> space
          cell -> to_string(cell.value) |> String.rjust(len)
        end
      end)
      |> IO.puts
    end)
  end
end


adjacent = [{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}]

"""
  .  4
  0  7  0
  1  0  0
"""
|> HLPsolver.solve(adjacent)

"""
  0 33 35  0  0
  0  0 24 22  0
  0  0  0 21  0  0
  0 26  0 13 40 11
 27  0  0  0  9  0  1
  .  .  0  0 18  0  0
  .  .  .  .  0  7  0  0
  .  .  .  .  .  .  5  0
"""
|> HLPsolver.solve(adjacent)

"""
  1  0  0  .  0  0  0  .  0  0  0  .  0  0  0  .  0  0  0  .  0  0  0  .  0  0  0
  .  .  0  .  0  .  0  .  0  .  0  .  0  .  0  .  0  .  0  .  0  .  0  .  0  .  0
  .  .  0  0  0  .  0  0  0  .  0  0  0  .  0  0  0  .  0  0  0  .  0  0  0  .  0
"""
|> HLPsolver.solve(adjacent)


  

You may also check:How to resolve the algorithm Catamorphism step by step in the Erlang programming language
You may also check:How to resolve the algorithm Roman numerals/Encode step by step in the Tailspin programming language
You may also check:How to resolve the algorithm Factorial step by step in the Verilog programming language
You may also check:How to resolve the algorithm Knuth shuffle step by step in the PARI/GP programming language
You may also check:How to resolve the algorithm Strip whitespace from a string/Top and tail step by step in the Forth programming language