Skip to content

LordTobyJ/ailo-zombies-test

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Zombie Grid Simulation

This project implements a deterministic zombie infection simulation on a 2-dimensional toroidal grid. Zombies move according to a predefined sequence, infect creatures they encounter, and newly infected zombies are queued for subsequent movement. Creatures within the system do not move.

The system is designed to be fully testable, extendable, deterministic, and explicit in state transitions.


Overview

The simulation consists of:

  • A square grid of fixed size
  • Creatures placed at specific coordinates
  • Zombies placed at specific coordinates
  • A movement sequence applied to each zombie
  • Infection rules that convert creatures into zombies
  • A FIFO queue that governs zombie movement order

The grid wraps at edges (toroidal topology). There are no boundaries.


Core Concepts

Grid

The Grid represents the world, and is the central controller. It owns:

  • Dimensions (width, height)
  • All Cell instances
  • All Zombie and Creature instances
  • A FIFO Queue<Zombie> used to control movement order
  • A Logger for traceability

The grid is responsible for:

  • Creating zombies and creatures
  • Moving zombies
  • Maintaining consistency between entities and cells
  • Producing a final output state

Cell

A Cell represents a single coordinate on the grid.

Each cell tracks:

  • Its (x, y) position
  • Zombies currently occupying the cell
  • Creatures currently occupying the cell

Key behaviours:

  • Coordinate wrapping via validate()
  • Cardinal neighbour lookup (toLeft, toRight, toUp, toDown)
  • Infection via infectCell()
  • Locks cell during infection to stop circular referencing

If at least one zombie and one creature are present, all creatures in the cell are infected, turning them into zombies.


Zombie

A Zombie:

  • Has a unique incrementing ID
  • Occupies exactly one cell at a time
  • Tracks the creature it originated from (if infected)
  • Moves according to a direction sequence specified by the input

Movement:

  • Executed step-by-step
  • Wraps at grid edges
  • Triggers infection after each step

Invalid movement instructions result in a hard error.


Creature

A Creature:

  • Has a unique ID
  • Occupies a single cell
  • Does not move
  • Can be converted into a zombie when infected

Creatures are passive entities.


Queue

The Queue<T> is a FIFO structure used to ensure zombies move in a deterministic order.

Properties:

  • Enqueue at tail
  • Dequeue from head
  • Prevents duplicate zombie movement in queue
  • Periodically compacts internal storage to avoid memory growth

Logger

The Logger provides structured logging with configurable behaviour:

  • Silent or console output
  • In-memory history tracking
  • Optional file persistence
  • Controlled crash behaviour on errors

Errors logged via throw() terminate execution.


Movement Rules

  • Zombies move one at a time, in FIFO order
  • Each zombie executes the full movement sequence
  • During movement, newly infected zombies are added to the queue
  • Zombies already queued are not re-queued

Movement directions are defined by a Direction enum and parsed from characters.


Input Format

The simulation reads from input.json:

{
  "gridSize": 4,
  "sequence": "RDLU",
  "creaturePositions": [[0,1], [2,2]],
  "zombiePositions": [[3,0]]
}

The original specification for the project requested a single zombie position. For the purposes of completeness, the project can support any number of zombies during input.

Note that overlapping creature and zombie positions at input will necessarily create a new zombie immediately as the creature will become infected.

Fields

  • gridSize: Size of the grid (NxN)
  • sequence: Movement sequence applied to each zombie
  • creaturePositions: Array of [x, y] creature coordinates
  • zombiePositions: Array of [x, y] zombie coordinates

Execution Flow

  1. Input is loaded from input.json
  2. Grid is created
  3. Creatures are placed
  4. Zombies are placed and queued
  5. Zombies move until the queue is empty
  6. Final grid state is printed

Output

The final output is a structured representation of the grid and its zombies and creatures, followed by a direct output of just the zombie and creature positions.

    {
      width: 4,
      height: 4,
      zombies: [
        {
          id: 0,
          cell: (1,1),
          wasCreature: false
        },
        {
          id: 1,
          cell: (1,1),
          wasCreature: true
        }
      ],
      creatures: []
    }

    zombies’ positions:
    (1,1) (1,1)

    creatures’ positions:
    none

Testing

The project includes exhaustive Jest test coverage for:

  • Grid
  • Cell
  • Zombie
  • Creature
  • Queue
  • Logger
  • Utility functions

Tests validate:

  • Deterministic movement
  • Infection rules
  • Queue correctness
  • Edge wrapping
  • Error handling
  • Logging behaviour

Design Characteristics

  • Deterministic execution
  • No randomness
  • No side effects outside logging
  • Explicit state transitions
  • Defensive rejection error handling
  • Fully unit-testable components

Limitations (By Design)

  • No diagonal movement
  • No creature movement
  • No concurrency
  • No graphical output

Author's Commentary

I wrote this project with developer extensibility in mind. Wherever possible I have made it easy for developers to work with the code, from naming conventions, to debug testability, to log management systems.

I wrote the project in just under 4 hours without the use of AI; but I did use AI to write the README.md, then checked and expanded the information. Similarly, I used AI to think through the possible edge cases within the solution to develop the tests - however the code itself is written completely by me.

I opted for an object oriented approach; not a particular favourite approach of mine, but to the best of my knowledge the correct choice for the requirements of this project. The statefulness of the project makes object-oriented particularly appropriate and gives access to a number of options that functional or procedural solutions to the problem would not offer. This solution effectively made the system a simplistic simulation engine which developers can easily modify the instructions of to generate many different scenarios.

A number of tradeoffs have been made within the project - most notably a Queue with a head pointer instead of running an array shift; and whilst observances have been made to the correct data structures to minimise time and space complexity, my focus was readability first and foremost. For the same reason, there is a level of redundancy between the Grid, the Cells, and the Zombies with each one being able to be accessed from the other.

Whilst the intent was to have the Grid be the primary controller for the logic and act as a facade layer, I didnt want to have a situation in which you were traversing multiple layers of abstraction for any given item. This tradeoff choice in particular has led to an added complexity in updating the grid's cells when they had been modified elsewhere, which if I were continuing work on this project I would seek better solution avenues for a v2 release. As it stands the updateGrid(cell) is sufficient, and I opted to keep the existing solution so as not to overabstract the solution.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors