// Cloned by Enhanced on 10 Jul 2018 from World "CELLS WITH MIND (2 minds implemented)" by Enhanced // Please leave this clone trail here.// Cloned by Enhanced on 10 Jul 2018 from World "CELLS WITH MIND (with more minds)" by SinfulSalad // Please leave this clone trail here.// Cloned by SinfulSalad on 5 Jul 2018 from World "CELLS WITH MIND" by SinfulSalad // Please leave this clone trail here.// Cloned by SinfulSalad on 25 Jun 2018 from World "Cells" by SinfulSalad // Please leave this clone trail here.// ============ CELLS ===============================================================================================// 'Cells' is a program that displays 4 team of cells trying to infect each other, until total domination is// accomplished. The rules are simple : once a cell is possessed by a team, it starts generating value, until a maximum// value is reached. Each cell can, at any given time, split and send one of its halves to another cell to infect it.// If the value of this half is higher than the value of the cell it is trying to infect, then the infection will// succeed. Each team can't split more than 15 of it's cells at any given time.// The team that wins is the team that controls all cells// ===================================================================================================================// === Start of tweaker's box ======================================================================================== // ===================================================================================================================// The easiest things to modify are in this box.// You should be able to change things in this box without being a JavaScript programmer.// Go ahead and change some of these. What's the worst that could happen?// These 3 have default values, so this section is optional:
AB.clockTick =33;// Speed of run: Step every n milliseconds. Default 100.
AB.maxSteps =20000;// Length of run: Maximum length of run in steps. Default 1000.
AB.screenshotStep =1000;// Take screenshot on this step. (All resources should have finished loading.) Default 50.const SKYCOLOR ="#000000";// this usage will be of color as a string, not as a number //put your music file here if you want to change the musicconst MUSIC_BACK ='/uploads/sinfulsalad/Forest.mp3';//you can change change the color used here if they do not suit you.//warning : if you modify a name, don't forget to modify the corresponding code//you can go there to get the code for any color : http://jdstiles.com/colorchart.htmlconst COLOR_NAME =["aquamarine","red","hotpink","lightgoldenrodyellow","lime","orange","saddlebrown","mediumblue"];const COLOR_CODE =["#5FDDB4","#FF0000","#FF69B4","#FAFAD2","#00FF00","#FFA500","#8B4513","#0000DD"];//you can change the number of teams fighting for total domination.//by default, there will be as many teams as there are minds (two in this version)//but if NB_TEAMS is higher than the number of minds, then it will add additional//teams with a basic mind.const NB_TEAMS =6;// ===================================================================================================================// === End of tweaker's box ==========================================================================================// ===================================================================================================================// You will need to be some sort of JavaScript programmer to change things below the tweaker's box.//----------------------------- MINDS ------------------------------------------/*
//Here is the template to create your own mind
//(An example of a basic mind is coded just below)
//There is only one order the mind can give to the world :
//which cell should try to infect which other cell, and when.
//To give this order, the mind have to define the attribute team.ordersArray
//and the function team.ACTION() (more on that below).
//There can't be more than 15 infections in progress at any given time
//If new orders are sent while this limit is reached, they will be ignored.
//Any kind of function or attribute can be defined here.
//VERY IMPORTANT :
//When you are done, don't forget to push your mind into the mindArray
//(you can do it right below the basic mind example).
//(it is recommended to read the class definition of the Team and Cell object
//in the World, to understand how they work, and what information they contain)
var newMind = function(team) {
//this attribute is necessary for the mind to work properly
//each order is a tuple containing two elements :
//1. the cell the mind wants to split
//2. the cell the mind is trying to infect
//ex : team.ordersArray.push([team.cells[2], team.possibleTargets[12]]);
//note : each mind can technically acces any cell on the battlefield because
//there are no private attributes, but it is only fair that it should only
//control the cells that belong to it's own team.
team.ordersArray = [];
team.newAttribute;
team.newFunction = function(){
};
//This function is necessary for the mind to work properly
//This is the function called by the World when it is waiting for
//an input from the mind.
//It should contain any kind of code using the functions and attributes created
//above, in order to generate orders. The orders will then be executed by the World.
//ACTION() should not modify any of the variables contained in the World,
//just read them to generate orders accordingly.
team.ACTION = function() {
//reset the orders' array
ordersArray = [];
//code
return team.ordersArray;
};
};
*///TODO : BUILD YOUR OWN MIND HERE//TODO : WHEN YOU ARE DONE, DONT FORGET TO ADD IT TO mindArray SO THE WORLD// KNOWS IT EXISTS. mindArray's definition is right below the last mind, and// right above the "useful functions"//HERE IS A BASIC EXAMPLE OF MIND (don't overwrite it)//there is no strategy here, each cell acts on its own, and choses//its target randomly among enemies and neutral cellsvar basicMind =function(team){
team.ordersArray =[];
team.individualMind =function(){var rand;for(var i =0; i<team.cells.length ; i++){//the more a huge cell is close to its max value, the more it is//likely to split and infect other cells//all targets are chosen randomly between enemies or neutral cellsif(team.cells[i].type =="huge"){//console.log("I want to split huge things");
rand =(team.cells[i].maxVal - team.cells[i].value);if(randomintAtoB(0, rand)===0&& team.cells[i].team.possibleTargets.length !==0){//console.log("IMSPLITTINGTHIS")
rand = randomintAtoB(0, team.cells[i].team.possibleTargets.length);
team.ordersArray.push([team.cells[i], team.possibleTargets[rand]]);}}//whenever a small or average cell reaches it's max value, it will split//all targets are chosen randomly between enemies or neutral cellselseif((team.cells[i].type =="small"|| team.cells[i].type =="avg")&& team.cells[i].value == team.cells[i].maxVal){if(team.cells[i].team.possibleTargets.length !==0){
rand = randomintAtoB(0, team.cells[i].team.possibleTargets.length);
team.ordersArray.push([team.cells[i], team.possibleTargets[rand]]);}}}};
team.ACTION =function(){
team.ordersArray =[];
team.individualMind();return team.ordersArray;};};//TODO : ADD YOUR MIND HEREvar mindArray =[];
mindArray.push(basicMind);//--------------------------------END MINDS-------------------------------------//---------------------------USEFUL FUNCTIONS-----------------------------------//take the hexadecimal value of a color 'col', and make it brighter or darker//depending on 'amt'function lightenDarkenColor(col, amt){var usePound =false;if(col[0]=="#"){
col = col.slice(1);
usePound =true;}var num = parseInt(col,16);var r =(num >>16)+ amt;if(r >255) r =255;elseif(r <0) r =0;var b =((num >>8)&0x00FF)+ amt;if(b >255) b =255;elseif(b <0) b =0;var g =(num &0x0000FF)+ amt;if(g >255) g =255;elseif(g <0) g =0;return(usePound?"#":"")+(g |(b <<8)|(r <<16)).toString(16);}//calculate the unsigned value of the angle between two 2D vectorfunction angle(vect1, vect2){
rst = vect1.x * vect2.x + vect1.y * vect2.y;
rst /=(Math.sqrt(Math.pow(vect1.x,2)+Math.pow(vect1.y,2)))*(Math.sqrt(Math.pow(vect2.x,2)+Math.pow(vect2.y,2)));
rst =Math.acos(rst);return rst;}//Search for an intem in an array, and returns its index//If the item is present muliple times in the array, it will return the first//occurence of that item//Returns -1 if the item is missing from the arrayfunction getIndexOfItem(item, array){var index =0;while(array[index]!= item && index < array.length) index++;if(index == array.length) index =-1;return index;}//generate a random float between [ A ; B [function randomfloatAtoB ( A, B ){return( A +(Math.random()*(B-A)));}//returns a whole number in from the [A,B[ rangefunction randomintAtoB ( A, B ){return(Math.floor ( randomfloatAtoB ( A, B )));}//---------------end useful functions-----------------------------------------------functionWorld(){//Speed of the simulation when it startsvar SPEED =1;var timer =0;var canvas;var context;//define the middle of the drawing areavar centerX;var centerY;//contains all the cells from the simulationvar allCells =[];//contains all the "ships" that travels from one cell to an other var allShips =[];//array containing all the teamsvar allTeams =[];//constructor of Team objectsfunctionTeam(name, color, startingCell){var team =Object.create(teamPrototype);
team.name = name;
team.score =0;//hexadecimal value of the color of its cells
team.color = color;//contains all the cells possessed by the team
team.cells =[];
team.nbShips =0;//give a starting sell to the team, and paint it the right color
startingCell.color = team.color;
startingCell.team = team;
team.cells.push(startingCell);//create an array that contains only the cells that need to be conquered
team.possibleTargets = allCells.slice();
team.possibleTargets.splice(getIndexOfItem(startingCell, team.possibleTargets),1);
allTeams.push(team);return team;}var teamPrototype ={//no functions to be defined at the moment};//TODO???function getTeamByColor(color){for(var i =0; i<allTeams.length ; i++){if(allTeams[i].color == color)return allTeams[i];else{
console.log("geTeamByColor failed");returnundefined;}}}//constructor of cellsfunctionCell(x,y, type, color ='#555555', destination = allCells, team =undefined){var cell =Object.create(cellPrototype);//the position (x,y) described here are relative to centerX and centerY,//which define the center of the drawing area
cell.x = x;
cell.y = y;//the type of a cell is either 'small', 'average(avg)' or 'huge'//its type changes its radius, its maximum capacity, and its production//rate
cell.type = type;switch(type){case"small":
cell.radius =15;
cell.value =5;break;case"avg":
cell.radius =25;
cell.value =10;break;default:
cell.radius =50;
cell.value =20;break;}
cell.maxVal = cell.value*5;
cell.production = cell.maxVal/60;//the default color of each cell is '#555555'
cell.color = color;
cell.team = team;//when the cell is created, it is saved in an array.//the default array is 'cells[]' (which contains all cells)
destination.push(cell);return cell;}var cellPrototype ={//draw the cell on the canvas ://at the right position//with the color of its team//with its current value written in its center
draw :function(){
context.beginPath();
context.arc(centerX+this.x, centerY+this.y,this.radius,0,2*Math.PI,false);
context.fillStyle =this.color;
context.fill();
context.lineWidth =2;
context.fillStyle ='#000000';
strokeRGB = lightenDarkenColor(this.color,+100);
context.strokeStyle = strokeRGB;
context.fillText(Math.floor(this.value), centerX+this.x-1, centerY+this.y+5);
context.stroke();},//create cells symmetric to this cells (horizontal AND vertical symmetry),//add them to the array 'cells', and draw them on the canvas.
drawSymmetry :function(){var newcell =Cell(-this.x,this.y,this.type,this.color);
newcell.draw();
newcell =Cell(-this.x,-this.y,this.type,this.color);
newcell.draw();
newcell =Cell(this.x,-this.y,this.type,this.color);
newcell.draw();},//any number of cells, located evenly around this cell.//you can change what type of cell you want to produce,//and how far away they should be from this cell
drawSurround :function(nbCells, radius, type){var newCell;for(var i=0; i <2*Math.PI-0.01; i +=2*Math.PI/nbCells){
newCell =Cell(this.x+radius*Math.cos(i),this.y+radius*Math.sin(i), type);
newCell.draw();}},//calculate the direction a 'ship' needs to move towards in order to//reach its destination
setDirection :function(cell){var vect0 ={
x :1,
y :0};var trajectory ={
x : cell.x-this.x,
y : cell.y-this.y
};var ang = angle(vect0, trajectory);if(cell.y <this.y) ang =-ang;this.direction = ang;},//create a 'ship' from this cell, give half the value of the cell to//the 'ship', and give it a destination (a cell)
split :function(dest){var newShip =Cell(this.x,this.y,"small",this.color, allShips,this.team);
newShip.value =Math.floor(this.value/2);
newShip.dest = dest;
newShip.direction;
newShip.setDirection(dest);this.value =Math.floor(this.value/2);this.team.nbShips ++;},//when this 'ship' has reached its destination, it transfers its value//to the destination cell. If the value of the ship is superior to the//value of the destination, the infection will work, and the destination//will become a part of the ship's team//the arrays of the concerned teams must be updated
infect :function(){//if close enoughif(Math.abs(this.x-this.dest.x)<2*SPEED &&Math.abs(this.y-this.dest.y)<2*SPEED){//remove the ship from the array of all ships
allShips.splice(getIndexOfItem(this, allShips),1);this.team.nbShips --;//calculate the resulting value of the destinationif(this.dest.color !=this.color)this.dest.value -=this.value;elsethis.dest.value +=this.value;//if the ship was strong enough to bring the value of the destination//below zero, then change the team of the destination//and update the arrays accordinglyif(this.dest.value <0){this.dest.value =-this.dest.value;if(this.dest.color !=="#555555"){//delete cell from original team.cellthis.dest.team.cells.splice(getIndexOfItem(this.dest,this.dest.team.cells),1);//add cell to original team.targetthis.dest.team.possibleTargets.push(this.dest);}this.dest.color =this.color;this.dest.team =this.team;//delete cell from new team.targetthis.team.possibleTargets.splice(getIndexOfItem(this.dest,this.team.possibleTargets),1);//add cell to new team.cellthis.team.cells.push(this.dest);}if(this.dest.value >this.dest.maxVal)this.dest.value =this.dest.maxVal;}},
grow :function(){if(this.color !=="#555555"&&this.value <this.maxVal){this.value +=this.production;if(this.value >this.maxVal)this.value =this.maxVal;}}};//------------------------------- INIT FUNCTION ----------------------------function initContext(){
context = canvas.getContext('2d');
context.font ="bold 15px Arial";
context.textAlign ='center';}//Use the cell constructor to create the 'battlefield'//remember that all cells created are added to the array 'cells'function initStage(){var newCell =Cell(200,200,"huge");
newCell.drawSurround(6,90,"small");
newCell =Cell(500,70,"huge");
newCell =Cell(350,80,"avg");
newCell.drawSurround(3,60,"small");
newCell =Cell(90*Math.cos(Math.PI/8),90*Math.sin(Math.PI/8),"avg");
newCell =Cell(90*Math.cos(3*Math.PI/8),90*Math.sin(3*Math.PI/8),"avg");var length = allCells.length;for(var i=0; i<length ; i++){
allCells[i].draw();
allCells[i].drawSymmetry();}
newCell =Cell(0,0,"huge");
newCell.draw();
newCell =Cell(250,0,"avg");
newCell.draw();
newCell =Cell(-250,0,"avg");
newCell.draw();
newCell =Cell(0,250,"avg");
newCell.draw();
newCell =Cell(0,-250,"avg");
newCell.draw();
newCell =Cell(160,0,"small");
newCell.draw();
newCell =Cell(-160,0,"small");
newCell.draw();
newCell =Cell(0,160,"small");
newCell.draw();
newCell =Cell(0,-160,"small");
newCell.draw();}//give a name, a color, and a starting cell to all teamsfunction initTeams(){var nbTeamsCreated =0;for(var i =0; i<mindArray.length ; i++){Team(COLOR_NAME[i], COLOR_CODE[i], searchStartingCell());
mindArray[i](allTeams[i]);
nbTeamsCreated++;}while(NB_TEAMS-nbTeamsCreated >0){Team(COLOR_NAME[nbTeamsCreated], COLOR_CODE[nbTeamsCreated], searchStartingCell());
basicMind(allTeams[nbTeamsCreated]);
nbTeamsCreated++;}}function searchStartingCell(){for(var i =0; i < allCells.length ; i++){if(allCells[i].type =="huge"&& allCells[i].team ===undefined)return allCells[i];}}//-------------------------- UPDATE FUNCTIONS ------------------------------function updateChart(){for(var i =0; i<allTeams.length ; i++) allTeams[i].score =0;for(i =0; i < allCells.length ; i++){if(allCells[i].team !==undefined){
allCells[i].team.score += allCells[i].value;}}for(i =0; i < allShips.length ; i++) allShips[i].team.score += allShips[i].value;}//use the data contained in the variable 'score', and use it to draw a//cute little chart on the left side of the screenfunction drawChart(){
context.font ="12px Arial";//this position is NOT relative to centerX and centerY//these are the absolute coordinates of the canvasvar posX =25;var posY =645;//starts by drawing a black rectangle, so that the data is not drawn on//top of the data of the previous step
context.fillStyle ="#000000";
context.fillRect(posX-10,0,150, canvas.height);var widthEach =Math.floor(120/allTeams.length);for(var i =0; i<allTeams.length ; i++){
context.fillStyle = allTeams[i].color;
context.fillRect(posX, posY-allTeams[i].score/6, widthEach, allTeams[i].score/6);
context.fillStyle ="#FFFFFF";
context.fillText(Math.floor(allTeams[i].score), posX+10, posY-5-allTeams[i].score/6);
posX += widthEach;}
context.font ="bold 15px Arial";}//at each step, draw a black/transparent rectangle on top of everything,//which creates that fading effect behind the 'ships'function updateBackground(){
context.globalAlpha =0.05;
context.fillRect(0,0, canvas.width, canvas.height);
context.globalAlpha =1;}//changes the position of all the ships, one step closer to their destinationfunction move(){for(var i=0; i<allShips.length ; i++){
allShips[i].x += SPEED*Math.cos(allShips[i].direction);
allShips[i].y += SPEED*Math.sin(allShips[i].direction);
allShips[i].infect();}}//this function redraws everything at each new stepfunction update(){
updateBackground();
updateChart();
drawChart();for(var i=0; i<allCells.length ; i++){if(timer%Math.floor(1000/(33*2*SPEED))===0&& timer !==0){
allCells[i].grow();}
allCells[i].draw();}if(timer%Math.floor(1000/(33*2*SPEED))===0&& timer !==0){
TAKE_ACTION();}for(i=0; i<allShips.length ; i++){
allShips[i].draw();}}//------------------------- RUN FUNCTIONS --------------------------------------function TAKE_ACTION(){var ordersArray =[];for(var i =0; i<allTeams.length ; i++){
ordersArray = ordersArray.concat(allTeams[i].ACTION());//console.log(ordersArray.length);}for(i =0; i<ordersArray.length ; i++){//TODO : explain thisif(ordersArray[i][0].team.nbShips <14){
ordersArray[i][0].split(ordersArray[i][1]);}}}this.newRun =function(){
threeworld.init ( SKYCOLOR );
initButtons();
initMusic();
canvas = threeworld.canvas;
initContext();
centerX =30+canvas.width /2;
centerY = canvas.height /2;
initStage();
initTeams();};this.nextStep =function(){
centerX =30+canvas.width /2;
centerY = canvas.height /2;
move();
update();
timer++;};this.endRun =function(){};//------------------------- USER INTERFACE ---------------------------------//this part is there to create the 3 buttons that change the speed of the simulationfunction initButtons(){
s ="<p><button id='regularButton'>x1</button> <button id='fasterButton'>\> x2 \></button> <button id='f a s t erButton'>\>\> x4 \>\></button></p>";
$("#user_span1").html( s );
document.getElementById("regularButton").addEventListener("click", regularSpeed);
document.getElementById("fasterButton").addEventListener("click", fastSpeed);
document.getElementById("f a s t erButton").addEventListener("click", fasterSpeed);}function regularSpeed(){SPEED =1;}function fastSpeed(){SPEED =2;}function fasterSpeed(){SPEED =4;}}// ------------------------------ MUSIC ----------------------------------------var backmusic =newAudio( MUSIC_BACK );function initMusic(){
backmusic.loop =true;// loop forever
backmusic.play();
$("#w2m_audio1").html(" <img class=audiobutton onclick='backmusic.play();' width=25 src='images/audio.on.1.png' > ");
$("#w2m_audio2").html(" <img class=audiobutton onclick='backmusic.pause();' width=25 src='images/audio.off.1.png' > ");}