JSFiddle - React, Tailwind, and code Playground
by Chris Maloney
HTML
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.4.2/d3.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/d3-selection-multi.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>repl.it</title>
<link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div id='screen'></div>
<script src="script.js"></script>
<pre id='log'></pre>
</body>
</html>
JavaScript
//options
const numPeople = 100
const recoveryTime = 3
const contactDistance = 15
const deathChancePerTick = 0.0025
const scr = d3.select('#screen')
const svg = scr.append('svg').attrs({
width: 500,
height: 500,
})
svg.append('rect').attrs({
x: 0, y: 0,
width: 500, height: 500,
fill: '#EEE'
})
const makePerson = (x, y, dir) => {
const person = svg.append('circle').attrs({
cx: x,
cy: y,
r: 5,
fill: 'blue',
})
return {
x, y, dir,
person,
status: 'healthy',
recovery: 0,
}
}
const infect = person => {
person.status = 'sick'
person.recovery = recoveryTime * 25
person.person.attr('fill', 'red')
}
const recover = person => {
person.status = 'recovered'
person.recovery = 0
person.person.attr('fill', 'gray')
}
const kill = person => {
person.status = 'dead'
person.person.attr('fill', 'none')
person.person.attr('stroke', 'black')
}
const population = Array(numPeople)
for (i = 0; i < numPeople; i++) {
population[i] = makePerson(Math.random() * 490 + 5, Math.random() * 490 + 5, Math.random() * 2 * Math.PI)
}
const contact = (p0, p1) => {
if (Math.abs(p1.x - p0.x) > contactDistance ||
Math.abs(p1.y - p0.y) > contactDistance)
return false
const dist = Math.sqrt(
(p1.x - p0.x) ** 2 + (p1.y - p0.y) ** 2)
return dist <= contactDistance
}
const update = () => {
population.forEach(person => {
if (person.status != 'dead') {
person.x += Math.cos(person.dir) * 3
person.y += Math.sin(person.dir) * 3
if (person.x <= 5) {
person.x = 6
person.dir = Math.PI - person.dir
}
if (person.x >= 495) {
person.x = 494
person.dir = Math.PI - person.dir
}
if (person.y <= 5) {
person.y = 6
person.dir = 2 * Math.PI - person.dir
}
if (person.y >= 495) {
person.y = 494
person.dir = 2 * Math.PI - person.dir
}
person.person.attrs({
cx: person.x,
cy: person.y,
...