Spaces:
Running
Running
Update index.html
Browse files- index.html +139 -102
index.html
CHANGED
|
@@ -1,65 +1,8 @@
|
|
| 1 |
-
|
| 2 |
-
function checkCourseCompletion() {
|
| 3 |
-
const bestCar = getBestCar();
|
| 4 |
-
|
| 5 |
-
if (bestCar && bestCar.checkpointIndex === track.checkpoints.length) {
|
| 6 |
-
// Launch a bunch of celebratory confetti!
|
| 7 |
-
createConfetti(100, canvas.width/2, canvas.height/2);
|
| 8 |
-
setTimeout(() => createConfetti(50, canvas.width/4, canvas.height/2), 300);
|
| 9 |
-
setTimeout(() => createConfetti(50, 3*canvas.width/4, canvas.height/2), 600);
|
| 10 |
-
|
| 11 |
-
// Show victory message
|
| 12 |
-
const message = document.createElement('div');
|
| 13 |
-
message.style.position = 'absolute';
|
| 14 |
-
message.style.top = '50%';
|
| 15 |
-
message.style.left = '50%';
|
| 16 |
-
message.style.transform = 'translate(-50%, -50%)';
|
| 17 |
-
message.style.background = 'rgba(16, 185, 129, 0.9)';
|
| 18 |
-
message.style.color = 'white';
|
| 19 |
-
message.style.padding = '20px';
|
| 20 |
-
message.style.borderRadius = '10px';
|
| 21 |
-
message.style.fontSize = '24px';
|
| 22 |
-
message.style.fontWeight = 'bold';
|
| 23 |
-
message.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.1)';
|
| 24 |
-
message.style.zIndex = '1000';
|
| 25 |
-
message.style.textAlign = 'center';
|
| 26 |
-
message.innerHTML = `
|
| 27 |
-
<div>๐ Course Completed! ๐</div>
|
| 28 |
-
<div style="font-size: 16px; margin-top: 10px;">
|
| 29 |
-
Generations: ${generation}<br>
|
| 30 |
-
Fitness: ${Math.round(bestCar.fitness * 1000)}
|
| 31 |
-
</div>
|
| 32 |
-
<button id="continueBtn" style="
|
| 33 |
-
background-color: white;
|
| 34 |
-
color: #10b981;
|
| 35 |
-
border: none;
|
| 36 |
-
padding: 8px 16px;
|
| 37 |
-
border-radius: 5px;
|
| 38 |
-
margin-top: 15px;
|
| 39 |
-
cursor: pointer;
|
| 40 |
-
font-weight: bold;">
|
| 41 |
-
Continue Training
|
| 42 |
-
</button>
|
| 43 |
-
`;
|
| 44 |
-
|
| 45 |
-
document.body.appendChild(message);
|
| 46 |
-
|
| 47 |
-
// Pause simulation
|
| 48 |
-
isRunning = false;
|
| 49 |
-
cancelAnimationFrame(animationId);
|
| 50 |
-
|
| 51 |
-
// Event listener for the continue button
|
| 52 |
-
document.getElementById('continueBtn').addEventListener('click', () => {
|
| 53 |
-
document.body.removeChild(message);
|
| 54 |
-
isRunning = true;
|
| 55 |
-
lastUpdateTime = performance.now();
|
| 56 |
-
animate();
|
| 57 |
-
});
|
| 58 |
-
}
|
| 59 |
-
}<!DOCTYPE html>
|
| 60 |
<html lang="en">
|
| 61 |
<head>
|
| 62 |
<meta charset="UTF-8">
|
|
|
|
| 63 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 64 |
<title>AI Driving Simulation</title>
|
| 65 |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" />
|
|
@@ -320,7 +263,7 @@
|
|
| 320 |
</head>
|
| 321 |
<body>
|
| 322 |
<div class="container">
|
| 323 |
-
<h1
|
| 324 |
|
| 325 |
<canvas id="simulationCanvas" width="800" height="500"></canvas>
|
| 326 |
|
|
@@ -401,6 +344,28 @@
|
|
| 401 |
|
| 402 |
<script>
|
| 403 |
document.addEventListener('DOMContentLoaded', () => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 404 |
// Canvas ์ค์
|
| 405 |
const canvas = document.getElementById('simulationCanvas');
|
| 406 |
const ctx = canvas.getContext('2d');
|
|
@@ -790,10 +755,8 @@
|
|
| 790 |
// Draw fancy car for the best performer
|
| 791 |
ctx.fillStyle = 'rgba(220, 38, 38, 0.9)';
|
| 792 |
|
| 793 |
-
// Main body
|
| 794 |
-
ctx.
|
| 795 |
-
ctx.roundRect(-6, -10, 12, 20, 2);
|
| 796 |
-
ctx.fill();
|
| 797 |
|
| 798 |
// Wheels
|
| 799 |
ctx.fillStyle = '#000';
|
|
@@ -804,9 +767,7 @@
|
|
| 804 |
|
| 805 |
// Windshield
|
| 806 |
ctx.fillStyle = '#60a5fa';
|
| 807 |
-
ctx.
|
| 808 |
-
ctx.roundRect(-4, -8, 8, 6, 1);
|
| 809 |
-
ctx.fill();
|
| 810 |
|
| 811 |
// Draw a small crown on top
|
| 812 |
ctx.fillStyle = '#facc15';
|
|
@@ -822,10 +783,8 @@
|
|
| 822 |
// Regular car
|
| 823 |
ctx.fillStyle = this.color;
|
| 824 |
|
| 825 |
-
// Main body
|
| 826 |
-
ctx.
|
| 827 |
-
ctx.roundRect(-6, -10, 12, 20, 2);
|
| 828 |
-
ctx.fill();
|
| 829 |
|
| 830 |
// Wheels (simple)
|
| 831 |
ctx.fillStyle = '#000';
|
|
@@ -1236,40 +1195,20 @@
|
|
| 1236 |
return false;
|
| 1237 |
}
|
| 1238 |
|
| 1239 |
-
//
|
| 1240 |
-
|
| 1241 |
-
|
| 1242 |
|
| 1243 |
-
|
| 1244 |
-
|
| 1245 |
-
|
| 1246 |
-
|
| 1247 |
-
|
| 1248 |
-
// ์ด๊ธฐ ์ธ๊ตฌ ์์ฑ
|
| 1249 |
-
cars = [];
|
| 1250 |
-
for (let i = 0; i < populationSize; i++) {
|
| 1251 |
-
cars.push(new Car());
|
| 1252 |
}
|
| 1253 |
|
| 1254 |
-
//
|
| 1255 |
-
generation = 0;
|
| 1256 |
-
generationCount.textContent = generation;
|
| 1257 |
-
populationCount.textContent = populationSize;
|
| 1258 |
|
| 1259 |
-
|
| 1260 |
-
isRunning = true;
|
| 1261 |
-
lastUpdateTime = performance.now();
|
| 1262 |
-
init();
|
| 1263 |
-
}
|
| 1264 |
-
|
| 1265 |
-
// ๊ฒฐ๊ณผ ์
๋ฐ์ดํธ ์๋ ์ ํ (๋งค ํ๋ ์๋ง๋ค ํ์ง ์๊ณ 10ํ๋ ์๋ง๋ค ํ ๋ฒ์ฉ)
|
| 1266 |
-
let updateFrameCount = 0;
|
| 1267 |
-
|
| 1268 |
-
// Confetti particle system
|
| 1269 |
-
const confetti = [];
|
| 1270 |
-
|
| 1271 |
-
function createConfetti(count, x, y) {
|
| 1272 |
-
for (let i = 0; i < count; i++) {
|
| 1273 |
confetti.push({
|
| 1274 |
x: x,
|
| 1275 |
y: y,
|
|
@@ -1317,6 +1256,101 @@
|
|
| 1317 |
ctx.globalAlpha = 1;
|
| 1318 |
}
|
| 1319 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1320 |
// ์ฃผ์ ์ ๋๋ฉ์ด์
๋ฃจํ
|
| 1321 |
function animate(currentTime = 0) {
|
| 1322 |
if (!isRunning) return;
|
|
@@ -1371,11 +1405,14 @@
|
|
| 1371 |
nextGeneration();
|
| 1372 |
}
|
| 1373 |
|
| 1374 |
-
// ์ต๊ณ ์๋์ฐจ ๊ฐ์กฐ ํ์
|
| 1375 |
const bestCar = getBestCar();
|
| 1376 |
if (bestCar) {
|
| 1377 |
bestCar.isBest = true;
|
| 1378 |
bestCar.color = 'rgba(220, 38, 38, 0.9)';
|
|
|
|
|
|
|
|
|
|
| 1379 |
}
|
| 1380 |
}
|
| 1381 |
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
<html lang="en">
|
| 3 |
<head>
|
| 4 |
<meta charset="UTF-8">
|
| 5 |
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
| 6 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 7 |
<title>AI Driving Simulation</title>
|
| 8 |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" />
|
|
|
|
| 263 |
</head>
|
| 264 |
<body>
|
| 265 |
<div class="container">
|
| 266 |
+
<h1><i class="fas fa-car-side"></i> AI Driving Simulation</h1>
|
| 267 |
|
| 268 |
<canvas id="simulationCanvas" width="800" height="500"></canvas>
|
| 269 |
|
|
|
|
| 344 |
|
| 345 |
<script>
|
| 346 |
document.addEventListener('DOMContentLoaded', () => {
|
| 347 |
+
// Add roundRect polyfill for browsers that don't support it
|
| 348 |
+
if (!CanvasRenderingContext2D.prototype.roundRect) {
|
| 349 |
+
CanvasRenderingContext2D.prototype.roundRect = function(x, y, width, height, radius) {
|
| 350 |
+
if (typeof radius === 'undefined') {
|
| 351 |
+
radius = 5;
|
| 352 |
+
}
|
| 353 |
+
|
| 354 |
+
this.beginPath();
|
| 355 |
+
this.moveTo(x + radius, y);
|
| 356 |
+
this.lineTo(x + width - radius, y);
|
| 357 |
+
this.arcTo(x + width, y, x + width, y + radius, radius);
|
| 358 |
+
this.lineTo(x + width, y + height - radius);
|
| 359 |
+
this.arcTo(x + width, y + height, x + width - radius, y + height, radius);
|
| 360 |
+
this.lineTo(x + radius, y + height);
|
| 361 |
+
this.arcTo(x, y + height, x, y + height - radius, radius);
|
| 362 |
+
this.lineTo(x, y + radius);
|
| 363 |
+
this.arcTo(x, y, x + radius, y, radius);
|
| 364 |
+
this.closePath();
|
| 365 |
+
return this;
|
| 366 |
+
};
|
| 367 |
+
}
|
| 368 |
+
|
| 369 |
// Canvas ์ค์
|
| 370 |
const canvas = document.getElementById('simulationCanvas');
|
| 371 |
const ctx = canvas.getContext('2d');
|
|
|
|
| 755 |
// Draw fancy car for the best performer
|
| 756 |
ctx.fillStyle = 'rgba(220, 38, 38, 0.9)';
|
| 757 |
|
| 758 |
+
// Main body - using rectangles instead of roundRect to avoid issues
|
| 759 |
+
ctx.fillRect(-6, -10, 12, 20);
|
|
|
|
|
|
|
| 760 |
|
| 761 |
// Wheels
|
| 762 |
ctx.fillStyle = '#000';
|
|
|
|
| 767 |
|
| 768 |
// Windshield
|
| 769 |
ctx.fillStyle = '#60a5fa';
|
| 770 |
+
ctx.fillRect(-4, -8, 8, 6);
|
|
|
|
|
|
|
| 771 |
|
| 772 |
// Draw a small crown on top
|
| 773 |
ctx.fillStyle = '#facc15';
|
|
|
|
| 783 |
// Regular car
|
| 784 |
ctx.fillStyle = this.color;
|
| 785 |
|
| 786 |
+
// Main body - using rectangles
|
| 787 |
+
ctx.fillRect(-6, -10, 12, 20);
|
|
|
|
|
|
|
| 788 |
|
| 789 |
// Wheels (simple)
|
| 790 |
ctx.fillStyle = '#000';
|
|
|
|
| 1195 |
return false;
|
| 1196 |
}
|
| 1197 |
|
| 1198 |
+
// Reduce maximum number of confetti particles
|
| 1199 |
+
const MAX_CONFETTI = 300;
|
| 1200 |
+
const confetti = [];
|
| 1201 |
|
| 1202 |
+
function createConfetti(count, x, y) {
|
| 1203 |
+
// Limit the number of particles to prevent performance issues
|
| 1204 |
+
if (confetti.length > MAX_CONFETTI) {
|
| 1205 |
+
// Remove older particles if we exceed the limit
|
| 1206 |
+
confetti.splice(0, count);
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1207 |
}
|
| 1208 |
|
| 1209 |
+
const actualCount = Math.min(count, 50); // Limit particles per burst
|
|
|
|
|
|
|
|
|
|
| 1210 |
|
| 1211 |
+
for (let i = 0; i < actualCount; i++) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1212 |
confetti.push({
|
| 1213 |
x: x,
|
| 1214 |
y: y,
|
|
|
|
| 1256 |
ctx.globalAlpha = 1;
|
| 1257 |
}
|
| 1258 |
|
| 1259 |
+
function checkCourseCompletion() {
|
| 1260 |
+
const bestCar = getBestCar();
|
| 1261 |
+
|
| 1262 |
+
// Prevent function from firing multiple times for the same completion
|
| 1263 |
+
if (bestCar && bestCar.checkpointIndex === track.checkpoints.length && !window.courseCompleted) {
|
| 1264 |
+
// Set a flag to prevent multiple triggers
|
| 1265 |
+
window.courseCompleted = true;
|
| 1266 |
+
|
| 1267 |
+
// Launch a moderate amount of celebratory confetti
|
| 1268 |
+
createConfetti(50, canvas.width/2, canvas.height/2);
|
| 1269 |
+
|
| 1270 |
+
// Use setTimeout for additional confetti bursts to spread them out
|
| 1271 |
+
setTimeout(() => createConfetti(25, canvas.width/4, canvas.height/2), 300);
|
| 1272 |
+
setTimeout(() => createConfetti(25, 3*canvas.width/4, canvas.height/2), 600);
|
| 1273 |
+
|
| 1274 |
+
// Show victory message
|
| 1275 |
+
const message = document.createElement('div');
|
| 1276 |
+
message.style.position = 'absolute';
|
| 1277 |
+
message.style.top = '50%';
|
| 1278 |
+
message.style.left = '50%';
|
| 1279 |
+
message.style.transform = 'translate(-50%, -50%)';
|
| 1280 |
+
message.style.background = 'rgba(16, 185, 129, 0.9)';
|
| 1281 |
+
message.style.color = 'white';
|
| 1282 |
+
message.style.padding = '20px';
|
| 1283 |
+
message.style.borderRadius = '10px';
|
| 1284 |
+
message.style.fontSize = '24px';
|
| 1285 |
+
message.style.fontWeight = 'bold';
|
| 1286 |
+
message.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.1)';
|
| 1287 |
+
message.style.zIndex = '1000';
|
| 1288 |
+
message.style.textAlign = 'center';
|
| 1289 |
+
message.innerHTML = `
|
| 1290 |
+
<div><i class="fas fa-trophy"></i> Course Completed! <i class="fas fa-trophy"></i></div>
|
| 1291 |
+
<div style="font-size: 16px; margin-top: 10px;">
|
| 1292 |
+
Generations: ${generation}<br>
|
| 1293 |
+
Fitness: ${Math.round(bestCar.fitness * 1000)}
|
| 1294 |
+
</div>
|
| 1295 |
+
<button id="continueBtn" style="
|
| 1296 |
+
background-color: white;
|
| 1297 |
+
color: #10b981;
|
| 1298 |
+
border: none;
|
| 1299 |
+
padding: 8px 16px;
|
| 1300 |
+
border-radius: 5px;
|
| 1301 |
+
margin-top: 15px;
|
| 1302 |
+
cursor: pointer;
|
| 1303 |
+
font-weight: bold;">
|
| 1304 |
+
Continue Training
|
| 1305 |
+
</button>
|
| 1306 |
+
`;
|
| 1307 |
+
|
| 1308 |
+
document.body.appendChild(message);
|
| 1309 |
+
|
| 1310 |
+
// Pause simulation
|
| 1311 |
+
isRunning = false;
|
| 1312 |
+
cancelAnimationFrame(animationId);
|
| 1313 |
+
|
| 1314 |
+
// Event listener for the continue button
|
| 1315 |
+
document.getElementById('continueBtn').addEventListener('click', () => {
|
| 1316 |
+
document.body.removeChild(message);
|
| 1317 |
+
isRunning = true;
|
| 1318 |
+
window.courseCompleted = false; // Reset the completion flag
|
| 1319 |
+
lastUpdateTime = performance.now();
|
| 1320 |
+
animate();
|
| 1321 |
+
});
|
| 1322 |
+
}
|
| 1323 |
+
}
|
| 1324 |
+
|
| 1325 |
+
// ์๋ฎฌ๋ ์ด์
์ํ
|
| 1326 |
+
let cars = [];
|
| 1327 |
+
let animationId;
|
| 1328 |
+
|
| 1329 |
+
// ์๋ฎฌ๋ ์ด์
์ด๊ธฐํ
|
| 1330 |
+
function init() {
|
| 1331 |
+
// ๋ฌด์์ ํธ๋ ์์ฑ
|
| 1332 |
+
track.generateRandomTrack();
|
| 1333 |
+
|
| 1334 |
+
// ์ด๊ธฐ ์ธ๊ตฌ ์์ฑ
|
| 1335 |
+
cars = [];
|
| 1336 |
+
for (let i = 0; i < populationSize; i++) {
|
| 1337 |
+
cars.push(new Car());
|
| 1338 |
+
}
|
| 1339 |
+
|
| 1340 |
+
// ํต๊ณ ์ด๊ธฐํ
|
| 1341 |
+
generation = 0;
|
| 1342 |
+
generationCount.textContent = generation;
|
| 1343 |
+
populationCount.textContent = populationSize;
|
| 1344 |
+
|
| 1345 |
+
// ์๋ฎฌ๋ ์ด์
์์
|
| 1346 |
+
isRunning = true;
|
| 1347 |
+
lastUpdateTime = performance.now();
|
| 1348 |
+
animate(); // Fix: Changed from init() to animate()
|
| 1349 |
+
}
|
| 1350 |
+
|
| 1351 |
+
// ๊ฒฐ๊ณผ ์
๋ฐ์ดํธ ์๋ ์ ํ (๋งค ํ๋ ์๋ง๋ค ํ์ง ์๊ณ 10ํ๋ ์๋ง๋ค ํ ๋ฒ์ฉ)
|
| 1352 |
+
let updateFrameCount = 0;
|
| 1353 |
+
|
| 1354 |
// ์ฃผ์ ์ ๋๋ฉ์ด์
๋ฃจํ
|
| 1355 |
function animate(currentTime = 0) {
|
| 1356 |
if (!isRunning) return;
|
|
|
|
| 1405 |
nextGeneration();
|
| 1406 |
}
|
| 1407 |
|
| 1408 |
+
// ์ต๊ณ ์๋์ฐจ ๊ฐ์กฐ ํ์ ๋ฐ ์ฝ์ค ์๋ฃ ํ์ธ
|
| 1409 |
const bestCar = getBestCar();
|
| 1410 |
if (bestCar) {
|
| 1411 |
bestCar.isBest = true;
|
| 1412 |
bestCar.color = 'rgba(220, 38, 38, 0.9)';
|
| 1413 |
+
|
| 1414 |
+
// Check if the best car has completed the course
|
| 1415 |
+
checkCourseCompletion();
|
| 1416 |
}
|
| 1417 |
}
|
| 1418 |
|