# `Yog.Pathfinding.Path`
[🔗](https://github.com/code-shoily/yog_ex/blob/v0.97.0/lib/yog/pathfinding/path.ex#L1)

Result of pathfinding algorithms (Dijkstra, A*, BFS, etc.).

Represents a path through the graph as a sequence of nodes with
a total weight and metadata about how the path was found.

## Fields

- `nodes` - Ordered list of node IDs forming the path
- `weight` - Total weight/cost of the path
- `algorithm` - Name of the algorithm used (optional)
- `metadata` - Optional metadata (visited nodes, iterations, time, etc.)

## Examples

    iex> path = %Yog.Pathfinding.Path{
    ...>   nodes: [1, 2, 3, 4],
    ...>   weight: 15.5,
    ...>   algorithm: :dijkstra
    ...> }
    iex> path.weight
    15.5
    iex> Yog.Pathfinding.Path.length(path)
    3
    iex> Yog.Pathfinding.Path.start(path)
    1
    iex> Yog.Pathfinding.Path.finish(path)
    4

# `t`

```elixir
@type t() :: %Yog.Pathfinding.Path{
  algorithm: atom(),
  metadata: map(),
  nodes: [Yog.Model.node_id()],
  weight: any()
}
```

# `at`

```elixir
@spec at(t(), non_neg_integer()) :: Yog.Model.node_id() | nil
```

Returns the node at a specific position in the path (0-indexed).

Returns `nil` if the index is out of bounds.

## Examples

    iex> path = Yog.Pathfinding.Path.new([1, 2, 3], 10)
    iex> Yog.Pathfinding.Path.at(path, 0)
    1
    iex> Yog.Pathfinding.Path.at(path, 2)
    3
    iex> Yog.Pathfinding.Path.at(path, 5)
    nil

# `contains?`

```elixir
@spec contains?(t(), Yog.Model.node_id()) :: boolean()
```

Checks if a node is part of the path.

## Examples

    iex> path = Yog.Pathfinding.Path.new([1, 2, 3], 10)
    iex> Yog.Pathfinding.Path.contains?(path, 2)
    true
    iex> Yog.Pathfinding.Path.contains?(path, 5)
    false

# `empty?`

```elixir
@spec empty?(t()) :: boolean()
```

Checks if the path is empty (contains no nodes).

## Examples

    iex> path = Yog.Pathfinding.Path.new([], 0)
    iex> Yog.Pathfinding.Path.empty?(path)
    true
    iex> path = Yog.Pathfinding.Path.new([1, 2], 5)
    iex> Yog.Pathfinding.Path.empty?(path)
    false

# `finish`

```elixir
@spec finish(t()) :: Yog.Model.node_id() | nil
```

Returns the ending node of the path.

Returns `nil` if the path is empty.

## Examples

    iex> path = Yog.Pathfinding.Path.new([1, 2, 3], 10)
    iex> Yog.Pathfinding.Path.finish(path)
    3
    iex> path = Yog.Pathfinding.Path.new([], 0)
    iex> Yog.Pathfinding.Path.finish(path)
    nil

# `hydrate_path`

```elixir
@spec hydrate_path(Yog.Model.graph(), [Yog.Model.node_id()]) :: list()
```

Hydrates a path of node IDs with their corresponding edge attributes from the graph.

This function transforms a list of node IDs representing a path (e.g., `[A, B, C]`)
into a list of edge triplets `{u, v, data}` by looking up the edge
metadata for each consecutive pair in the graph.

This is particularly useful when you have a sequence of nodes (from a pathfinding
algorithm) and you need to "hydrate" it with the actual edge weights or
attributes used to traverse it.

## Examples

    iex> graph =
    ...>   Yog.directed()
    ...>   |> Yog.add_edge_ensure(from: 1, to: 2, with: 10, default: nil)
    ...>   |> Yog.add_edge_ensure(from: 2, to: 3, with: 5, default: nil)
    iex> path = [1, 2, 3]
    iex> Yog.Pathfinding.Path.hydrate_path(graph, path)
    [{1, 2, 10}, {2, 3, 5}]

# `length`

```elixir
@spec length(t()) :: non_neg_integer()
```

Returns the length of the path (number of edges).

The length is the number of nodes minus 1. An empty path or
single-node path has length 0.

## Examples

    iex> path = Yog.Pathfinding.Path.new([1, 2, 3, 4], 15)
    iex> Yog.Pathfinding.Path.length(path)
    3
    iex> path = Yog.Pathfinding.Path.new([1], 0)
    iex> Yog.Pathfinding.Path.length(path)
    0
    iex> path = Yog.Pathfinding.Path.new([], 0)
    iex> Yog.Pathfinding.Path.length(path)
    0

# `new`

```elixir
@spec new([Yog.Model.node_id()], any()) :: t()
```

Creates a new path result.

## Examples

    iex> path = Yog.Pathfinding.Path.new([1, 2, 3], 10)
    iex> path.nodes
    [1, 2, 3]
    iex> path.weight
    10

# `new`

```elixir
@spec new([Yog.Model.node_id()], any(), atom()) :: t()
```

Creates a new path result with algorithm name.

## Examples

    iex> path = Yog.Pathfinding.Path.new([1, 2, 3], 10, :dijkstra)
    iex> path.algorithm
    :dijkstra

# `new`

```elixir
@spec new([Yog.Model.node_id()], any(), atom(), map()) :: t()
```

Creates a new path result with algorithm and metadata.

## Examples

    iex> path = Yog.Pathfinding.Path.new([1, 2, 3], 10, :astar, %{visited: 42})
    iex> path.metadata
    %{visited: 42}

# `reverse`

```elixir
@spec reverse(t()) :: t()
```

Reverses the path (both node order and preserves weight).

## Examples

    iex> path = Yog.Pathfinding.Path.new([1, 2, 3], 10, :dijkstra)
    iex> reversed = Yog.Pathfinding.Path.reverse(path)
    iex> reversed.nodes
    [3, 2, 1]
    iex> reversed.weight
    10
    iex> reversed.algorithm
    :dijkstra

# `start`

```elixir
@spec start(t()) :: Yog.Model.node_id() | nil
```

Returns the starting node of the path.

Returns `nil` if the path is empty.

## Examples

    iex> path = Yog.Pathfinding.Path.new([1, 2, 3], 10)
    iex> Yog.Pathfinding.Path.start(path)
    1
    iex> path = Yog.Pathfinding.Path.new([], 0)
    iex> Yog.Pathfinding.Path.start(path)
    nil

---

*Consult [api-reference.md](api-reference.md) for complete listing*
