Game Of Life model for Political Revolution and Political Polarization
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="UTF-8" /> | |
<title>The Game of Life</title> | |
<link | |
href="https://cdn.jsdelivr.net/gh/rastikerdar/vazirmatn@v33.003/Vazirmatn-font-face.css" | |
rel="stylesheet" | |
type="text/css" | |
/> | |
<style> | |
* { | |
direction: rtl !important; | |
font-family: Vazirmatn, Vazir; | |
} | |
#gridContainer { | |
padding-bottom: 10px; | |
} | |
table { | |
background-color: #c5d6c6; | |
border-spacing: 0; | |
} | |
td { | |
border: 1px solid #f1f5da; | |
border-radius: 3px; | |
width: 10px; | |
height: 10px; | |
} | |
span { | |
color: #222; | |
} | |
#start, | |
#clear, | |
#random { | |
padding: 0.75em; | |
border-radius: 5px; | |
border: none; | |
background: linear-gradient(to bottom right, #c5dec6, #587559); | |
} | |
td.dead { | |
background-color: transparent; | |
} | |
td.live { | |
background-color: #cc4774; | |
border-radius: 10px; | |
} | |
td.right { | |
background-color: blue; | |
border-radius: 10px; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="gridContainer"></div> | |
<div class="controls"> | |
<button id="start"><span>شروع</span></button> | |
<button id="clear"><span>پاک کردن</span></button> | |
<button id="random"><span>رندوم</span></button> | |
</div> | |
<script> | |
var rows = 30; | |
var cols = 100; | |
var playing = false; | |
var grid = new Array(rows); | |
var nextGrid = new Array(rows); | |
var timer; | |
var reproductionTime = 100; | |
function initializeGrids() { | |
for (var i = 0; i < rows; i++) { | |
grid[i] = new Array(cols); | |
nextGrid[i] = new Array(cols); | |
} | |
} | |
function resetGrids() { | |
for (var i = 0; i < rows; i++) { | |
for (var j = 0; j < cols; j++) { | |
grid[i][j] = 0; | |
nextGrid[i][j] = 0; | |
} | |
} | |
} | |
function copyAndResetGrid() { | |
for (var i = 0; i < rows; i++) { | |
for (var j = 0; j < cols; j++) { | |
grid[i][j] = nextGrid[i][j]; | |
nextGrid[i][j] = 0; | |
} | |
} | |
} | |
// Initialize | |
function initialize() { | |
createTable(); | |
initializeGrids(); | |
resetGrids(); | |
setupControlButtons(); | |
randomButtonHandler(); | |
} | |
// Lay out the board | |
function createTable() { | |
var gridContainer = document.getElementById("gridContainer"); | |
if (!gridContainer) { | |
// Throw error | |
console.error("Problem: No div for the drid table!"); | |
} | |
var table = document.createElement("table"); | |
for (var i = 0; i < rows; i++) { | |
var tr = document.createElement("tr"); | |
for (var j = 0; j < cols; j++) { | |
// | |
var cell = document.createElement("td"); | |
cell.setAttribute("id", i + "_" + j); | |
cell.setAttribute("class", "dead"); | |
cell.onclick = cellClickHandler; | |
tr.appendChild(cell); | |
} | |
table.appendChild(tr); | |
} | |
gridContainer.appendChild(table); | |
} | |
function cellClickHandler() { | |
var rowcol = this.id.split("_"); | |
var row = rowcol[0]; | |
var col = rowcol[1]; | |
var classes = this.getAttribute("class"); | |
if (classes.indexOf("live") > -1) { | |
this.setAttribute("class", "dead"); | |
grid[row][col] = 0; | |
} else { | |
this.setAttribute("class", "live"); | |
grid[row][col] = 1; | |
} | |
} | |
function updateView() { | |
for (var i = 0; i < rows; i++) { | |
for (var j = 0; j < cols; j++) { | |
var cell = document.getElementById(i + "_" + j); | |
if (grid[i][j] == 0) { | |
cell.setAttribute("class", "dead"); | |
} else if (grid[i][j] == 2) { | |
cell.setAttribute("class", "right"); | |
} else { | |
cell.setAttribute("class", "live"); | |
} | |
} | |
} | |
} | |
function setupControlButtons() { | |
// button to start | |
var startButton = document.getElementById("start"); | |
startButton.onclick = startButtonHandler; | |
// button to clear | |
var clearButton = document.getElementById("clear"); | |
clearButton.onclick = clearButtonHandler; | |
// button to set random initial state | |
var randomButton = document.getElementById("random"); | |
randomButton.onclick = randomButtonHandler; | |
} | |
function randomButtonHandler() { | |
if (playing) return; | |
clearButtonHandler(); | |
for (var i = 0; i < rows; i++) { | |
for (var j = 0; j < cols; j++) { | |
if (Math.random() > 0.9) { | |
var cell = document.getElementById(i + "_" + j); | |
cell.setAttribute("class", "right"); | |
grid[i][j] = 2; | |
} else if (Math.random() > 0.8) { | |
var cell = document.getElementById(i + "_" + j); | |
cell.setAttribute("class", "live"); | |
grid[i][j] = 1; | |
} | |
} | |
} | |
} | |
// clear the grid | |
function clearButtonHandler() { | |
console.log("Clear the game: stop playing, clear the grid"); | |
playing = false; | |
var startButton = document.getElementById("start"); | |
startButton.innerHTML = "شروع"; | |
clearTimeout(timer); | |
var cellsList = document.getElementsByClassName("live"); | |
// convert to array first, otherwise, you're working on a live node list | |
// and the update doesn't work! | |
var cells = []; | |
for (var i = 0; i < cellsList.length; i++) { | |
cells.push(cellsList[i]); | |
} | |
for (var i = 0; i < cells.length; i++) { | |
cells[i].setAttribute("class", "dead"); | |
} | |
cellsList = document.getElementsByClassName("right"); | |
var cells = []; | |
for (var i = 0; i < cellsList.length; i++) { | |
cells.push(cellsList[i]); | |
} | |
for (var i = 0; i < cells.length; i++) { | |
cells[i].setAttribute("class", "dead"); | |
} | |
resetGrids; | |
} | |
// start/pause/continue the game | |
function startButtonHandler() { | |
if (playing) { | |
console.log("Pause the game"); | |
playing = false; | |
this.innerHTML = "Continue"; | |
clearTimeout(timer); | |
} else { | |
console.log("Continue the game"); | |
playing = true; | |
this.innerHTML = "Pause"; | |
play(); | |
} | |
} | |
// run the life game | |
function play() { | |
computeNextGen(); | |
if (playing) { | |
timer = setTimeout(play, reproductionTime); | |
} | |
} | |
function computeNextGen() { | |
for (var i = 0; i < rows; i++) { | |
for (var j = 0; j < cols; j++) { | |
applyRules(i, j); | |
} | |
} | |
modelPoliticalPolarization(0.3); | |
modelPoliticalRevolution(50, 15, 20); | |
// copy NextGrid to grid, and reset nextGrid | |
copyAndResetGrid(); | |
// copy all 1 values to "live" in the table | |
updateView(); | |
} | |
// RULES | |
// Any live cell with fewer than two live neighbours dies, as if caused by under-population. | |
// Any live cell with two or three live neighbours lives on to the next generation. | |
// Any live cell with more than three live neighbours dies, as if by overcrowding. | |
// Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction. | |
function applyRules(row, col) { | |
let status = grid[row][col]; | |
let numNeighborsOne = countNeighborsOne(row, col); | |
let numNeighborsTwo = countNeighborsTwo(row, col); | |
if (status == 1 || status == 2) { | |
if (numNeighborsOne + numNeighborsTwo < 2) { | |
nextGrid[row][col] = 0; | |
} else if (numNeighborsOne + numNeighborsTwo > 3) { | |
nextGrid[row][col] = 0; | |
} else if (numNeighborsTwo == 2 || numNeighborsTwo == 3) { | |
nextGrid[row][col] = 2; | |
} else if (numNeighborsOne == 2 || numNeighborsOne == 3) { | |
nextGrid[row][col] = 1; | |
} | |
} else if (status == 0) { | |
let numNeighborsOne = countNeighborsOne(row, col); | |
let numNeighborsTwo = countNeighborsTwo(row, col); | |
if (numNeighborsOne + numNeighborsTwo == 3) { | |
if (numNeighborsOne > numNeighborsTwo) { | |
nextGrid[row][col] = 1; | |
} else { | |
nextGrid[row][col] = 2; | |
} | |
} | |
} | |
} | |
function modelPoliticalRevolution(location_x, location_y, strength) { | |
for (var i = 0; i < rows; i++) { | |
for (var j = 0; j < cols; j++) { | |
let distance = Math.sqrt( | |
Math.pow(location_x - i, 2) + Math.pow(location_y - j, 2) | |
); | |
if (distance <= strength) { | |
var cell = document.getElementById(i + "_" + j); | |
if (grid[i][j] == 0) { | |
if (Math.random() > 0.5) { | |
grid[i][j] = 2; | |
} else { | |
grid[i][j] = 1; | |
} | |
grid[i][j] = 1; | |
} else if (grid[i][j] == 1 || grid[i][j] == 2) { | |
grid[i][j] = 0; | |
} | |
} | |
} | |
} | |
} | |
function modelPoliticalPolarization(value) { | |
for (var i = 0; i < rows; i++) { | |
for (var j = 0; j < cols; j++) { | |
if (grid[i][j] == 1) { | |
if (Math.random() < value) { | |
grid[i][j] = 2; | |
} | |
} else if (grid[i][j] == 2) { | |
if (Math.random() < value) { | |
grid[i][j] = 1; | |
} | |
} | |
} | |
} | |
} | |
function countNeighborsOne(row, col) { | |
var count = 0; | |
if (row - 1 >= 0) { | |
if (grid[row - 1][col] == 1) count++; | |
} | |
if (row - 1 >= 0 && col - 1 >= 0) { | |
if (grid[row - 1][col - 1] == 1) count++; | |
} | |
if (row - 1 >= 0 && col + 1 < cols) { | |
if (grid[row - 1][col + 1] == 1) count++; | |
} | |
if (col - 1 >= 0) { | |
if (grid[row][col - 1] == 1) count++; | |
} | |
if (col + 1 < cols) { | |
if (grid[row][col + 1] == 1) count++; | |
} | |
if (row + 1 < rows) { | |
if (grid[row + 1][col] == 1) count++; | |
} | |
if (row + 1 < rows && col - 1 >= 0) { | |
if (grid[row + 1][col - 1] == 1) count++; | |
} | |
if (row + 1 < rows && col + 1 < cols) { | |
if (grid[row + 1][col + 1] == 1) count++; | |
} | |
return count; | |
} | |
function countNeighborsTwo(row, col) { | |
var count = 0; | |
if (row - 1 >= 0) { | |
if (grid[row - 1][col] == 2) count++; | |
} | |
if (row - 1 >= 0 && col - 1 >= 0) { | |
if (grid[row - 1][col - 1] == 2) count++; | |
} | |
if (row - 1 >= 0 && col + 1 < cols) { | |
if (grid[row - 1][col + 1] == 2) count++; | |
} | |
if (col - 1 >= 0) { | |
if (grid[row][col - 1] == 2) count++; | |
} | |
if (col + 1 < cols) { | |
if (grid[row][col + 1] == 2) count++; | |
} | |
if (row + 1 < rows) { | |
if (grid[row + 1][col] == 2) count++; | |
} | |
if (row + 1 < rows && col - 1 >= 0) { | |
if (grid[row + 1][col - 1] == 2) count++; | |
} | |
if (row + 1 < rows && col + 1 < cols) { | |
if (grid[row + 1][col + 1] == 2) count++; | |
} | |
return count; | |
} | |
// Start everything | |
window.onload = initialize; | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment