<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" c initial-scale=1.0"> <title>Snake Game with RL</title> <style> canvas { border: 1px solid #000; display: block; margin: 0 auto; } </style> </head> <body> <canvas id="gameCanvas" width="400" height="400"></canvas> [removed] // Game variables const canvas = document.getElementById("gameCanvas"); const ctx = canvas.getContext("2d"); const scale = 20; const rows = canvas.height / scale; const columns = canvas.width / scale; let snake; let fruit; // Snake object class Snake { constructor() { this.x = 0; this.y = 0; this.xSpeed = scale * 1; this.ySpeed = 0; this.total = 0; this.tail = []; } draw() { ctx.fillStyle = "#FFFFFF"; for (let i = 0; i < this.tail.length; i++) { ctx.fillRect(this.tail[i].x, this.tail[i].y, scale, scale); } ctx.fillRect(this.x, this.y, scale, scale); } update() { for (let i = 0; i < this.tail.length - 1; i++) { this.tail[i] = this.tail[i + 1]; } this.tail[this.total - 1] = { x: this.x, y: this.y }; this.x += this.xSpeed; this.y += this.ySpeed; if (this.x >= canvas.width) { this.x = 0; } else if (this.x < 0) { this.x = canvas.width - scale; } if (this.y >= canvas.height) { this.y = 0; } else if (this.y < 0) { this.y = canvas.height - scale; } } changeDirection(direction) { switch(direction) { case 'Up': if (this.ySpeed !== scale * 1) { this.xSpeed = 0; this.ySpeed = -scale * 1; } break; case 'Down': if (this.ySpeed !== -scale * 1) { this.xSpeed = 0; this.ySpeed = scale * 1; } break; case 'Left': if (this.xSpeed !== scale * 1) { this.xSpeed = -scale * 1; this.ySpeed = 0; } break; case 'Right': if (this.xSpeed !== -scale * 1) { this.xSpeed = scale * 1; this.ySpeed = 0; } break; } } eat(fruit) { if (this.x === fruit.x && this.y === fruit.y) { this.total++; return true; } return false; } collision() { for (let i = 0; i < this.tail.length; i++) { if (this.x === this.tail[i].x && this.y === this.tail[i].y) { return true; } } return false; } getHeadPosition() { return { x: this.x, y: this.y }; } } // Fruit object class Fruit { constructor() { this.x = (Math.floor(Math.random() * rows)) * scale; this.y = (Math.floor(Math.random() * columns)) * scale; } draw() { ctx.fill ctx.fillRect(this.x, this.y, scale, scale); } } // Q-learning RL agent class QAgent { constructor() { this.qTable = {}; this.alpha = 0.1; this.gamma = 0.9; this.epsil this.lastState = null; this.lastActi } getStateKey(state) { return `${state.x},${state.y}`; } chooseAction(state) { if (Math.random() < this.epsilon || !(this.getStateKey(state) in this.qTable)) { const acti 'Down', 'Left', 'Right']; return actions[Math.floor(Math.random() * actions.length)]; } else { const stateKey = this.getStateKey(state); const acti const maxActi b) => actionValues[a] > actionValues[b] ? a : b); return maxAction; } } learn(state, action, reward, nextState) { const stateKey = this.getStateKey(state); const nextStateKey = this.getStateKey(nextState); if (!(stateKey in this.qTable)) { this.qTable[stateKey] = { Up: 0, Down: 0, Left: 0, Right: 0 }; } if (!(nextStateKey in this.qTable)) { this.qTable[nextStateKey] = { Up: 0, Down: 0, Left: 0, Right: 0 }; } const oldQValue = this.qTable[stateKey][action]; const maxNextQValue = Math.max(...Object.values(this.qTable[nextStateKey])); this.qTable[stateKey][action] += this.alpha * (reward + this.gamma * maxNextQValue - oldQValue); } } // Game initialization let qAgent = new QAgent(); function init() { snake = new Snake(); fruit = new Fruit(); window.setInterval(() => { ctx.clearRect(0, 0, canvas.width, canvas.height); fruit.draw(); snake.update(); snake.draw(); const state = snake.getHeadPosition(); const action = qAgent.chooseAction(state); snake.changeDirection(action); const nextState = snake.getHeadPosition(); const reward = snake.eat(fruit) ? 1 : 0; qAgent.learn(state, action, reward, nextState); if (snake.collision()) { alert("Game Over!"); snake = new Snake(); fruit = new Fruit(); } }, 100); } // Start the game init(); [removed] </body> </html>