lib/genetix/problems/n_queens.ex

defmodule Genetix.Problems.NQueens do
  @moduledoc """
  A specific genetic problem implementation for NQueens.
  The N Queen is a combinatorial optimization problem, the objective is to configure NQueens on chess board so that no queen theatens another.any()

  Hyperparameters

    - `size` number of queens. Default `8`.

  ## Examples

      iex> Genetix.Evolution.run(Genetix.Problems.NQueens, size: 8)

  """
  @behaviour Genetix.Problem
  alias Genetix.Types.Chromosome

  @impl true
  @doc """
  Genotype implementation for NQueen problem. Permutation.
  """
  def genotype(opts \\ []) do
    size = Keyword.get(opts, :size, 8)
    genes = Enum.shuffle(0..(size - 1))
    %Chromosome{genes: genes, size: size}
  end

  @impl true
  @doc """
  Fitness function implementation for NQueen problem.
  """
  def fitness_function(chromosome, opts \\ []) do
    size = Keyword.get(opts, :size, 8)

    diag_clashes =
      for i <- 0..(size - 1), j <- 0..(size - 1) do
        if i != j do
          dx = abs(i - j)

          dy =
            abs(
              chromosome.genes
              |> Enum.at(i)
              |> Kernel.-(Enum.at(chromosome.genes, j))
            )

          if dx == dy do
            1
          else
            0
          end
        else
          0
        end
      end

    length(Enum.uniq(chromosome.genes)) - Enum.sum(diag_clashes)
  end

  @impl true
  @doc """
  Terminate implementation for NQueen problem.
  """
  def terminate?([best | _], _generation, _opts \\ []) do
    IO.write("\r#{inspect(best.fitness)}")
    best.fitness == best.size
  end
end