Created
February 1, 2025 07:14
-
-
Save hermesthecat/41bd9a49e839a9b92d486637595bd5dd to your computer and use it in GitHub Desktop.
autonomous snake game - claude 3.5 sonnet. javascript.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="tr"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Çift Yılan Oyunu - A. Kerem Gök</title> | |
<style> | |
body { | |
display: flex; | |
flex-direction: column; | |
align-items: center; | |
justify-content: center; | |
height: 100vh; | |
margin: 0; | |
background-color: #2c3e50; | |
} | |
canvas { | |
border: 2px solid #fff; | |
background-color: #34495e; | |
} | |
.score { | |
color: white; | |
font-size: 24px; | |
margin: 10px 0; | |
font-family: Arial, sans-serif; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="score">Yılan 1: <span id="score1">0</span> | Yılan 2: <span id="score2">0</span></div> | |
<canvas id="gameCanvas" width="600" height="400"></canvas> | |
<script> | |
const canvas = document.getElementById('gameCanvas'); | |
const ctx = canvas.getContext('2d'); | |
// Yılanlar için sınıf oluşturma | |
class Snake { | |
constructor(x, y, color) { | |
this.body = [ | |
{x: x, y: y}, | |
{x: x - 10, y: y}, | |
{x: x - 20, y: y} | |
]; | |
this.color = color; | |
this.direction = 'right'; | |
this.score = 0; | |
} | |
// Akıllı hareket sistemi | |
move() { | |
const head = {x: this.body[0].x, y: this.body[0].y}; | |
// Diğer yılanın konumunu al | |
const otherSnake = this === snake1 ? snake2 : snake1; | |
// En yakın yılan parçasının mesafesini hesapla | |
let minDistance = Infinity; | |
otherSnake.body.forEach(segment => { | |
const distance = Math.sqrt( | |
Math.pow(head.x - segment.x, 2) + | |
Math.pow(head.y - segment.y, 2) | |
); | |
minDistance = Math.min(minDistance, distance); | |
}); | |
// Yem yönünü hesapla | |
const foodDirection = { | |
x: food.x - head.x, | |
y: food.y - head.y | |
}; | |
// Yeme olan mesafeyi hesapla | |
const foodDistance = Math.sqrt( | |
Math.pow(foodDirection.x, 2) + | |
Math.pow(foodDirection.y, 2) | |
); | |
// Mevcut yönü tersine çeviren yön sözlüğü | |
const oppositeDir = { | |
'up': 'down', | |
'down': 'up', | |
'left': 'right', | |
'right': 'left' | |
}; | |
// Duvar yakınlığını kontrol et | |
const wallProximity = { | |
up: head.y < 30, | |
down: head.y > canvas.height - 30, | |
left: head.x < 30, | |
right: head.x > canvas.width - 30 | |
}; | |
// Yön seçimi için puanlama sistemi | |
const directionScores = { | |
up: 0, | |
down: 0, | |
left: 0, | |
right: 0 | |
}; | |
// Yem duvar dibinde mi kontrol et | |
const foodNearWall = ( | |
food.x < 30 || food.x > canvas.width - 30 || | |
food.y < 30 || food.y > canvas.height - 30 | |
); | |
// Gelişmiş yem puanlaması (duvar dibindeyse daha yüksek puan) | |
const foodWeight = foodNearWall ? 300 / (foodDistance + 1) : 150 / (foodDistance + 1); | |
if (Math.abs(foodDirection.x) > Math.abs(foodDirection.y)) { | |
directionScores.right += foodDirection.x > 0 ? foodWeight : 0; | |
directionScores.left += foodDirection.x < 0 ? foodWeight : 0; | |
} else { | |
directionScores.down += foodDirection.y > 0 ? foodWeight : 0; | |
directionScores.up += foodDirection.y < 0 ? foodWeight : 0; | |
} | |
// Diğer yılandan kaçınma puanlaması | |
const snakeAvoidanceWeight = 150 / (minDistance + 1); | |
['up', 'down', 'left', 'right'].forEach(dir => { | |
let testHead = {x: head.x, y: head.y}; | |
switch(dir) { | |
case 'up': testHead.y -= 10; break; | |
case 'down': testHead.y += 10; break; | |
case 'left': testHead.x -= 10; break; | |
case 'right': testHead.x += 10; break; | |
} | |
// O yöne gidersek diğer yılana olan mesafeyi hesapla | |
let wouldCollide = false; | |
otherSnake.body.forEach(segment => { | |
if (testHead.x === segment.x && testHead.y === segment.y) { | |
wouldCollide = true; | |
} | |
}); | |
// Çarpışma olacaksa o yönü cezalandır | |
if (wouldCollide) { | |
directionScores[dir] -= 1000; | |
} | |
// Yakınsa o yönden kaçın | |
else if (minDistance < 50) { | |
directionScores[dir] -= snakeAvoidanceWeight; | |
} | |
}); | |
// Duvar yakınlığı kontrolü (yem duvar dibindeyse görmezden gel) | |
if (!foodNearWall) { | |
Object.keys(wallProximity).forEach(dir => { | |
if (wallProximity[dir]) { | |
directionScores[dir] -= 3; | |
} | |
}); | |
} | |
// Mevcut yönün tersine gitmeyi engelle | |
directionScores[oppositeDir[this.direction]] = -10; | |
// En yüksek puanlı yönü seç | |
let bestDirection = this.direction; | |
let maxScore = -Infinity; | |
Object.keys(directionScores).forEach(dir => { | |
if (directionScores[dir] > maxScore) { | |
maxScore = directionScores[dir]; | |
bestDirection = dir; | |
} | |
}); | |
// Sıkışma durumundan kurtulma | |
if (maxScore < -500) { // Eğer tüm yönler tehlikeli ise | |
const directions = ['up', 'down', 'left', 'right'] | |
.filter(dir => dir !== oppositeDir[this.direction]); | |
bestDirection = directions[Math.floor(Math.random() * directions.length)]; | |
} | |
this.direction = bestDirection; | |
// Yön'e göre hareket | |
switch(this.direction) { | |
case 'up': head.y -= 10; break; | |
case 'down': head.y += 10; break; | |
case 'left': head.x -= 10; break; | |
case 'right': head.x += 10; break; | |
} | |
// Duvar çarpışma kontrolü | |
if (head.x < 0 || head.x >= canvas.width || | |
head.y < 0 || head.y >= canvas.height) { | |
// Yılanı başlangıç konumuna resetle | |
this.body = [ | |
{x: Math.floor(Math.random() * (canvas.width / 10)) * 10, | |
y: Math.floor(Math.random() * (canvas.height / 10)) * 10}, | |
{x: this.body[0].x - 10, y: this.body[0].y}, | |
{x: this.body[0].x - 20, y: this.body[0].y} | |
]; | |
this.score = Math.max(0, this.score - 50); // Ceza puanı | |
return; | |
} | |
this.body.unshift(head); | |
this.body.pop(); | |
} | |
// Yılanı çizme | |
draw() { | |
ctx.fillStyle = this.color; | |
this.body.forEach(segment => { | |
ctx.fillRect(segment.x, segment.y, 9, 9); | |
}); | |
} | |
// Çarpışma kontrolü | |
checkCollision(food) { | |
const head = this.body[0]; | |
if (head.x === food.x && head.y === food.y) { | |
this.grow(); | |
this.score += 10; | |
return true; | |
} | |
return false; | |
} | |
// Yılanı büyütme | |
grow() { | |
const tail = this.body[this.body.length - 1]; | |
this.body.push({x: tail.x, y: tail.y}); | |
} | |
} | |
// Oyun değişkenleri | |
const snake1 = new Snake(100, 100, '#e74c3c'); | |
const snake2 = new Snake(400, 300, '#2ecc71'); | |
let food = generateFood(); | |
const scoreElement1 = document.getElementById('score1'); | |
const scoreElement2 = document.getElementById('score2'); | |
// Yem oluşturma fonksiyonu | |
function generateFood() { | |
return { | |
x: Math.floor(Math.random() * (canvas.width / 10)) * 10, | |
y: Math.floor(Math.random() * (canvas.height / 10)) * 10 | |
}; | |
} | |
// Yem çizme | |
function drawFood() { | |
ctx.fillStyle = '#f1c40f'; | |
ctx.fillRect(food.x, food.y, 9, 9); | |
} | |
// Ana oyun döngüsü | |
function gameLoop() { | |
ctx.clearRect(0, 0, canvas.width, canvas.height); | |
// Yılanların hareketi ve çizimi | |
snake1.move(); | |
snake2.move(); | |
// Yem kontrolü | |
if (snake1.checkCollision(food) || snake2.checkCollision(food)) { | |
food = generateFood(); | |
} | |
// Skor güncelleme | |
scoreElement1.textContent = snake1.score; | |
scoreElement2.textContent = snake2.score; | |
// Çizimler | |
drawFood(); | |
snake1.draw(); | |
snake2.draw(); | |
setTimeout(gameLoop, 50); // Oyun hızı 2 katına çıkarıldı | |
} | |
// Oyunu başlat | |
gameLoop(); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment