https://github.com/ajcwebdev/chase-maze
https://github.com/ajcwebdev/chase-maze
Last synced: 4 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/ajcwebdev/chase-maze
- Owner: ajcwebdev
- Created: 2024-11-10T01:12:37.000Z (8 months ago)
- Default Branch: main
- Last Pushed: 2024-11-20T00:15:53.000Z (7 months ago)
- Last Synced: 2025-03-16T08:43:09.584Z (4 months ago)
- Language: JavaScript
- Size: 5.86 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Chase Maze
## HTML
```html
Chase Maze
Chase Maze
P1 Score: 0
P2 Score: 0
Time: 0:00
Next maze in: 60s
Player 1: Arrow Keys | Player 2: WASD
Catch the moving red square!
Maze changes each catch!
Press Space for manual reset
```
## CSS
```css
.container {
display: flex;
flex-direction: column;
align-items: center;
font-family: Arial, sans-serif;
padding: 20px;
}#maze {
background: #f0f0f0;
padding: 10px;
border-radius: 5px;
transition: opacity 0.3s;
}.maze-row {
display: flex;
}.cell {
width: 30px;
height: 30px;
border: 1px solid #ddd;
display: flex;
align-items: center;
justify-content: center;
}.wall {
background-color: #333;
}.player1 {
background-color: #4CAF50;
border-radius: 50%;
}.player2 {
background-color: #2196F3;
border-radius: 50%;
}.goal {
background-color: #f44336;
border-radius: 4px;
}.instructions {
margin: 20px;
padding: 15px;
background: #e9e9e9;
border-radius: 5px;
}.stats {
display: flex;
gap: 20px;
font-size: 24px;
margin: 10px;
}#score1 {
color: #4CAF50;
font-weight: bold;
}#score2 {
color: #2196F3;
font-weight: bold;
}.countdown {
color: #f44336;
font-weight: bold;
}
```## JavaScript
```js
// game.jsconst state = {
width: 15,
height: 15,
maze: [],
player1: { x: 1, y: 1 },
player2: { x: 13, y: 1 },
goal: { x: 7, y: 7 },
moveInterval1: null,
moveInterval2: null,
goalMoveInterval: null,
moveSpeed: 100,
goalSpeed: 200,
keysPressed: new Set(),
score1: 0,
score2: 0,
startTime: Date.now(),
timerInterval: null,
nextResetTime: Date.now() + 60000
}const initMaze = () => {
state.maze = Array(state.height).fill().map(() => Array(state.width).fill(1))
}const generateMaze = () => {
const stack = [{x: 1, y: 1}]
state.maze[1][1] = 0while (stack.length > 0) {
const current = stack[stack.length - 1]
const neighbors = []
const directions = [[0, -2], [2, 0], [0, 2], [-2, 0]]for (let [dx, dy] of directions) {
const newX = current.x + dx
const newY = current.y + dy
if (newX > 0 && newX < state.width - 1 &&
newY > 0 && newY < state.height - 1 &&
state.maze[newY][newX] === 1) {
neighbors.push({x: newX, y: newY, dx, dy})
}
}if (neighbors.length === 0) {
stack.pop()
} else {
const next = neighbors[Math.floor(Math.random() * neighbors.length)]
state.maze[next.y][next.x] = 0
state.maze[current.y + next.dy/2][current.x + next.dx/2] = 0
stack.push({x: next.x, y: next.y})
}
}// Open center area
for (let y = 6; y < 9; y++) {
for (let x = 6; x < 9; x++) {
state.maze[y][x] = 0
}
}
}const moveGoal = () => {
const moves = []
const directions = [[0, -1], [1, 0], [0, 1], [-1, 0]]for (let [dx, dy] of directions) {
const newX = state.goal.x + dx
const newY = state.goal.y + dy
if (newX >= 0 && newX < state.width &&
newY >= 0 && newY < state.height &&
state.maze[newY][newX] === 0) {
const dist1 = Math.abs(newX - state.player1.x) + Math.abs(newY - state.player1.y)
const dist2 = Math.abs(newX - state.player2.x) + Math.abs(newY - state.player2.y)
moves.push({x: newX, y: newY, minDist: Math.min(dist1, dist2)})
}
}if (moves.length === 0) return
if (Math.random() < 0.7) {
// Move away from closest player
moves.sort((a, b) => b.minDist - a.minDist)
const bestMoves = moves.filter(m => m.minDist === moves[0].minDist)
const move = bestMoves[Math.floor(Math.random() * bestMoves.length)]
state.goal.x = move.x
state.goal.y = move.y
} else {
// Random move
const move = moves[Math.floor(Math.random() * moves.length)]
state.goal.x = move.x
state.goal.y = move.y
}
}const spawnGoal = () => {
const centerX = Math.floor(state.width / 2)
const centerY = Math.floor(state.height / 2)
const validSpots = []for (let y = centerY - 2; y <= centerY + 2; y++) {
for (let x = centerX - 2; x <= centerX + 2; x++) {
if (state.maze[y][x] === 0) {
validSpots.push({x, y})
}
}
}if (validSpots.length > 0) {
const spot = validSpots[Math.floor(Math.random() * validSpots.length)]
state.goal.x = spot.x
state.goal.y = spot.y
}
}const render = () => {
const mazeElement = document.getElementById('maze')
mazeElement.innerHTML = ''for (let y = 0; y < state.height; y++) {
const row = document.createElement('div')
row.className = 'maze-row'for (let x = 0; x < state.width; x++) {
const cell = document.createElement('div')
cell.className = 'cell'
if (state.maze[y][x] === 1) cell.classList.add('wall')
if (x === state.player1.x && y === state.player1.y) cell.classList.add('player1')
if (x === state.player2.x && y === state.player2.y) cell.classList.add('player2')
if (x === state.goal.x && y === state.goal.y) cell.classList.add('goal')
row.appendChild(cell)
}mazeElement.appendChild(row)
}document.getElementById('score1').textContent = `P1 Score: ${state.score1}`
document.getElementById('score2').textContent = `P2 Score: ${state.score2}`
}const updateTimer = () => {
const elapsed = Math.floor((Date.now() - state.startTime) / 1000)
const minutes = Math.floor(elapsed / 60)
const seconds = elapsed % 60
document.getElementById('timer').textContent =
`Time: ${minutes}:${seconds.toString().padStart(2, '0')}`
}const updateCountdown = () => {
const remaining = Math.ceil((state.nextResetTime - Date.now()) / 1000)
document.getElementById('countdown').textContent = `Next maze in: ${remaining}s`
document.getElementById('countdown').classList.toggle('countdown', remaining <= 10)
}const regenerateMaze = () => {
const mazeElement = document.getElementById('maze')
mazeElement.style.opacity = '0'setTimeout(() => {
initMaze()
generateMaze()
spawnGoal()
mazeElement.style.opacity = '1'
render()
}, 300)
}const movePlayer = (playerNum, dx, dy) => {
const player = playerNum === 1 ? state.player1 : state.player2
const newX = player.x + dx
const newY = player.y + dyif (newX >= 0 && newX < state.width &&
newY >= 0 && newY < state.height &&
state.maze[newY][newX] === 0) {
player.x = newX
player.y = newYif (player.x === state.goal.x && player.y === state.goal.y) {
if (playerNum === 1) state.score1++
else state.score2++
state.goalSpeed = Math.max(100, state.goalSpeed - 10)
regenerateMaze()
}
render()
}
}const startMovement = (playerNum, dx, dy) => {
const intervalKey = `moveInterval${playerNum}`
if (state[intervalKey]) clearInterval(state[intervalKey])
movePlayer(playerNum, dx, dy)
state[intervalKey] = setInterval(() => movePlayer(playerNum, dx, dy), state.moveSpeed)
}const stopMovement = (playerNum) => {
const intervalKey = `moveInterval${playerNum}`
if (state[intervalKey]) {
clearInterval(state[intervalKey])
state[intervalKey] = null
}
}const startGame = () => {
state.goalMoveInterval = setInterval(() => {
moveGoal()
render()
}, state.goalSpeed)state.timerInterval = setInterval(() => {
updateTimer()
updateCountdown()
if (Date.now() >= state.nextResetTime) {
state.nextResetTime = Date.now() + 60000
regenerateMaze()
}
}, 1000)
}const reset = () => {
clearInterval(state.moveInterval1)
clearInterval(state.moveInterval2)
clearInterval(state.goalMoveInterval)
clearInterval(state.timerInterval)state.player1 = { x: 1, y: 1 }
state.player2 = { x: 13, y: 1 }
state.score1 = 0
state.score2 = 0
state.goalSpeed = 200
state.keysPressed.clear()
state.startTime = Date.now()
state.nextResetTime = Date.now() + 60000regenerateMaze()
startGame()
}document.addEventListener('keydown', (e) => {
if (state.keysPressed.has(e.key)) return
state.keysPressed.add(e.key)switch (e.key.toLowerCase()) {
case 'arrowup': startMovement(1, 0, -1); break
case 'arrowdown': startMovement(1, 0, 1); break
case 'arrowleft': startMovement(1, -1, 0); break
case 'arrowright': startMovement(1, 1, 0); break
case 'w': startMovement(2, 0, -1); break
case 's': startMovement(2, 0, 1); break
case 'a': startMovement(2, -1, 0); break
case 'd': startMovement(2, 1, 0); break
case ' ': reset(); break
}
})document.addEventListener('keyup', (e) => {
state.keysPressed.delete(e.key)
const key = e.key.toLowerCase()
if (['arrowup', 'arrowdown', 'arrowleft', 'arrowright'].includes(key)) stopMovement(1)
if (['w', 'a', 's', 'd'].includes(key)) stopMovement(2)
})// Start game
initMaze()
generateMaze()
spawnGoal()
render()
startGame()
```