Skip to content

Commit

Permalink
Lots of improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
rafa-br34 committed Jan 25, 2024
1 parent 1a8f96c commit b5c2b2e
Show file tree
Hide file tree
Showing 10 changed files with 677 additions and 22 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
This repository contains a C++ and web implementation of [Langton's ant](https://wikipedia.org/wiki/Langton's_ant) cellular automata.
The web version can be found [here](https://rafa-br34.github.io/LangtonsAnt)

![Langton's ant on a 30720x17280 grid with the LRRRRRLLR pattern after 1292334158 iterations](ASSETS/LRRRRRLLR_30720x17280_1292334158.png)
8 changes: 4 additions & 4 deletions SOURCE/Types/Ant.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ const char* DirectionStrings[] = {
// 7 0 1
// 6 o 2
// 5 4 3
constexpr int8_t c_DirectionsX[] = { 0, 1, 1, 1, 0, -1, -1, -1 };
constexpr int8_t c_DirectionsY[] = { -1, -1, 0, 1, 1, 1, 0, -1 };
constexpr int8_t c_DirectionsX[] = { 0, 1, 1, 1, 0, -1, -1, -1 };
constexpr int8_t c_DirectionsY[] = { -1, -1, 0, 1, 1, 1, 0, -1 };
constexpr int8_t c_VectorLookup[] = { 7, 0, 1, 6, 0, 2, 5, 4, 3 };

template<typename CellType=uint8_t, typename SizeType=int>
Expand All @@ -58,8 +58,8 @@ class Ant {


FORCE_INLINE void Rotate(int8_t Rotation) {
// Decode vector into direction by flattening it and using a lookup table,
// add the new rotation + 8 (rotation can be negative), and then mod 8
// Decode direction vector into direction index by flattening it and indexing a lookup table,
// add the new rotation + 8(rotation can be negative), and then mod 8
int8_t CurrentDirection = (c_VectorLookup[(3 * this->Direction.Y + this->Direction.X) + 4] + Rotation + 8) % 8;

this->Direction.X = c_DirectionsX[CurrentDirection];
Expand Down
56 changes: 44 additions & 12 deletions WebVersion/Index.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,36 +37,68 @@

<link rel="stylesheet" href="Styles/Main.css">
<script src="https://code.jquery.com/jquery-3.7.1.js"></script>
<script src="Script.js"></script>

<script src="Scripts/Debug.js"></script>

<script src="Scripts/Renderer.js"></script>
<script src="Scripts/Main.js"></script>
<script src="Scripts/Ant.js"></script>
</head>
<body>
<div id="CanvasContainer">
<canvas id="MainCanvas" width="1000" height="1000"></canvas>
<canvas id="MainCanvas"></canvas>

<div style="display: inline-grid; grid-template-columns: repeat(4, 1fr); gap: 1px; padding-top: 2px">
<div style="display: inline-grid; grid-template-columns: repeat(4, 1fr); gap: 1px; margin-top: -9px;">
<button id="SaveImage">Save Image</button>
<button id="SaveImage">A</button>
<button id="SaveImage">B</button>
<button id="SaveImage">C</button>
<button id="ResetCamera">Reset Camera</button>
<button id="ResetState">Reset State</button>
<button id="StartStop">Start</button>
</div>

<div style="display: inline-grid; grid-template-columns: repeat(2, 1fr); padding-top: 2px">
<span>FPS: 0</span>
<span>IPS: 0</span>
<span>Entropy: 0.00</span>
<span>Iteration: 0</span>
<span id="Stats_FPS">FPS: 0</span>
<span id="Stats_IPS">IPS: 0</span>
<span id="Stats_X">X: 0</span>
<span id="Stats_Y">Y: 0</span>
<span id="Stats_Entropy">Entropy: 0.00</span>
<span id="Stats_Iteration">Iteration: 0</span>
</div>
</div>

<div id="ManagerContainer">
<!-- Ants -->
<div>
<div class="SidePanel">
<!-- Simulation settings -->
<div class="InnerPanel">
<label class="OptionName">Grid Size</label>
<span style="display: flex; height: min-content; justify-content: center;">
<input id="GridSizeX" type="number" min="4" step="2" max="50000" value="100" style="width: 25%;">
<input id="GridSizeY" type="number" min="4" step="2" max="50000" value="100" style="width: 25%;">
</span>
</div>

<div class="InnerPanel">

</div>

<div class="InnerPanel" style="width: 100%">
Panel 3
</div>
</div>

<!-- Rules -->
<div>
<div class="SidePanel">
<div class="InnerPanel">
Panel 0
</div>

<div class="InnerPanel">
Panel 1
</div>

<div class="InnerPanel" style="width: 100%">
Panel 3
</div>
</div>
</div>
</body>
Expand Down
139 changes: 139 additions & 0 deletions WebVersion/Scripts/Ant.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
const c_DirectionEnum = Object.freeze({
R45: 1, // Right 45°
R90: 2, // Right 90°
R135: 3, // Right 135°

L45: -1, // Left 45°
L90: -2, // Left 90°
L135: -3, // Left 135°

C: 0, // Continue
U: 4, // U Turn

R: 2,
L: -2,
})

const c_DirectionStrings = Object.freeze([
"L135",
"L90",
"L45",

"C",

"R45",
"R90",
"R135",

"U"
])

function CreateStateMachine(Positions) {
let NewMachine = []

for (let Name of Positions)
NewMachine.push(c_DirectionEnum[Name])

return NewMachine
}

function StateMachineToString(StateMachine, Separator="") {
let NewString = ""

for (Direction of StateMachine)
NewString += c_DirectionStrings[(Direction + 3) % c_DirectionStrings.length] + Separator

return NewString
}

// Directions: (360 / 8)
// 7 0 1
// 6 o 2
// 5 4 3
const c_DirectionsX = [ 0, 1, 1, 1, 0, -1, -1, -1 ]
const c_DirectionsY = [ -1, -1, 0, 1, 1, 1, 0, -1 ]
const c_VectorLookup = [ 7, 0, 1, 6, 0, 2, 5, 4, 3 ]

class Ant {
LastPosition = { X: 0, Y: 0 }
Direction = { X: 0, Y: 0 }
Position = { X: 0, Y: 0 }

StateMachine = []

Rotate(Rotation) {
// Decode direction vector into direction index by flattening it and indexing a lookup table,
// add the new rotation + 8(rotation can be negative), and then mod 8
let CurrentDirection = (c_VectorLookup[(3 * this.Direction.Y + this.Direction.X) + 4] + Rotation + 8) % 8

this.Direction.X = c_DirectionsX[CurrentDirection]
this.Direction.Y = c_DirectionsY[CurrentDirection]
}

WrapPosition(GridSize) {
if (this.Position.X < 0) this.Position.X = GridSize.X - 1
if (this.Position.Y < 0) this.Position.Y = GridSize.Y - 1
if (this.Position.X >= GridSize.X) this.Position.X = 0
if (this.Position.Y >= GridSize.Y) this.Position.Y = 0
}

Update(Grid, GridSize, Wrap=false) {
let Dir = this.Direction
let Pos = this.Position

// Check if the last update has landed us in a invalid position
if (Pos.X >= GridSize.X || Pos.Y >= GridSize.Y || Pos.X < 0 || Pos.Y < 0) return 0

let CellIndex = GridSize.X * Pos.Y + Pos.X
let CellValue = Grid[CellIndex]

this.Rotate(this.StateMachine[CellValue % this.StateMachine.length])
Pos.X += Dir.X
Pos.Y += Dir.Y

Grid[CellIndex] = (CellValue + 1) % this.StateMachine.length

if (Wrap) this.WrapPosition(GridSize)
return 1
}

// Double step update (used for multiple ants)
UpdatePosition(Grid, GridSize, Wrap=false) {
let Last = this.LastPosition
let Pos = this.Position
let Dir = this.Direction

Last.X = Pos.X
Last.Y = Pos.Y

this.Rotate(this.StateMachine[Grid[GridSize.X * Pos.Y + Pos.X] % this.StateMachine.length])
Pos.X += Dir.X
Pos.Y += Dir.Y

if (Wrap) this.WrapPosition(GridSize)
}

UpdateCell(Grid, GridSize) {
let Last = this.LastPosition
let Pos = this.Position

// Check if the last update has landed us in a invalid position
// Positive out of bounds checks go first since a overflow will also trigger them
if (Pos.X >= GridSize.X || Pos.Y >= GridSize.Y || Pos.X < 0 || Pos.Y < 0) return 0

let CellIndex = GridSize.X * Last.Y + Last.X
let CellValue = Grid[CellIndex]

Grid[CellIndex] = (CellValue + 1) % this.StateMachine.length

return 1
}

constructor(X, Y, DX, DY, StateMachine) {
this.Position.X = X
this.Position.Y = Y
this.Direction.X = DX
this.Direction.Y = DY
this.StateMachine = StateMachine
}
}
28 changes: 28 additions & 0 deletions WebVersion/Scripts/Debug.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const c_DEBUG = true

let DBG
let DBG_PUSH_FMT
let DBG_POP_FMT
{
let g_DBG_FMT = []
if (c_DEBUG) {
DBG = function (...Args) {
console.log(...g_DBG_FMT, ...Args)
}

DBG_PUSH_FMT = function (Format) {
g_DBG_FMT.push(Format)
}

DBG_POP_FMT = function () {
g_DBG_FMT.pop()
}
}
else {
DBG = function () { }

DBG_PUSH_FMT = function () { }

DBG_POP_FMT = function () { }
}
}
Loading

0 comments on commit b5c2b2e

Please sign in to comment.