How to resolve the algorithm Langton's ant step by step in the Elm programming language

Published on 12 May 2024 09:40 PM

How to resolve the algorithm Langton's ant step by step in the Elm programming language

Table of Contents

Problem Statement

Langton's ant is a cellular automaton that models an ant sitting on a plane of cells, all of which are white initially, the ant facing in one of four directions. Each cell can either be black or white. The ant moves according to the color of the cell it is currently sitting in, with the following rules: This rather simple ruleset leads to an initially chaotic movement pattern, and after about 10000 steps, a cycle appears where the ant moves steadily away from the starting location in a diagonal corridor about 10 cells wide.
Conceptually the ant can then walk infinitely far away.

Start the ant near the center of a 100x100 field of cells, which is about big enough to contain the initial chaotic part of the movement. Follow the movement rules for the ant, terminate when it moves out of the region, and show the cell colors it leaves behind.

The problem has received some analysis; for more details, please take a look at the Wikipedia article   (a link is below)..

Let's start with the solution:

Step by Step solution about How to resolve the algorithm Langton's ant step by step in the Elm programming language

Source code in the elm programming language

import Maybe as M
import Matrix 
import Time exposing (Time, every, second)
import List exposing (..)
import String exposing (join)
import Html exposing (div, h1, text)
import Html.App exposing (program)
import Svg 
import Svg.Attributes exposing (version, viewBox, cx, cy, r, x, y, x1, y1, x2, y2, fill,style, width, height, preserveAspectRatio)

w = 700
h = 700
dt = 0.0001

type Direction = North | West | South | East

type alias Model =
  { rows : Int
  , cols : Int
  , boxes : Matrix.Matrix Bool
  , location : Matrix.Location
  , direction : Direction
  }

initModel : Int -> Int -> Model
initModel cols rows = 
     { rows = rows
     , cols = cols 
     , boxes = Matrix.matrix rows cols (\location -> False)
     , location = (rows//2,cols//2)
     , direction = North
     }

view model =
  let
    borderLineStyle = style "stroke:black;stroke-width:0.3"

    x1Min = x1 <| toString 0
    y1Min = y1 <| toString 0
    x1Max = x1 <| toString model.cols
    y1Max = y1 <| toString model.rows
    x2Min = x2 <| toString 0
    y2Min = y2 <| toString 0
    x2Max = x2 <| toString model.cols
    y2Max = y2 <| toString model.rows

    borders = [ Svg.line [ x1Min, y1Min, x2Max, y2Min, borderLineStyle ] []
              , Svg.line [ x1Max, y1Min, x2Max, y2Max, borderLineStyle ] []
              , Svg.line [ x1Max, y1Max, x2Min, y2Max, borderLineStyle ] []
              , Svg.line [ x1Min, y1Max, x2Min, y2Min, borderLineStyle ] []
              ]

    circleInBox (row,col) color = 
      Svg.circle [ r "0.25"
      , fill (color)
      , cx (toString (toFloat col + 0.5))
      , cy (toString (toFloat row + 0.5))
      ] [] 

    showUnvisited location box =
       if box then [circleInBox location "black" ]
              else []

    unvisited = model.boxes 
                  |> Matrix.mapWithLocation showUnvisited 
                  |> Matrix.flatten 
                  |> concat

    maze = [ Svg.g [] <| borders ++ unvisited ] 

  in
      div 
          [] 
          [ h1 [] [text "Langton's Ant"]
          , Svg.svg 
              [ version "1.1"
              , width (toString w)
              , height (toString h)
              , viewBox (join " " 
                           [ 0          |> toString
                           , 0          |> toString
                           , model.cols |> toString
                           , model.rows |> toString ])
              ] 
              maze
          ]

updateModel : Model -> Model
updateModel model = 
      let current = model.location
          inBox =    snd current >= 0 && snd current < model.cols
                  && fst current >= 0 && fst current < model.rows
      in if not inBox then
           model
         else
           let currentValue = Matrix.get current model.boxes |> M.withDefault False

               dir = case (model.direction, currentValue) of
                       (North, True) -> East
                       (East, True) -> South
                       (South, True) -> West
                       (West, True) -> North
 
                       (North, False) -> West
                       (East, False) -> North
                       (South, False) -> East
                       (West, False) -> South
 
               next = case dir of
                        North -> (fst current+1, snd current)
                        South -> (fst current-1, snd current)
                        East -> (fst current, snd current+1)
                        West -> (fst current, snd current-1)
 
               boxes = Matrix.set current (not currentValue) model.boxes 
 
           in {model | boxes=boxes, location=next, direction=dir}

type Msg = Tick Time 

subscriptions model = every (dt * second) Tick

main =
  let 
    update msg model = (updateModel model, Cmd.none)
    init = (initModel 100 100 , Cmd.none)
  in program 
       { init = init
       , view = view
       , update = update
       , subscriptions = subscriptions
       }


  

You may also check:How to resolve the algorithm Langton's ant step by step in the COBOL programming language
You may also check:How to resolve the algorithm Introspection step by step in the OCaml programming language
You may also check:How to resolve the algorithm Price fraction step by step in the XPL0 programming language
You may also check:How to resolve the algorithm Phrase reversals step by step in the Phix programming language
You may also check:How to resolve the algorithm Currency step by step in the Scala programming language