Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us
Notesclub

Untitled notebook

bot/livebook-annotated.livemd

Untitled notebook

Section

Bot.show({1, 1})
defmodule Rover do
  # Define a struct which describes the model of the bots state
  defstruct location: {0, 0}, heading: :north, history: []

  def new do
    # __struct__()
    %__MODULE__{}
  end

  # move the robot forward from current position, record that position
  # into the head of `history`
  def forward(rover) do
    %{
      rover
      | location: move(rover.location, rover.heading),
        history: [rover.location | rover.history]
    }
  end

  def left(%{heading: h} = rover) do
    # Based on previous heading, rotate the robot to the
    # appropriate cardinal direction
    case h do
      :north -> %{rover | heading: :west}
      :west -> %{rover | heading: :south}
      :south -> %{rover | heading: :east}
      :east -> %{rover | heading: :north}
    end
  end

  def right(%{heading: h} = rover) do
    # Based on previous heading, rotate the robot to the
    # appropriate cardinal direction
    case h do
      :north -> %{rover | heading: :east}
      :east -> %{rover | heading: :south}
      :south -> %{rover | heading: :west}
      :west -> %{rover | heading: :north}
    end
  end

  def show(rover) do
    Bot.show(rover)
  end

  # Increment x or y coords of the robot's location given the heading
  defp move({x, y}, :north) do
    {x, y - 1}
  end

  defp move({x, y}, :east) do
    {x + 1, y}
  end

  defp move({x, y}, :south) do
    {x, y + 1}
  end

  defp move({x, y}, :west) do
    {x - 1, y}
  end

  # Same as above functions, but handles via a case block
  # defp move({ x, y }, heading) do
  #   case heading do
  #     :north -> { x, y - 1 }
  #     :east -> { x + 1, y }
  #     :south -> { x, y + 1 }
  #     :west -> { x - 1, y }
  #   end
  # end

  def go(rover, str) do
    case str do
      "f" -> forward(rover)
      "r" -> right(rover)
      "l" -> left(rover)
    end
  end

  def all(rover, string) do
    steps = String.graphemes(string)
    Enum.reduce(steps, rover, fn step, acc -> go(acc, step) end)
  end
end
# Move the rover around, then show it
Rover.new()
|> Rover.forward()
|> Rover.forward()
|> Rover.forward()
|> Rover.forward()
|> Rover.right()
|> Rover.forward()
|> Rover.forward()
|> Rover.right()
|> Rover.right()
|> Rover.forward()
|> Rover.forward()
|> Rover.forward()
|> Rover.forward()
|> Rover.forward()
|> Rover.forward()
|> Rover.show()
# Do the same as above, but use the go functionsions case switching
Rover.new()
|> Rover.go("f")
|> Rover.go("f")
|> Rover.go("r")
|> Rover.go("f")
|> Rover.go("f")
|> Rover.go("l")
|> Rover.go("f")
|> Rover.go("f")
|> Rover.show()
# Expand on the go example, by way of enumerating the string `track` which in turn feeds `go`
track = "fffrfffrfff"

Rover.new()
|> Rover.all(track)
|> Rover.show()
defmodule Chain do
  def new do
    # (C)RC
    {}
  end

  def add(chain, item) do
    {item, chain}
  end

  def head({first, _rest}) do
    first
  end

  def head({}) do
    raise "Can't take the `head` of empty chain"
  end

  def tail({_first, rest}) do
    rest
  end

  def show({}) do
    ""
  end

  def show({head, rest}) do
    inspect(head) <> "-" <> show(rest)
  end

  def total({head, rest}) do
    head + total(rest)
  end

  def total({}) do
    0
  end

  def count({_head, rest}) do
    1 + count(rest)
  end

  def count({}) do
    0
  end

  def reduce({}, acc, _reducer) do
    acc
  end

  def reduce({head, rest}, acc, reducer) do
    new_acc = reducer.(head, acc)
    reduce(rest, new_acc, reducer)
  end
end
# Create a new chain, add items thereto, then return the head of the chain
Chain.new()
|> Chain.add(3)
|> Chain.add(2)
|> Chain.add(1)
|> Chain.head()
# What happens trying to get `head` of an empty chain?
# Depends on if we're handling it (line 15 above)
# By default, FunctionClauseError

Chain.new()
|> Chain.head()
# Create a new chain, add items thereto, then return the tail of the chain
Chain.new()
|> Chain.add(3)
|> Chain.add(2)
|> Chain.add(1)
|> Chain.tail()
# Test an empty chain condition for `show`
Chain.new()
|> Chain.show()
# Populate a chain, and pipe it through the `show` function
Chain.new()
|> Chain.add(3)
|> Chain.add(2)
|> Chain.add(1)
|> Chain.show()
# Test an empty chain condition for `total`
Chain.new()
|> Chain.total()
# Populate a chain and `total` it
Chain.new()
|> Chain.add(3)
|> Chain.add(2)
|> Chain.add(1)
|> Chain.total()
# Test an empty chain for `reduce`
chain = Chain.new()

Chain.reduce(chain, 0, fn i, acc -> i + acc end)
# Populate a chain and reduce it. Here, we pass an anon reducer function 
# which is doing simple addition
chain =
  Chain.new()
  |> Chain.add(3)
  |> Chain.add(2)
  |> Chain.add(1)

Chain.reduce(chain, 0, fn i, acc -> i + acc end)