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 |
|