Javascript: Can't find errors in graphical genetic algorithm - javascript

I'm quite new to Javascript, and I've been working on a graphic-based genetic algorithm. However, I think I'm getting some tunnel vision after working on it a while and I can't seem to catch what's going wrong?
I'm using Javascript with p5.js.
Problem described below.
Premise
Create a bunch of red dots with probability-based movement. Fitness determined by how many randomly placed green dots they eat. Evolve to eat more.
Errors
When I run it, a green dot always appears in the upper left even though they should be randomly placed.
(RESOLVED) The breeding function doesn't seem to work properly. It should:
Create an array for the next generation (this works)
Draw random parents from mating pool (this works)
Randomly cross their chromosome arrays to form a new individual (not sure)
Apply mutation chance for each new individual (not sure)
Store offspring in the new generation (this works)
Replace a random offspring with fittest member of last generation (not sure)
Replace current generation array with new generation array (not sure)
Code
var settings = {
populationSize : 25,
geneLength : 8,
mutationProbability : 0.01,
forestSize : 1500,
rows : 124,
cols : 249,
year : 250,
end : 20,
};
function onCanvas(position){
return position*4+2;
}
function randombetween(min, max){
return Math.random()*max;
}
//set up sheep
var population = new Population(settings.populationSize, settings.geneLength);
function Sheep(g, dna){
this.genLen = g;
this.state = 0;
this.fitness=0;
this.xpos = Math.floor(Math.random()*settings.cols);
this.ypos = Math.floor(Math.random()*settings.rows);
this.chromosome = new Array(this.genLen);
if (dna != null){
this.chromosome = dna;
} else{
for(var x=0; x<this.genLen; x+=4){
this.chromosome[x] = Math.random();
this.chromosome[x+1] = randombetween(0, 1-this.chromosome[x]);
this.chromosome[x+2] = randombetween(0, 1-this.chromosome[x]-this.chromosome[x+1]);
this.chromosome[x+3] = 1-this.chromosome[x]-this.chromosome[x+1]-this.chromosome[x+2];
}
}
}
function Population(p, g){
this.popSize = p;
this.sheep = [];
this.matingPool = [];
this.maxFit;
this.maxFitIndex;
for (var x = 0; x < this.popSize; x++) {
this.sheep[x] = new Sheep(g, null);
}
this.evaluate = function() {
//find maximum fitness in generation
this.maxFit = 0;
this.maxFitIndex = 0;
for (var x = 0; x < this.popSize; x++) {
//this.sheep[x].calcFitness();
if (this.sheep[x].fitness > this.maxFit){
this.maxFitIndex = x;
this.maxFit = this.sheep[x].fitness;
}
}
//document.write("Maximum fitness: " + this.maxFit);
//normalize fitness
for (var i = 0; i < this.popSize; i++) {
this.sheep[i].fitness /= this.maxFit;
}
//reset mating pool every generation
this.matingPool = [];
//higher fitness means more representation in the pool
for (var i = 0; i < this.popSize; i++) {
var n = this.sheep[i].fitness *10;
for (var j = 0; j < n; j++) {
this.matingPool.push(this.sheep[i]);
}
}
}
//create children sheep
this.breed = function (){
var newsheep = [];
for (var i = 0; i < this.popSize; i++){
//pick random parents from the mating pool
let parentA = this.matingPool[Math.floor(Math.random()*this.matingPool.length)];
let parentB = this.matingPool[Math.floor(Math.random()*this.matingPool.length)];
//parent genes are randomly crossed
var newchromosome = [];
var midpoint = Math.floor(Math.random()*g);
for (var j = 0; j < g; j++){
if (j > midpoint){
newchromosome[j] = parentA.chromosome[j];
} else{
newchromosome[j] = parentB.chromosome[j];
}
}
//offspring may be mutated
if(Math.random()<=settings.mutationProbability){
newchromosome[Math.floor(Math.random()*g)]=Math.floor(Math.random()*10+1);
}
newsheep[i] = new Eater(g, newchromosome);
}
//elite offspring survive into next generation, replacing a random offspring
var random = Math.floor(Math.random()*this.popSize);
if(Math.random()<=settings.mutationProbability){
this.sheep[this.maxFitIndex].chromosome[Math.floor(Math.random()*g)]=Math.floor(Math.random()*10+1);
}
for(var x = 0; x < g; x++){
newsheep[random].chromosome[x] = this.sheep[this.maxFitIndex].chromosome[x];
}
//update array of sheep
for(var x=0; x<this.popSize; x++){
this.sheep[x] = newsheep[x];
}
}
}
//set up trees
var forest = new Forest(settings.forestSize);
function radialTreePopulation(x,y,r,count){
let trees = [];
for(let i = 0;i < count; i++){
trees.push({
posx : (x + Math.floor((Math.random()* r) * (Math.random() < 0.5 ? -1 : 1))),
posy : (y + Math.floor((Math.random()* r) * (Math.random() < 0.5 ? -1 : 1)))
});
}
return trees;
}
function Forest(f){
this.forSize = f/ 75;
this.trees = [];
for (var x = 0; x < this.forSize ; x++) {
this.trees.push(...radialTreePopulation(
(Math.floor(Math.random()*(settings.cols-20)+10))| 0,
(Math.floor(Math.random()*(settings.rows-20)+10))| 0,
11,
75)
);
}
}
//evaluate how to move
function moveHungry(x, move){
if(move<population.sheep[x].chromosome[0]){
return 0;
}
else if(move-population.sheep[x].chromosome[0]<population.sheep[x].chromosome[1]){
return 1;
}
else if(move-population.sheep[x].chromosome[0]-population.sheep[x].chromosome[1]<population.sheep[x].chromosome[2]){
return 2;
}
else{
return 3;
}
}
function moveEaten(x,move){
if(move<population.sheep[x].chromosome[4]){
return 0;
}
else if(move-population.sheep[x].chromosome[4]<population.sheep[x].chromosome[5]){
return 1;
}
else if(move-population.sheep[x].chromosome[4]-population.sheep[x].chromosome[5]<population.sheep[x].chromosome[6]){
return 2;
}
else{
return 3;
}
}
//count generations and days
var generation=0;
var counter = 0;
//create world
function createWorld(){
background("lightblue");
fill(0,255,0);
for(var x=0; x<settings.forestSize; x++){
rect(onCanvas(forest.trees[x].posx), onCanvas(forest.trees[x].posy), 4, 4);
}
fill(255,0,0);
for(var x=0; x<settings.populationSize; x++){
population.sheep[x].state=0;
rect(onCanvas(population.sheep[x].xpos), onCanvas(population.sheep[x].ypos), 4, 4);
}
//remove eaten trees
for(var x=0; x<settings.populationSize; x++){
for(var y=0; y<settings.forestSize; y++){
if(population.sheep[x].xpos==forest.trees[y].posx && population.sheep[x].ypos==forest.trees[y].posy){
forest.trees[y].posx=null;
forest.trees[y].posy=null;
population.sheep[x].state=1;
population.sheep[x].fitness++;
}
}
}
//move sheep based on chromosome
for(var x=0; x<settings.populationSize; x++){
var move = Math.random();
if(population.sheep[x].state==0){
switch(moveHungry(x, move)){
case 0: //up
if(population.sheep[x].ypos>0)
population.sheep[x].ypos-=1;
break;
case 1: //down
if(population.sheep[x].ypos<settings.rows-1)
population.sheep[x].ypos+=1;
break;
case 2: //right
if(population.sheep[x].xpos<settings.cols-1)
population.sheep[x].xpos+=1;
break;
case 3: //left
if(population.sheep[x].xpos>0)
population.sheep[x].xpos-=1;
}
}
else {
switch(moveEaten(x, move)){
case 0: //up
if(population.sheep[x].ypos>0)
population.sheep[x].ypos-=1;
break;
case 1: //down
if(population.sheep[x].ypos<settings.rows-1)
population.sheep[x].ypos+=1;
break;
case 2: //right
if(population.sheep[x].xpos<settings.cols-1)
population.sheep[x].xpos+=1;
break;
case 3: //left
if(population.sheep[x].xpos>0)
population.sheep[x].xpos-=1;
}
}
}
counter++;
}
function reset(){
counter=0;
//regrow forest
forest = new Forest(settings.forestSize);
//reset locations and fitness values
for(var x=0; x<settings.populationSize; x++){
population.sheep[x].xpos = Math.floor(Math.random()*settings.cols);
population.sheep[x].ypos = Math.floor(Math.random()*settings.rows);
population.sheep[x].fitness=0;
}
}
function setup() {
createCanvas(1000, 500);
}
function draw() {
createWorld();
if(counter>=settings.year){
population.evaluate();
population.breed();
reset();
generation++;
if(generation>=settings.end){
noLoop();
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.min.js"></script>

Related

Generating random path in 2d array using javascript

I am trying to make a path in 2d array it supposes to go from point A to B currently I only try to make a path currently I have this script below some time it works sometimes it gets stuck in an endless loop.
My final goal is to make three random paths going from point A to B, C, D...
I hope you guys can help me.
I don't want to use a star since I want it to be random and not the shortest path.
var startRow = 0;
var startCol = 0;
var curRowPos = 0;
var curColPos = 0;
var width = 10;
var height = 10;
var mapCode = 0;
var finalCode = 0;
var dirction = [];
var map = GenerateArray(width,height,true);
var pos = {
start : [],
end : [],
}
GeneratePath();
printmap();
function printmap(){
var res = '';
console.log('-----------------------------------')
for(var i = 0; i < width; i++){
for(var j = 0; j < height; j++){
res += map[i][j] +','
}
res += '\n'
}
console.log(res)
console.log('-----------------------------------')
}
function GenerateArray(width,height,empty){
var arr = new Array(2);
for (var x = 0; x < width; x++){
arr[x] = new Array(2);
for (var y = 0; y < height; y++){
arr[x][y] = 0;
}
}
return arr;
}
function GeneratePath()
{
startRow = curRowPos = Math.floor(Math.random() * width);
curColPos = startCol; // pick starting column, row is 0
map[startRow][ startCol] = 1; // assign 1 to start square
pos.start = [startRow,startCol]
while ( finalCode == 0 )
{
getDirections();
SelectDir();
printmap(); // random selection of available directions
}
return;
}
function getDirections(){
var N ,S,W,E;
N = curRowPos - 1 > 0 && map[curRowPos - 1][ curColPos] == 0;
S = curRowPos + 1 < width && map[curRowPos + 1][ curColPos] == 0;
W = curColPos + 1 < height && map[curRowPos ][ curColPos+ 1] == 0;
E = curColPos -1 >= 0 && curColPos < height && map[curRowPos ][ curColPos- 1] == 0 ;
direction = [];
if(N){
direction.push("north");
}
if(S){
direction.push("south");
}
if(W){
direction.push("west");
}
if(E){
direction.push("east");
}
}
function SelectDir(){
var select = 0;
var selection = "";
if (direction.length != 0) // select random direction from list
{
select = Math.floor(Math.random() * direction.length);
selection = direction[select];
}
else selection = "blocked"; // no moves available
if (curColPos == width-1)
{
finalCode = 1; // set final square if row 7
}
if(finalCode == 1){
pos.end = [startRow,startCol]
return;
}
switch (selection)
{
case "blocked":
map[curRowPos][ curColPos] = -1;
//BackUp(); // back up to last avail square with move options
break;
case "north":
curRowPos = curRowPos - 1;
map[curRowPos][curColPos] = 1;
direction = [];
break;
case "south":
curRowPos = curRowPos + 1;
map[curRowPos][curColPos] = 1;
direction = [];
break;
case "east":
curColPos = curColPos - 1;
map[curRowPos][curColPos] = 1;
direction = [];
break;
case "west":
curColPos = curColPos + 1;
map[curRowPos][curColPos] = 1;
direction = [];
break;
default:
break;
}
return;
}
function BackUp()
{
console.log("backup")
map[curRowPos][curColPos] = 0; // set element to indicate no movement
direction = [];
var tempN = 0;
var tempS = 0;
var tempE = 0;
var tempW = 0;
// start logic to determine last space before dead end.
// gets mapCode for surrounding square, assign to temp int.
printmap();
if (curRowPos < width)
{
tempN = map[curRowPos-1][ curColPos];
}
if (curRowPos > 0)
{
tempS = map[curRowPos + 1][ curColPos];
}
if (curColPos < width)
{
tempE = map[curRowPos][ curColPos-1];
}
if (curColPos > 0)
{
tempW = map[curRowPos][ curColPos+1];
}
// determine highest value of temp int's. Highest value is the
// square previous to dead end. Set curRowPos or or curColPos accordingly.
if (tempN > tempS)
{
if (tempN > tempE)
{
if (tempN > tempW)
{
curRowPos = curRowPos + 1;
return;
}
else
{
curColPos = curColPos - 1;
return;
}
}
else if (tempE > tempW)
{
curColPos = curColPos + 1;
return;
}
else
{
curColPos = curColPos - 1;
return;
}
}
else if (tempS > tempE)
{
if (tempS > tempW)
{
curRowPos = curRowPos - 1;
return;
}
else
{
curColPos = curColPos - 1;
return;
}
}
else if (tempE > tempW)
{
curColPos = curColPos + 1;
return;
}
else
{
curColPos = curColPos - 1;
return;
}
}
First of all, I would not use global variables for that, as that makes the code more difficult to understand when you want to read it later on. Replacing them with function arguments should work in this case.
It seems that hitting a dead end will make the algorithm reach an endless loop - as it won't do anything in that case.
There are two more problems - the first one is, how do you define a random path? From what distribution should it be? Should it be a random shortest path? (Generally, the shortest path isn't unique.) Should it be as long as possible? (That's the Traveling Salesman Problem, something I believe you want to avoid)
This brings me to the second problem - the backtracking will make it take exponential time if unlucky. Maybe you want the path to be short, but not always the shortest path. In that case, the A* algorithm can still be used! Feeding it random weights for the edges will make it take a path that is still the shortest according to some metric, but that metric will be different for different paths - and this is even parametrizable - adding less noise will make the resulting path shorter and closer to the shortest path, while adding more noise will make it the algorithm take longer (but still quadratic time because this is the worst case of A*)

Js Multi-dimensional Array setting value oddly

I've made a multidimensional array with Array constructor and Array.fill method.
I cannot figure out where the problem is, but this code doesn't work as I want.
function loadChunk(){
for(var x = 0; x< 3; x++){
for(var y= 0; y < 3; y++){
console.log(x+","+y);
console.log((world[x][y]).loaded);
if(!(world[x][y]).loaded){
world[x][y].loaded=true;
}
}
}
}
function createWorld(w, d){
var worldz = new Array(d * 2 + 1);
var world = new Array(w * 2 + 1);
world.fill(worldz);
for(var x = 0; x< w * 2+ 1; x++){
for(var z = 0; z < d * 2 + 1; z++){
world[x][z]= { loaded: false };
}
}
return world;
}
var world = createWorld(1, 1);
Start();
function Start(){
loadChunk();
}
You can see what is happening with console.
With my view, no true should be written on console.
The problem is, if I edit world[0][n],then world[1 or more][n] changes too.
Replace your createWorld function with this:
function createWorld(w, d){
var world = new Array(w * 2 + 1);
for(var x = 0; x< w * 2+ 1; x++){
// each item of the array requires a new instance
// you should not use fill method in this situation
world[x]=new Array(d * 2 + 1);
for(var z = 0; z < d * 2 + 1; z++){
world[x][z]= { loaded: false };
}
}
return world;
}
function loadChunk() {
for (var x = 0; x < 3; x++) {
for (var y = 0; y < 3; y++) {
console.log(x + "," + y, (world[x][y]).loaded);
if (!(world[x][y]).loaded) {
world[x][y].loaded = true;
}
}
}
}
function createWorld(w, d) {
var world = [];
for (var x = 0; x < w * 2 + 1; x++) {
world[x] = [];
for (var z = 0; z < d * 2 + 1; z++) {
world[x][z] = {loaded: false};
}
}
return world;
}
var world = createWorld(1, 1);
Start();
function Start() {
loadChunk();
}
The problem that you expirience is that you fill "rows" of world with the same array, so world[0] === world[1] && world[1] === world[2] because array variable worldz is holding a reference
The best way to learn your problem is doing next thing:
function createWorld(w, d){
var worldz = new Array(d * 2 + 1);
var world = new Array(w * 2 + 1);
world.fill(worldz);
for(var x = 0; x< w * 2+ 1; x++){
for(var z = 0; z < d * 2 + 1; z++){
world[x][z]= { loaded: false };
debugger;
}
}
return world;
}
And inspecting in chrome debugger what happens with world variable on a first step
The reason why a change of world[0][0] also changes world[1][0] and world[2][0] (same for other indecees of worldz) is that world.fill(worldz) makes all elements of world the same identical object (Array) worldz.
To avoid this every element of world should be a new Array like eg:
for(n=0,max=world.length;n<max;n++) {world[n] = new Array(d * 2 + 1);}

Making a canvas using p5.js

enter image description hereI got an exercise , where i have to create a rectangle-canvas using p5.js , but that canvas will consist small rects ,so i do it , but there is also 1 point in the exrecise . How can i get those small rects in 2 different colors , but 50% of those colores must be green and the other red , using matrix .
Here is the code .
var matrix = [
];
var ab = 36;
for (var y = 0; y < ab; y++) {
matrix.push([])
for (var x = 0; x < 36; x++) {
matrix[y][x] = Math.floor(Math.random() * 2)
}
}
console.log(matrix)
var side = 16;
function setup() {
createCanvas(matrix[0].length * side, matrix.length * side);
background('#acacac');
frameRate()
}
function draw() {
for (var y = 0; y < matrix.length; y++) {
for (var x = 0; x < matrix[y].length; x++) {
if (matrix[y][x] == 0) {
fill(0, 255, 0)
rect(y * side, x * side, side, side)
}
else if (matrix[y][x] == 1) {
fill("red")
rect(y * side, x * side, side, side)
}
function Shuffle (arguments) {
for(var k = 0; k < arguments.length; k++){
var i = arguments[k].length;
if ( i == 0 ) return false;
else{
while ( --i ) {
var j = Math.floor( Math.random() * ( i + 1 ) );
var tempi = arguments[k][i];
var tempj = arguments[k][j];
arguments[k][i] = tempj;
arguments[k][j] = tempi;
}
return arguments;
}
}
}
so as discussed in comments , the problem reduces to filling exactly half the matrix with one color and other half with other.
your matrix is in two dimension i will give a solution in one dimension, which should be quite easy to extend to 2-d
var count = 0;
var arr = [];
for( var i = 0 ;i < ab;i++){
arr[i] = 0;
}
while(true) {
var i = floor(random(ab));
if(arr[i] !==1) {
arr[i] = 1;
count++;
}
if(count === ab/2) break; // assume ab is even
}
there is one more way
fill half the array with 1 and half with 0 and then shuffle the array
you can very easily google algorithms for shuffling,
one pseudocode i could find
// after filling half elements with 1 and half with zero
// To shuffle an array a of n elements (indices 0..n-1):
for i from n - 1 downto 1 do
j = random integer with 0 <= j <= i
exchange a[j] and a[i]
source: https://www.geeksforgeeks.org/shuffle-a-given-array/
There it is my problem
var matrix = [
];
var ab = 36;
for (var y = 0; y < ab; y++) {
matrix.push([])
for(var x = 0 ; x<ab;x++){
matrix[y][x] = Math.floor(Math.random()*1)
}
for(var x = 0 ; x<ab/2;x++){
matrix[y][x] = 1
}
}
var count = 0;
var arr = [];
for( var i = 0 ;i < ab;i++){
arr[i] = 0;
}
while(true) {
var i = Math.floor(Random(ab));
if(arr[i] !==1) {
arr[i] = 1;
count++;
}
if(count === ab/2) break; // assume ab is even
}
console.log(arr)
var side = 16;
function setup() {
createCanvas(arr[0].length * side, arr.length * side);
background('#acacac');
frameRate()
}
function draw() {
for (var y = 0; y < arr.length; y++) {
for (var x = 0; x < arr[y].length; x++) {
if (matrix[y][x] == 0) {
fill(0, 255, 0)
rect(y * side, x * side, side, side)
}
else if (matrix[y][x] == 1) {
fill("red")
rect(y * side, x * side, side, side)
}
else if (matrix[y][x] == 2) {
fill(255, 255, 0)
rect(y * side, x * side, side, side)
}
else if (matrix[y][x] == 3) {
fill(255, 0, 0)
rect(y * side, x * side, side, side)
}
}
}
}

advice with my javascript collision detection

I'm attempting to make a top-down shooter style game reminiscent of the old Galaga games.
I've got the player and enemies and projectiles moving and working fine apart from when I try to check for collisions between the bullets being fired by the player and the enemy spaceships.
both the bullets and enemies are made using constructors and then placed in an array to keep track of them.
//due to the number of enemies on screen they'll be held in an array
var enemies = [];
for(e = 0; e < enemies; e++) {
enemies[e] = [];
enemies[e] = {x:0,y:0};
}
//class constructor to create enemies
class enemy {
constructor(x,y) {
this.enemyX = x;
this.enemyY = y;
this.enemyWidth = 32;
this.enemyHeight = 32;
}
}
//variable array for the bullets
var playerBullets = [];
for(i = 0; i < playerBullets; i++) {
playerBullets[i] = { x: 0, y: 0 };
}
//class constructor to create the bullets
class bullet {
constructor(x,y){
this.bulletX = x;
this.bulletY = y;
this.bulletWidth = 5;
this.bulletHeight = 5;
}
}
I have tried to make a collision detector function that first goes through the array of bullets and then the array of enemies and checks for overlapping borders and to give an alert when a collision has been found, but I'm having trouble with it. If anyone can help I would greatly appreciate it.
//code for detecting collisions from the bullets
function collisionDetection() {
for(i = 0; i < playerBullets.length; i++) {
for(e = 0; e < enemies.length; e++) {
if (playerBullets[i].x < enemies.x + enemy.width &&
playerBullets[i].x + bullet.width > enemies.x &&
playerBullets[i].y < enemies.y + enemy.height &&
playerBullets[i].y + bullet.height > enemies.y){
alert("HIT");
}
}
}
}
you missed the index of the enemies: enemies[e] and enemy has enemyX enemyY enemyWidth and enemyHeight property, and bullets has: bulletX, bulletY bulletWidth bulletHeight
function collisionDetection() {
for(i = 0; i < playerBullets.length; i++) {
for(e = 0; e < enemies.length; e++) {
if (playerBullets[i].bulletX < enemies[e].enemyX + enemies[e].enemyWidth &&
playerBullets[i].bulletX + playerBullets[i].bulletWidth > enemies[e].enemyX &&
playerBullets[i].bulletY < enemies[e].enemyY + enemies[e].enemyHeight &&
playerBullets[i].bulletY + playerBullets[i].bulletHeight > enemies[e].enemyY){
alert("HIT");
}
}
}
}

Javascript while loop (Card deck simulation)

I am having an issue with the following code that simulates a card deck.
The deck is created properly (1 array containing 4 arrays (suits) containing 13 elements each (face values)) and when I use the G.test(); function it is correctly pulling 13 random cards but then returns 39x "Empty" (A total of 52).
I hate to ask for help, but I have left the problem overnight and then some and I still cannot find the reason that this is happening. I appreciate any and all insight that can be offered.
var G = {};
G.cards = [[], [], [], []];
G.newCard = function(v) { //currently a useless function, tried a few things
return v;
};
G.deck = {
n: function() { //new deck
var x; var list = [];
list.push(G.newCard("A"));
for (x = 2; x <= 10; x += 1) {
list.push(G.newCard(x.toString()));
}
list.push(G.newCard("J"), G.newCard("Q"), G.newCard("K"));
for (x = 0; x < G.cards.length; x += 1) {
G.cards[x] = list;
}
},
d: function() { //random card - returns suit & value
var s; var c; var v; var drawn = false; var n;
s = random(0, G.cards.length);
c = random(0, G.cards[s].length);
n = 0;
while (!drawn) {
if (G.cards[s].length > 0) {
if (G.cards[s][c]) {
v = G.cards[s].splice(c, 1);
drawn = true;
} else {
c = random(0, G.cards[s].length);
}
} else {
s = (s + 1 >= G.cards.length) ? 0 : s + 1;
n += 1;
console.log(s);
if (n >= G.cards.length) {
console.log(n);
return "Empty";
}
}
}
return {s: s, v: v[0]};
},
}; //G.deck
G.test = function() {
var x; var v;
G.deck.n();
for (x = 0; x < 52; x += 1) {
v = G.deck.d();
console.log(v);
}
};
Replace
for (x = 0; x < G.cards.length; x += 1) {
G.cards[x] = list;
}
with
for (x = 0; x < G.cards.length; x += 1) {
G.cards[x] = list.slice();
}
as this prevents all elements of G.cards[x] binding to the same (single) array instance.
If all elements bind to the same instance, mutating one element equals mutating all elements. list.slice() creates a new copy of list and thus a new array instance to prevent the aforementioned issue.
I won't go through your code, but I built a code that will do what you wanted. I only built this for one deck and not multiple deck play. There are two functions, one will generate the deck, and the other will drawn cards from the deck, bases on how many hands you need and how many cards you wanted for each hand. One a card is drawn, it will not be re-drawn. I might publish a short article for how a card dealing program work or similar in the short future at http://kevinhng86.iblog.website.
function random(min, max){
return Math.floor(Math.random() * (max - min)) + min;
}
function deckGenerate(){
var output = [];
var face = {1: "A", 11: "J", 12: "Q", 13: "K"};
// Heart Space Diamond & Club;
var suit = ["H", "S", "D", "C"];
// Delimiter between card identification and suit identification.
var d = "-";
for(i = 0; i < 4; i++){
output[i] = [];
for(ind = 0; ind < 13; ind++ ){
card = (ind + 1);
output[i][ind] = (card > 10) || (card === 1)? face[card] + d + suit[i] : card.toString() + d + suit[i];
}
}
return output;
}
function randomCard(deck, hand, card){
var output = [];
var randS = 0;
var randC = 0;
if( hand * card > 52 ) throw("Too many card, I built this for one deck only");
for(i = 0; i < hand; i++){
output[i] = [];
for(ind = 0; ind < card; ind++){
randS = random(0, deck.length);
randC = random(0, deck[randS].length);
output[i][ind] = deck[randS][randC];
deck[randS].splice(randC,1);
if(deck[randS].length === 0) deck.splice(randS,1);
}
}
document.write( JSON.stringify(deck, null, 2) );
return output;
}
var deck = deckGenerate()
document.write( JSON.stringify(deck, null, 2) );
document.write("<br><br>");
var randomhands = randomCard(deck, 5, 8);
document.write("<br><br>");
document.write("<br><br>");
document.write( JSON.stringify(randomhands, null, 2) );

Categories

Resources