-
Notifications
You must be signed in to change notification settings - Fork 10
/
GameOfLife.js
137 lines (124 loc) · 4.62 KB
/
GameOfLife.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// import DOM helper for render function
import $$ from 'dom7'
// import js-son and assign Belief, Plan, Agent, and Environment to separate consts
import { Belief, Plan, Agent, Environment } from 'js-son-agent'
/*
Note: beliefs will be created dynamically at a later stage
create plans all agents have the same plans, as the head of the plans determines the correct
action (being "active" or "inactive" in the next round) dynamically, based on the states of the
neighbors.
*/
/*
determine how many neighbors of an agent are active
*/
const determineNeighborActivity = (index, activityArray) => {
const leftNeighbors = index % 15 === 0
? []
: [activityArray[index - 16], activityArray[index - 1], activityArray[index + 14]]
const rightNeighbors = index % 15 === 14
? []
: [activityArray[index - 14], activityArray[index + 1], activityArray[index + 16]]
return [
activityArray[index - 15],
activityArray[index + 15]
].concat(leftNeighbors, rightNeighbors).filter(element => element).length
}
const plans = [
Plan(
beliefs => {
const neighborActivity = determineNeighborActivity(beliefs.index, beliefs.activityArray)
const isActive = beliefs.activityArray[beliefs.index]
return (isActive && neighborActivity >= 2 && neighborActivity < 4) ||
neighborActivity === 3
},
() => ({ nextRound: 'active' })
),
Plan(
beliefs => {
const neighborActivity = determineNeighborActivity(beliefs.index, beliefs.activityArray)
const isActive = beliefs.activityArray[beliefs.index]
return !(isActive && neighborActivity >= 2 && neighborActivity < 4) &&
!neighborActivity === 3
},
() => ({ nextRound: 'inActive' })
)
]
// generates (pseudo-)random initial activity state (active or inactive)
const generateInitialActivity = () => [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0,
0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0,
0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0,
0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0,
0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0,
0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0,
0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
]
// generates 100 agents with provided initial activity state
const generateAgents = initialActivity => initialActivity.map((value, index) => {
const beliefs = { ...Belief('index', index), ...Belief('activityArray', initialActivity) }
return new Agent(index, beliefs, {}, plans)
})
/*
generate initial environment state
*/
const generateState = initialActivity => ({
previousActivity: initialActivity,
nextActivity: []
})
// state update function: collect future state of agents to assign new agent states next round
const updateState = (actions, agentId, currentState) => {
const stateUpdate = {
...currentState
}
const agentActive = actions.some(action => action.nextRound === 'active')
stateUpdate.nextActivity.push(agentActive)
if (agentId === '224') {
return {
previousActivity: stateUpdate.nextActivity,
nextActivity: []
}
}
return stateUpdate
}
/* the state filter provides the agent with the ``currentState`` activity array that changes at the
end of each iteration */
const stateFilter = state => ({ activityArray: state.previousActivity })
// render environment's ``currentState`` as grid to DOM
const render = state => {
if (state.nextActivity.length === 0) {
const agentActivity = state.previousActivity
const grid = agentActivity.map((value, index) => {
const agentClass = value ? 'agent active-agent' : 'agent inactive-agent'
if (index === 0) {
return `<div class="row no-gap"><div class="col-5 ${agentClass}">_</div>`
} else if (index % 15 === 0) {
return `</div><div class="row no-gap"><div class="col-5 ${agentClass}">_</div>`
} else if (index === 224) {
return `<div class="col-5 ${agentClass}">_</div></div>`
} else {
return `<div class="col-5 ${agentClass}">_</div>`
}
}).join('')
$$('#game-of-life-grid').html(grid)
}
}
// instantiate game of life as new environment
const GameOfLife = () => {
const initialActivity = generateInitialActivity()
return new Environment(
generateAgents(initialActivity),
generateState(initialActivity),
updateState,
render,
stateFilter
)
}
export default GameOfLife