@ -8,10 +8,41 @@ const STATE = {
WIN : 'WIN'
} ;
const COLORS = [
'#FF6200' , // Orange
'#06E746' , // Green
'#E370FF' , // Purple
'#06D6C4' , // Turq
'#ff217c' // Pink
] ;
const ICONS = [
'assets/comet.svg' ,
'assets/moon.svg' ,
'assets/planet.svg' ,
'assets/rocket.svg' ,
'assets/spacesuit.svg' ,
'assets/spider.svg' ,
'assets/ufo.svg'
] ;
const Ricochet = function ( { messenger } ) {
this . messenger = messenger ;
this . squaresPerSide = 20 ;
// Reference lookups
this . robotIds = Array . from ( Array ( 5 ) . keys ( ) ) . map ( _ => uuid . v4 ( ) ) ;
this . colors = this . robotIds . reduce ( ( acc , id , i ) => {
acc [ id ] = COLORS [ i ] ;
return acc ;
} , { } ) ;
this . icons = this . robotIds . reduce ( ( acc , id , i ) => {
acc [ id ] = ICONS [ i ] ;
return acc ;
} , { } ) ;
// Properties that will be emitted
this . players = { } ;
this . robots = this . freshRobots ( ) ;
@ -78,17 +109,22 @@ Ricochet.prototype.removePlayer = function(id) {
//===== State generators
Ricochet . prototype . freshRobots = function ( ) {
const robots = [ '#E00000' , '#00C000' , '#0000FF' , '#00C0C0' , '#F000F0' ] ;
const icons = [ 'assets/comet.svg' , 'assets/moon.svg' , 'assets/planet.svg' , 'assets/rocket.svg' , 'assets/spacesuit.svg' ] ;
// spider.svg, ufo.svg
return robots . map ( ( color , idx ) => ( {
i : this . randomSquare ( ) ,
j : this . randomSquare ( ) ,
color ,
id : uuid . v4 ( ) ,
icon : icons [ idx ]
} ) ) ;
const result = [ ] ;
for ( let k = 0 ; k < this . robotIds . length ; k ++ ) {
const id = this . robotIds [ k ] ;
const { i , j } = this . randomUnoccupiedSquare ( ) ;
result . push ( {
i ,
j ,
color : this . colors [ id ] ,
id ,
icon : this . icons [ id ]
} ) ;
}
return result ;
} ;
Ricochet . prototype . freshWalls = function ( ) {
@ -112,8 +148,8 @@ Ricochet.prototype.freshWalls = function() {
// DO NUMBER OF CORNERS FIRST AFTER TESTING
for ( let n = 0 ; n < numberOfWalls ; n ++ ) {
const ri = this . randomSquare ( ) ;
const rj = this . randomSquare ( ) ;
break ;
// const { i: ri, j: rj } = this.randomSquare();
const isHorizontal = Math . random ( ) < 0.5 ;
@ -148,30 +184,16 @@ Ricochet.prototype.freshWalls = function() {
} ;
Ricochet . prototype . freshObjective = function ( ) {
const isValid = ( { i , j } ) => {
// Square has a robot on it.
for ( let k = 0 ; k < this . robots . length ; k ++ ) {
if ( this . robots [ k ] . i === i && this . robots [ k ] . j === j ) {
return false ;
}
}
const rand = Math . floor ( Math . random ( ) * this . robotIds . length ) ;
const id = this . robotIds [ rand ] ;
const { i , j } = this . randomUnoccupiedSquare ( ) ;
return true ;
return {
i ,
j ,
id : this . robotIds [ 0 ] , //id;
color : this . colors [ id ] ,
} ;
const objective = { i : this . robots [ 0 ] . i , j : this . robots [ 0 ] . j } ;
let counter = 0 ;
while ( isValid ( objective ) === false && counter < 20 ) {
counter ++ ;
objective . i = this . randomSquare ( ) ;
objective . j = this . randomSquare ( ) ;
}
const rand = Math . floor ( Math . random ( ) * this . robots . length ) ;
objective . id = this . robots [ 0 ] . id ;
// objective.id = this.robots[rand].id;
return objective ;
} ;
Ricochet . prototype . onMessage = function ( ws , rawBody ) {
@ -188,6 +210,7 @@ Ricochet.prototype.onMessage = function(ws, rawBody) {
}
switch ( message . type ) {
case 'newround' : this . msgNewRound ( ) ; break ;
case 'objective' : this . msgObjective ( ) ; break ;
case 'robots' : this . msgRobots ( ) ; break ;
case 'skip' : this . msgSkip ( ) ; break ;
@ -201,6 +224,34 @@ Ricochet.prototype.onMessage = function(ws, rawBody) {
} ;
//===== Message handlers
Ricochet . prototype . msgNewRound = function ( ) {
this . objective = this . freshObjective ( ) ;
this . state = STATE . PLAY ;
const lastPositions = this . winningStack . reduce ( ( acc , v ) => {
acc [ v . id ] = v ;
return acc ;
} , { } )
this . robots = Object . values ( lastPositions ) . map ( ( { i , j , id } ) => ( {
i ,
j ,
id ,
color : this . colors [ id ] ,
icon : this . icons [ id ]
} ) ) ;
this . countdownTimer = null ;
this . countdownTimestamp = null ;
this . winningPlayerId = null ;
this . winningStack = null ;
this . messenger . messageAll ( { type : 'objective' , body : this . objective } ) ;
this . messenger . messageAll ( { type : 'state' , body : this . state } ) ;
this . messenger . messageAll ( { type : 'robots' , body : this . robots } ) ;
} ;
Ricochet . prototype . msgObjective = function ( ) {
this . objective = this . freshObjective ( ) ;
this . messenger . messageAll ( { type : 'objective' , body : this . objective } ) ;
@ -240,7 +291,50 @@ Ricochet.prototype.msgSolve = function(message) {
//===== Helper functions
Ricochet . prototype . randomSquare = function ( ) {
return Math . floor ( Math . random ( ) * this . squaresPerSide ) ;
return {
i : Math . floor ( Math . random ( ) * this . squaresPerSide ) ,
j : Math . floor ( Math . random ( ) * this . squaresPerSide )
} ;
} ;
Ricochet . prototype . randomUnoccupiedSquare = function ( ) {
let result = this . randomSquare ( ) ;
let CONTROL _COUNTER = 0 ;
while ( this . isSquareOccupied ( result ) && CONTROL _COUNTER < 20 ) {
CONTROL _COUNTER ++ ;
result = this . randomSquare ( ) ;
}
if ( CONTROL _COUNTER > 19 ) {
console . log ( ` ================== \n \n CRITICAL ERROR! \n \n randomUnoccupiedSquare() while() short-circuited! \n \n ================== ` ) ;
}
return result ;
} ;
Ricochet . prototype . isSquareOccupied = function ( { i , j } ) {
if ( i < 0 || i > this . squaresPerSide ) {
return true ;
}
if ( j < 0 || j > this . squaresPerSide ) {
return true ;
}
if ( this . robots ) {
for ( let k = 0 ; k < this . robots . length ; k ++ ) {
if ( this . robots [ k ] . i === i && this . robots [ k ] . j === j ) {
return true ;
}
}
}
if ( this . objective && i === this . objective . i && j === this . objective . j ) {
return true ;
}
return false ;
} ;
Ricochet . prototype . sanitizeStack = function ( rawMoveStack ) {