xxxxxxxxxx
171
let columns;
let rows;
let cellSize = 15;
let board;
let snake;
function setup()
{
createCanvas(800, 800);
// Assign number of columns and rows based on canvas size
columns = floor(width / cellSize);
rows = floor(height / cellSize);
board = create2DArray(columns, rows); // Creating cells grid
snake = new Snake(floor(columns/ 2), floor(rows/ 2)); // Calling snake object with starting point in center of grid
}
function draw()
{
background(255);
// Check for user mouse click
userInteract();
// Call snake class functions
snake.update();
snake.display();
// Call board functions
updateBoard();
displayBoard();
}
// Creating board
function create2DArray(columns, rows)
{
let board = [];
// Loop through each cell in the grid
for (let i = 0; i < columns; i++) {
board[i] = [];
for (let j = 0; j < rows; j++) {
// Assign a random state "alive or dead" to each cell
board[i][j] = floor(random(2));
}
}
return board;
}
// Calculating alive neighbors
function neighborState(board, x, y)
{
// Initializing number of alive neigbors as 0
let aliveNeighbor = 0;
// Looping through cells in every 3X3 neighbourhood
for (let i = -1; i <= 1; i++) {
for (let j = -1; j <= 1; j++) {
// Calculating indices around edge
let column = (x + i + columns) % columns;
let row = (y + j + rows) % rows;
// Incrementing based on previous alive neighbors
aliveNeighbor += board[column][row];
}
}
aliveNeighbor -= board[x][y];
return aliveNeighbor;
}
// Updating cells based on their neighboring cells
function updateBoard()
{
// Creating a new board to assign its value to the previous board
let newBoard = create2DArray(columns, rows);
// Looping through all rows and columns
for (let i = 0; i < columns; i++)
{
for (let j = 0; j < rows; j++)
{
// Calculating neighbors state "alive or dead"
let neighbors = neighborState(board, i, j);
// Rules of game of life to update cells
if (board[i][j] === 1 && (neighbors < 2 || neighbors > 3))
{
// Cell dies due to underpopulation or overpopulation
newBoard[i][j] = 0;
}
// Cell reproduction
else if (board[i][j] === 0 && neighbors === 3)
{
newBoard[i][j] = 1;
}
// Cell remains in original condition
else
{
newBoard[i][j] = board[i][j];
}
}
}
// updating board value based on new board state
board = newBoard;
}
// Displaying board on canvas
function displayBoard()
{
// Loop through each column and row
for (let i = 0; i < columns; i++) {
for (let j = 0; j < rows; j++) {
// Calculating coordinates of the cell
let x = i * cellSize;
let y = j * cellSize;
/// fill color based on state "alive or dead"
fill(board[i][j] === 1 ? color(0, 255, 0, 150) : color(255, 0, 0, 150));
noStroke();
rect(x, y, cellSize, cellSize);
}
}
}
function userInteract()
{
if (mouseIsPressed)
{
// Assigning the board indices i and j based on mouse posiiton
let i = floor(mouseX / cellSize);
let j = floor(mouseY / cellSize);
// If i and j are within the range of columns and rows
if (i >= 0 && i < columns && j >= 0 && j < rows)
{
// Change the state of the clicked cell from dead to alive or vice versa
board[i][j] = 1 - board[i][j];
}
}
}
class Snake
{
constructor(startX, startY)
{
// Array to store the segments of the snake, starting with the head
this.body = [createVector(startX, startY)];
}
update()
{
// Copy the current head position of the snake
let head = this.body[0].copy();
// Asssign position of the mouse in terms of board cells
let mousePos = createVector(mouseX / cellSize, mouseY / cellSize);
// Calculate the direction vector from the head to the mouse position and limit its magnitude to 1
let direction = p5.Vector.sub(mousePos, head).limit(1);
// update head position based on direction vector
head.add(direction);
// Add the updated head to the front of the snake's body
this.body.unshift(head);
// Keeping the body shorter than 20 segments
if (this.body.length > 20)
{
this.body.pop();
}
}
// Display snake based on board indices
display()
{
for (let i = 0; i < this.body.length; i++) {
let pos = this.body[i];
let x = pos.x * cellSize;
let y = pos.y * cellSize;
fill(0, 0, 255, 150);
noStroke();
rect(x, y, cellSize, cellSize);
}
}
}