{"id":13426382,"url":"https://github.com/chen0040/js-simulator","last_synced_at":"2025-08-15T22:31:05.420Z","repository":{"id":57283706,"uuid":"93476376","full_name":"chen0040/js-simulator","owner":"chen0040","description":"General-purpose discrete-event multiagent simulation library for agent-based modelling and simulation","archived":false,"fork":false,"pushed_at":"2017-06-24T05:29:18.000Z","size":170,"stargazers_count":68,"open_issues_count":1,"forks_count":9,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-06-30T19:04:43.432Z","etag":null,"topics":["abms","agent-based-framework","agent-based-modeling","agent-based-simulation","discrete-event-simulation","flocking-algorithm","game-of-life","multi-agent-systems","multiagent-systems","simulation","simulation-framework"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chen0040.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-06-06T04:32:48.000Z","updated_at":"2025-02-18T01:32:15.000Z","dependencies_parsed_at":"2022-09-19T20:34:26.238Z","dependency_job_id":null,"html_url":"https://github.com/chen0040/js-simulator","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/chen0040/js-simulator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chen0040%2Fjs-simulator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chen0040%2Fjs-simulator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chen0040%2Fjs-simulator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chen0040%2Fjs-simulator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chen0040","download_url":"https://codeload.github.com/chen0040/js-simulator/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chen0040%2Fjs-simulator/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270637924,"owners_count":24620430,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-15T02:00:12.559Z","response_time":110,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["abms","agent-based-framework","agent-based-modeling","agent-based-simulation","discrete-event-simulation","flocking-algorithm","game-of-life","multi-agent-systems","multiagent-systems","simulation","simulation-framework"],"created_at":"2024-07-31T00:01:33.198Z","updated_at":"2025-08-15T22:31:05.103Z","avatar_url":"https://github.com/chen0040.png","language":"JavaScript","readme":"# js-simulator\n\nInspired by the MASON Multiagent Simulation library in Java, js-simulator is a general-purpose discrete-event multiagent simulator for agent-based modelling and simulation. It was written entirely in Javascript. \n\n[![Build Status](https://travis-ci.org/chen0040/js-simulator.svg?branch=master)](https://travis-ci.org/chen0040/js-simulator) [![Coverage Status](https://coveralls.io/repos/github/chen0040/js-simulator/badge.svg?branch=master)](https://coveralls.io/github/chen0040/js-simulator?branch=master) \n\n\n# Install\n\nRun the following npm command to install\n\n```bash\nnpm install js-simulator\n```\n\n# Demo\n\nThe following HTML demo is available:\n\n* Flocking Boids [HTML DEMO](https://rawgit.com/chen0040/js-simulator/master/examples/example-flocking.html)\n* Conway's Game of Life [HTML DEMO](https://rawgit.com/chen0040/js-simulator/master/examples/example-game-of-life.html)\n* School Yard [HTML DEMO](https://rawgit.com/chen0040/js-simulator/master/examples/example-school-yard.html)\n* L-System (Fractal Plant) [HTML DEMO](https://rawgit.com/chen0040/js-simulator/master/examples/example-l-system.html)\n* L-System (Dragon Curve) [HTML DEMO](https://rawgit.com/chen0040/js-simulator/master/examples/example-dragon-curve.html)\n* Ant System [HTML DEMO](https://rawgit.com/chen0040/js-simulator/master/examples/example-ant.html)\n* Particle Swarm [HTML DEMO](https://rawgit.com/chen0040/js-simulator/master/examples/example-pso.html)\n* Virus [HTML DEMO](https://rawgit.com/chen0040/js-simulator/master/examples/example-virus.html)\n* (Spring) Balls [HTML DEMO](https://rawgit.com/chen0040/js-simulator/master/examples/example-balls.html)\n* Solar System [HTML DEMO](https://rawgit.com/chen0040/js-simulator/master/examples/example-solar.html)\n* Near Beer Game [HTML DEMO](https://rawgit.com/chen0040/js-simulator/master/examples/example-near-beer-game.html)\n\nMore demo and HTML GUI supports will be added in the subsequent releases.\n\n\n# Usage\n\n### Create and schedule discrete events or agents\n\nThe discrete-event simulator is managed via the Scheduler class, which can be created as shown below:\n\n```javascript\njssim = require('js-simulator');\nvar scheduler = new jssim.Scheduler();\n```\n\nThe scheduler schedules and fires events based on their time and rank (i.e. the order of the event) spec. \n\nTo schedule the an event to fire at a particular time:\n\n```javascript\nvar rank = 1; // the higher the rank, the higher the priority assigned and the higher-rank event will be fired first for all events occurring at the same time interval\nvar evt = new jssim.SimEvent(rank);\nevt.id = 20; \nevt.update = function(deltaTime) {\n    console.log('event [' + this.id + '] with rank ' + this.rank + ' is fired at time ' + this.time);\n    \n    // the code below allows the evt to send message to another agent (i.e., the agent referred by receiver variable)\n    /*\n    var receiver_id = receiver.guid()\n    this.sendMsg(receiver_id, {\n        content: \"Hello\"\n    });\n    */\n    \n    // the code below allows the evt to process messages sent from another agent\n    /*\n    var messages = this.readInbox();\n    for(var i = 0; i \u003c messages.length; ++i){\n        var msg = messages[i];\n        var sender_id = msg.sender;\n        var recipient_id = msg.recipient; // should equal to this.guid()\n        var time = msg.time;\n        var rank = msg.rank; // the messages[0] contains the highest ranked message and last messages contains lowest ranked\n        var content = msg.content; // for example the \"Hello\" text from the sendMsg code above\n    }\n    */\n};\n\nvar time_to_fire = 10; // fire this event at time = 10\nscheduler.schedule(evt, time_to_fire);\n```\n\nThe main logic for an event is defined in its update(deltaTime) method, as shown in the code above. Events with higher ranks and earlier time_to_fire will always be executed first by the scheduler.\n\nAn event can also be sheduled to fire at a later time from the current time (e.g., such an event can be fired within another event):\n\n```javascript\nvar delta_time_later = 10; // the event will be fired 10 time units from now, where now refers to the current scheduler time\nscheduler.scheduleOnceIn(evt, delta_time_later);\n```\n\nIn terms of multi-agent system, an event can be thought of as an agent. Such an agent may need to execute repeatedly. In the js-simulator, this is achieved by firing an event repeatedly at a fixed interval:\n\n```javascript\nvar interval = 2; // time interval between consecutive firing of the event\nvar start_time = 12; // time to fire the event for the first time\nscheduler.scheduleRepeatingAt(evt, start_time, interval);\n```\n\nIf the start_time is at from the start of the simulation, then the above scheduling can also be replaced by:\n\n```javascript\nscheduler.scheduleRepatingIn(evt, interval);\n```\n\n### Execute the scheduler loop for the main discrete-event simulation\n\nAfter the events/agents are scheduled, they are not fired immediately but only fired when scheduler.update() method is called, each call to scheduler.update() to move the \ntime forward. At each time forwarded, events with higher rank will be executed (by calling their update(delaTime) method) first. Also events with the same rank will be shuffled before execution.\n\nThe scheduler can be executed in the following loop:\n\n```javascript\nwhile(scheduler.hasEvents()) {\n    var evts_fired = scheduler.update();\n}\n```\n\nThe above will run until no more events to fire in the scheduler, to stop the scheduler at a particular instead, use the following loop:\n\n```javascript\nwhile(scheduler.current_time \u003c 20) { // stop the scheduler when current scheduler time is 20\n    scheduler.update();\n}\n```\n\nThe current scheduler time can be obtained by calling (this is useful if we want to know the current time inside the scheduler):\n\n```javascript\nvar current_scheduler_time = scheduler.current_time;\n```\n\n# Sample Codes\n\n### Flocking behavior Demo\n\nThe source code below shows how to create a flocking of 15 boids (12 preys and 3 predators) that demonstrate the flocking principles:\n\nFirstly we will declare a Boid class the inherits from the jsssim.SimEvent class, which defines the behavior of a single boid:\n\n```javascript\nvar jssim = require('js-simulator');\n\n\nvar Boid = function(id, initial_x, initial_y, space, isPredator) {\n    var rank = 1;\n    jssim.SimEvent.call(this, rank);\n    this.id = id;\n    this.space = space;\n    this.space.updateAgent(this, initial_x, initial_y);\n    this.sight = 75;\n    this.speed = 12;\n    this.separation_space = 30;\n    this.velocity = new jssim.Vector2D(Math.random(), Math.random());\n    this.isPredator = isPredator;\n    this.border = 100;\n};\n\nBoid.prototype = Object.create(jssim.SimEvent);\nBoid.prototype.update = function(deltaTime) {\n    var boids = this.space.findAllAgents();\n    var pos = this.space.getLocation(this.id);\n\n    if(this.isPredator) {\n        var prey = null;\n        var min_distance = 10000000;\n        for (var boidId in boids)\n        {\n            var boid = boids[boidId];\n            if(!boid.isPredator) {\n                var boid_pos = this.space.getLocation(boid.id);\n                var distance = pos.distance(boid_pos);\n                if(min_distance \u003e distance){\n                    min_distance = distance;\n                    prey = boid;\n                }\n            }\n        }\n\n        if(prey != null) {\n            var prey_position = this.space.getLocation(prey.id);\n            this.velocity.x += prey_position.x - pos.x;\n            this.velocity.y += prey_position.y - pos.y;\n        }\n    } else {\n        for (var boidId in boids)\n        {\n            var boid = boids[boidId];\n            var boid_pos = this.space.getLocation(boid.id);\n            var distance = pos.distance(boid_pos);\n            if (boid != this \u0026\u0026 !boid.isPredator)\n            {\n                if (distance \u003c this.separation_space)\n                {\n                    // Separation\n                    this.velocity.x += pos.x - boid_pos.x;\n                    this.velocity.y += pos.y - boid_pos.y;\n                }\n                else if (distance \u003c this.sight)\n                {\n                    // Cohesion\n                    this.velocity.x += (boid_pos.x - pos.x) * 0.05;\n                    this.velocity.y += (boid_pos.y - pos.y) * 0.05;\n                }\n                if (distance \u003c this.sight)\n                {\n                    // Alignment\n                    this.velocity.x += boid.velocity.x * 0.5;\n                    this.velocity.y += boid.velocity.y * 0.5;\n                }\n            }\n            if (boid.isPredator \u0026\u0026 distance \u003c this.sight)\n            {\n                // Avoid predators.\n                this.velocity.x += pos.x - boid_pos.x;\n                this.velocity.y += pos.y - boid_pos.y;\n            }\n        }\n    }\n\n\n    // check speed\n    var speed = this.velocity.length();\n    if(speed \u003e this.speed) {\n        this.velocity.resize(this.speed);\n    }\n\n    pos.x += this.velocity.x;\n    pos.y += this.velocity.y;\n\n    // check boundary\n    var val = this.boundary - this.border;\n    if (pos.x \u003c this.border) pos.x = this.boundary - this.border;\n    if (pos.y \u003c this.border) pos.y = this.boundary - this.border;\n    if (pos.x \u003e val) pos.x = this.border;\n    if (pos.y \u003e val) pos.y = this.border;\n        \n    console.log(\"boid [ \" + this.id + \"] is at (\" + pos.x + \", \" + pos.y + \") at time \" + this.time);\n};\n```\n\nOnce the boid is defined we can then create and schedule the flocking event simulator using the code below:\n\n```javascript\nvar scheduler = new jssim.Scheduler();\nscheduler.reset();\n\nvar space = new jssim.Space2D();\nfor(var i = 0; i \u003c 15; ++i) {\n    var is_predator = i \u003e 12;\n    var boid = new Boid(i, 0, 0, space, is_predator);\n    scheduler.scheduleRepeatingIn(boid, 1);\n}\n\nwhile(scheduler.current_time \u003c 20) {\n  scheduler.update();\n}\n\n\n```\n\n### Conway's Game of Life\n\nThe sample code below shows how to create the game of life simulation:\n\n```javascript\nvar jssim = require('js-simulator');\n\nvar CellularAgent = function(world) {\n  jssim.SimEvent.call(this);\n  this.world = world;\n}; \n\nCellularAgent.prototype = Object.create(jssim.SimEvent.prototype);\nCellularAgent.prototype.update = function (deltaTime) {\n  var width = this.world.width;\n  var height = this.world.height;\n  var past_grid = this.world.makeCopy();\n  for(var i=0; i \u003c width; ++i) {\n      for(var j = 0; j \u003c height; ++j) {\n          var count = 0;\n          for(var dx = -1; dx \u003c 2; ++dx) {\n              var x = i + dx;\n              if (x \u003e= width) {\n                  x = 0;\n              }\n              if (x \u003c 0) {\n                  x = width - 1;\n              }\n              for(var dy = -1; dy \u003c 2; ++dy) {\n                var y = j + dy;\n                  if(y \u003e= height) {\n                      y = 0;\n                  }\n                  if(y \u003c 0) {\n                      y = height - 1;\n                  }\n                  count += past_grid.getCell(x, y);\n              }\n          }\n          if (count \u003c= 2 || count \u003e= 5) {\n              this.world.setCell(i, j, 0); // dead\n          }\n          if (count == 3) {\n              this.world.setCell(i, j, 1); // live\n          }\n      }\n  }\n};\n\nvar scheduler = new jssim.Scheduler();\nvar grid = new jssim.Grid(640, 640);\n\nscheduler.reset();\ngrid.reset();\n\ngrid.setCell(1, 0, 1);\ngrid.setCell(2, 0, 1);\ngrid.setCell(0, 1, 1);\ngrid.setCell(1, 1, 1);\ngrid.setCell(1, 2, 1);\ngrid.setCell(2, 2, 1);\ngrid.setCell(2, 3, 1);\n\nscheduler.scheduleRepeatingIn(new CellularAgent(grid), 1);\n\nwhile(scheduler.current_time \u003c 20) { // this assumes that we want to terminate at time 20\n  scheduler.update();\n}\n```\n\n### School Yard Demo\n\nThe sample code below shows the school yard demo:\n\n```javascript\nvar Student = function(id, yard, network) {\n   jssim.SimEvent.call(this);\n   this.id = id;\n   this.yard = yard;\n   this.network = network;\n   this.MAX_FORCES = 3.0;\n   this.forceToSchoolMultiplier = 0.01;\n   this.randomMultiplier = 0.1;\n};\nStudent.prototype = Object.create(jssim.SimEvent.prototype);\nStudent.prototype.update = function(deltaTime) {\n   var students = this.yard.findAllAgents();\n\n\n   var me = this.yard.getLocation(this.id);\n\n    var sumForces = new jssim.Vector2D(0, 0);\n    var forceVector = new jssim.Vector2D(0, 0);\n    var edges = this.network.adj(this.id);\n    var len = edges.length;\n    for (var buddy = 0; buddy \u003c len; ++buddy)\n    {\n        var e = edges[buddy];\n        var buddiness = e.info;\n\n\n        var him = this.yard.getLocation(e.other(this.id));\n\n        if (buddiness \u003e= 0)\n        {\n            forceVector.set((him.x - me.x) * buddiness, (him.y - me.y) * buddiness);\n            if (forceVector.length() \u003e this.MAX_FORCES)\n            {\n                forceVector.resize(this.MAX_FORCES);\n            }\n        }\n        else\n        {\n            forceVector.set((me.x - him.x) * buddiness, (me.y - him.y) * buddiness);\n            if (forceVector.length() \u003e this.MAX_FORCES)\n            {\n                forceVector.resize(0);\n            }\n            else if(forceVector.length() \u003e 0)\n            {\n                forceVector.resize(this.MAX_FORCES - forceVector.length());\n            }\n        }\n\n        sumForces.addIn(forceVector);\n    }\n\n    sumForces.addIn(\n        new jssim.Vector2D((this.yard.width * 0.5 - me.x) * this.forceToSchoolMultiplier, (this.yard.height * 0.5 - me.y) * this.forceToSchoolMultiplier)\n        );\n\n    sumForces.addIn(\n        new jssim.Vector2D(this.randomMultiplier * (Math.random() * 1.0 - 0.5), this.randomMultiplier * Math.random() * 1.0 - 0.5));\n\n    sumForces.addIn(me);\n\n    me.x = sumForces.x;\n    me.y = sumForces.y;\n\n    console.log(\"Student \" + this.id + \" is at (\" + me.x + \", \" + me.y + \") at time \" + this.time);\n};\n\nvar scheduler = new jssim.Scheduler();\nvar yard = new jssim.Space2D();\nvar network = new jssim.Network(30);\nyard.width = 50;\nyard.height = 50;\n\nscheduler.reset();\nyard.reset();\nnetwork.reset();\nfor(var i=0; i \u003c 30; ++i) {\n   var student = new Student(i, yard, network);\n   yard.updateAgent(student, Math.random() * yard.width, Math.random() * yard.height);\n   scheduler.scheduleRepeatingIn(student, 1);\n}\n\nvar buddies = {};\nfor (var i = 0; i \u003c 30; ++i)\n{\n    var student = i;\n    var studentB = i;\n    do\n    {\n        studentB = Math.floor(Math.random() * 30);\n    } while (student == studentB);\n    var buddiness = Math.random();\n    if(!network.connected(student, studentB)){\n        network.addEdge(new jssim.Edge(student, studentB, buddiness));\n    }\n\n    var studentB = i;\n    do\n    {\n        studentB = Math.floor(Math.random() * 30);\n    } while (student == studentB);\n\n    buddiness = Math.random();\n    if(!network.connected(student, studentB)){\n        network.addEdge(new jssim.Edge(student, studentB, buddiness));\n    }\n}\n\nwhile (scheduler.current_time \u003c 2) {\n   scheduler.update();\n}\n```\n\n\n\n","funding_links":[],"categories":["JavaScript","Frameworks and libraries"],"sub_categories":["JavaScript"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchen0040%2Fjs-simulator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchen0040%2Fjs-simulator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchen0040%2Fjs-simulator/lists"}