|  |  |  | @ -1,4 +1,4 @@ | 
			
		
	
		
			
				
					|  |  |  |  | const [EMPTY, FOOD, SUPER_FOOD, WALL, FIRE, HOLE, HOLE_S, SNAKE]=Array(7).keys(); | 
			
		
	
		
			
				
					|  |  |  |  | const [EMPTY, FOOD, SUPER_FOOD, DECAY_FOOD, WALL, FIRE, HOLE, HOLE_S, SNAKE]=Array(255).keys(); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | class SnekGame { | 
			
		
	
		
			
				
					|  |  |  |  | 	constructor(settings, canvas, rules) { | 
			
		
	
	
		
			
				
					|  |  |  | @ -18,6 +18,7 @@ class SnekGame { | 
			
		
	
		
			
				
					|  |  |  |  | 							case ' ': return EMPTY; | 
			
		
	
		
			
				
					|  |  |  |  | 							case 'f': return FOOD; | 
			
		
	
		
			
				
					|  |  |  |  | 							case 'F': return SUPER_FOOD; | 
			
		
	
		
			
				
					|  |  |  |  | 							case 'd': return DECAY_FOOD; | 
			
		
	
		
			
				
					|  |  |  |  | 							case 'w': return WALL; | 
			
		
	
		
			
				
					|  |  |  |  | 							case 'o': return HOLE; | 
			
		
	
		
			
				
					|  |  |  |  | 							case 'i': return FIRE; | 
			
		
	
	
		
			
				
					|  |  |  | @ -37,6 +38,15 @@ class SnekGame { | 
			
		
	
		
			
				
					|  |  |  |  | 						if(c==FOOD) this.fruits.push([x, y]); | 
			
		
	
		
			
				
					|  |  |  |  | 					} | 
			
		
	
		
			
				
					|  |  |  |  | 				)); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 			// extract the decaying fruits
 | 
			
		
	
		
			
				
					|  |  |  |  | 			this.decayFood=[]; | 
			
		
	
		
			
				
					|  |  |  |  | 			this.world | 
			
		
	
		
			
				
					|  |  |  |  | 				.forEach((l, x) => l.forEach( | 
			
		
	
		
			
				
					|  |  |  |  | 					(c, y) => { | 
			
		
	
		
			
				
					|  |  |  |  | 						if(c==DECAY_FOOD) this.decaying.push([x, y, 0]); | 
			
		
	
		
			
				
					|  |  |  |  | 					} | 
			
		
	
		
			
				
					|  |  |  |  | 				)); | 
			
		
	
		
			
				
					|  |  |  |  | 		} else { // dimension and objects
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 			// get the dimensions
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -64,6 +74,14 @@ class SnekGame { | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 			// add the super food
 | 
			
		
	
		
			
				
					|  |  |  |  | 			if(settings.superFood) settings.superFood.forEach(([x, y]) => this.world[x][y]=SUPER_FOOD); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 			// add the decaying food
 | 
			
		
	
		
			
				
					|  |  |  |  | 			if(settings.decayFood) { | 
			
		
	
		
			
				
					|  |  |  |  | 				settings.decayFood.forEach(([x, y]) => this.world[x][y]=DECAY_FOOD); | 
			
		
	
		
			
				
					|  |  |  |  | 				this.decayFood=settings.decayFood.map(([x, y]) => [x, y, 0]); | 
			
		
	
		
			
				
					|  |  |  |  | 			} else { | 
			
		
	
		
			
				
					|  |  |  |  | 				this.decayFood=[]; | 
			
		
	
		
			
				
					|  |  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		// add the snake to the world
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -93,6 +111,7 @@ class SnekGame { | 
			
		
	
		
			
				
					|  |  |  |  | 		this.rules=Object.assign({ | 
			
		
	
		
			
				
					|  |  |  |  | 			fruitRegrow: true, | 
			
		
	
		
			
				
					|  |  |  |  | 			superFruitGrow: false, | 
			
		
	
		
			
				
					|  |  |  |  | 			decayingFruitGrow: false, | 
			
		
	
		
			
				
					|  |  |  |  | 			speedIncrease: true, | 
			
		
	
		
			
				
					|  |  |  |  | 			worldWrap: true, | 
			
		
	
		
			
				
					|  |  |  |  | 			winCondition: 'none', | 
			
		
	
	
		
			
				
					|  |  |  | @ -151,6 +170,7 @@ class SnekGame { | 
			
		
	
		
			
				
					|  |  |  |  | 		const hole=assets.get('hole'); | 
			
		
	
		
			
				
					|  |  |  |  | 		const fire=assets.get('fire'); | 
			
		
	
		
			
				
					|  |  |  |  | 		const superFruit=assets.get('superFruit'); | 
			
		
	
		
			
				
					|  |  |  |  | 		const decayFruit=assets.get('decayFruit'); | 
			
		
	
		
			
				
					|  |  |  |  | 		const putTile=(x, y, tile) => this.ctx.drawImage( | 
			
		
	
		
			
				
					|  |  |  |  | 			tile, | 
			
		
	
		
			
				
					|  |  |  |  | 			offsetX+cellSize*x, | 
			
		
	
	
		
			
				
					|  |  |  | @ -161,6 +181,9 @@ class SnekGame { | 
			
		
	
		
			
				
					|  |  |  |  | 		const putTileAnim=(x, y, tile) => putTile(x, y, tile[ | 
			
		
	
		
			
				
					|  |  |  |  | 			Math.floor(Date.now()/1000*60+x+y)%tile.length | 
			
		
	
		
			
				
					|  |  |  |  | 		]); | 
			
		
	
		
			
				
					|  |  |  |  | 		const putTileAnimPercent=(x, y, tile, percent) => putTile(x, y, tile[ | 
			
		
	
		
			
				
					|  |  |  |  | 			Math.min(Math.round(percent*tile.length), tile.length-1) | 
			
		
	
		
			
				
					|  |  |  |  | 		]); | 
			
		
	
		
			
				
					|  |  |  |  | 		const checkAdj=(x, y) => { | 
			
		
	
		
			
				
					|  |  |  |  | 			let adj={}; | 
			
		
	
		
			
				
					|  |  |  |  | 			adj.u=this.world[x][y-1]; | 
			
		
	
	
		
			
				
					|  |  |  | @ -204,6 +227,11 @@ class SnekGame { | 
			
		
	
		
			
				
					|  |  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		// draw our decaying fruits
 | 
			
		
	
		
			
				
					|  |  |  |  | 		this.decayFood.forEach(([x, y, birth]) => | 
			
		
	
		
			
				
					|  |  |  |  | 			putTileAnimPercent(x, y, decayFruit, (this.playTime-birth)/2000) | 
			
		
	
		
			
				
					|  |  |  |  | 		); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		// draw our snake
 | 
			
		
	
		
			
				
					|  |  |  |  | 		const snake=assets.get('snake'); | 
			
		
	
		
			
				
					|  |  |  |  | 		this.ctx.fillStyle=snake.color; | 
			
		
	
	
		
			
				
					|  |  |  | @ -377,6 +405,14 @@ class SnekGame { | 
			
		
	
		
			
				
					|  |  |  |  | 				this.score+=10; | 
			
		
	
		
			
				
					|  |  |  |  | 				break; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 			// you eat, you get a small score boost
 | 
			
		
	
		
			
				
					|  |  |  |  | 			case DECAY_FOOD: | 
			
		
	
		
			
				
					|  |  |  |  | 				this.score+=5; | 
			
		
	
		
			
				
					|  |  |  |  | 				this.decayFood=this.decayFood.filter( | 
			
		
	
		
			
				
					|  |  |  |  | 					([x, y, _]) => !(x==head[0] && y==head[1]) | 
			
		
	
		
			
				
					|  |  |  |  | 				); | 
			
		
	
		
			
				
					|  |  |  |  | 				break; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 			// you eat, you grow
 | 
			
		
	
		
			
				
					|  |  |  |  | 			case FOOD: | 
			
		
	
		
			
				
					|  |  |  |  | 				// re-grow the snake
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -421,6 +457,15 @@ class SnekGame { | 
			
		
	
		
			
				
					|  |  |  |  | 					} | 
			
		
	
		
			
				
					|  |  |  |  | 				} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 				if(this.rules.decayingFruitGrow) { | 
			
		
	
		
			
				
					|  |  |  |  | 					if(Math.random()<.2) { // 20% chance
 | 
			
		
	
		
			
				
					|  |  |  |  | 						const emptyCells=getEmptyCells(); | 
			
		
	
		
			
				
					|  |  |  |  | 						const cell=emptyCells[Math.floor(Math.random()*emptyCells.length)]; | 
			
		
	
		
			
				
					|  |  |  |  | 						this.world[cell[0]][cell[1]]=DECAY_FOOD; | 
			
		
	
		
			
				
					|  |  |  |  | 						this.decayFood.push([cell[0], cell[1], this.playTime]); | 
			
		
	
		
			
				
					|  |  |  |  | 					} | 
			
		
	
		
			
				
					|  |  |  |  | 				} | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 				if(this.rules.speedIncrease) { | 
			
		
	
		
			
				
					|  |  |  |  | 					this.delay*=this.rules.speedMultiplier; | 
			
		
	
		
			
				
					|  |  |  |  | 					if(this.delay<this.rules.speedCap) this.delay=this.rules.speedCap; | 
			
		
	
	
		
			
				
					|  |  |  | @ -437,6 +482,16 @@ class SnekGame { | 
			
		
	
		
			
				
					|  |  |  |  | 		} | 
			
		
	
		
			
				
					|  |  |  |  | 		this.snake.unshift(head); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		// decay decaying food
 | 
			
		
	
		
			
				
					|  |  |  |  | 		this.decayFood.forEach( | 
			
		
	
		
			
				
					|  |  |  |  | 			([x, y, birth]) => { | 
			
		
	
		
			
				
					|  |  |  |  | 				if(this.playTime>=birth+2000) this.world[x][y]=EMPTY; | 
			
		
	
		
			
				
					|  |  |  |  | 			} | 
			
		
	
		
			
				
					|  |  |  |  | 		); | 
			
		
	
		
			
				
					|  |  |  |  | 		this.decayFood=this.decayFood.filter( | 
			
		
	
		
			
				
					|  |  |  |  | 			([_, __, birth]) => this.playTime<birth+2000 | 
			
		
	
		
			
				
					|  |  |  |  | 		); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 		// automatic speed increase
 | 
			
		
	
		
			
				
					|  |  |  |  | 		if(this.rules.autoSpeedIncrease) { | 
			
		
	
		
			
				
					|  |  |  |  | 			if(this.delay>50 && this.tickId%this.rules.autoSpeadIncreaseTicks==0) this.delay--; | 
			
		
	
	
		
			
				
					|  |  |  | 
 |