1- function getsnakeGameHTML ( ) {
1+ function getSnakeGameHTML ( ) {
22 return `
33 <div class="project-content">
44 <h2>🐍 Classic Snake Game</h2>
55 <div class="snake-container">
6+ <div class="controls-top">
7+ <div class="difficulty-box">
8+ <label for="difficultySelect">Difficulty: </label>
9+ <select id="difficultySelect">
10+ <option value="easy">Easy (1x Score)</option>
11+ <option value="medium" selected>Medium (2x Score)</option>
12+ <option value="hard">Hard (3x Score)</option>
13+ </select>
14+ </div>
15+ </div>
16+
617 <div class="game-area">
718 <div id="canvas-wrapper" class="ui-canvas-frame">
819 <canvas id="snakeCanvas" width="600" height="400"></canvas>
@@ -19,6 +30,10 @@ function getsnakeGameHTML() {
1930 <span>Score</span>
2031 <div id="score">0</div>
2132 </div>
33+ <div class="score-card high-score-card">
34+ <span>Best</span>
35+ <div id="best-score">0</div>
36+ </div>
2237 </div>
2338 </div>
2439
@@ -40,6 +55,31 @@ function getsnakeGameHTML() {
4055 padding: 20px;
4156 font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
4257 }
58+ .controls-top {
59+ margin-bottom: 15px;
60+ margin-right: 140px; /* Aligns with canvas center offset */
61+ }
62+ .difficulty-box select {
63+ padding: 6px 10px;
64+ border-radius: 6px;
65+ border: 1px solid var(--accent-border, #ccc);
66+ background-color: #ffffff !important; /* Explicitly forces white background */
67+ color: #222222 !important; /* Explicitly forces dark gray/black text */
68+ font-size: 14px;
69+ font-family: inherit;
70+ font-weight: 500;
71+ cursor: pointer;
72+ outline: none;
73+ }
74+ .difficulty-box select {
75+ padding: 4px 8px;
76+ border-radius: 4px;
77+ border: 1px solid #aaa;
78+ background-color: #ffffff;
79+ color: #222222;
80+ font-weight: normal;
81+ cursor: pointer;
82+ }
4383 .game-area {
4484 display: flex;
4585 align-items: flex-start;
@@ -52,16 +92,16 @@ function getsnakeGameHTML() {
5292 }
5393 #canvas-wrapper {
5494 position: relative;
55- border: 4px solid var(--success-color);
95+ border: 4px solid var(--success-color, #2ecc71 );
5696 border-radius: 12px;
5797 overflow: hidden;
5898 box-shadow: 0 15px 35px rgba(0,0,0,0.3);
5999 }
60100 #snakeCanvas {
61- background-color: var(--panel-color);
101+ background-color: var(--panel-color, #222 );
62102 background-image:
63- linear-gradient(var(--border-color) 1px, transparent 1px),
64- linear-gradient(90deg, var(--border-color) 1px, transparent 1px);
103+ linear-gradient(var(--border-color, rgba(255,255,255,0.05) ) 1px, transparent 1px),
104+ linear-gradient(90deg, var(--border-color, rgba(255,255,255,0.05) ) 1px, transparent 1px);
65105 background-size: 20px 20px;
66106 display: block;
67107 }
@@ -71,14 +111,18 @@ function getsnakeGameHTML() {
71111 gap: 15px;
72112 }
73113 .score-card {
74- background: var(--accent-soft);
75- border: 1px solid var(--accent-border);
76- color: var(--text-color);
114+ background: var(--accent-soft, #fafafa );
115+ border: 1px solid var(--accent-border, #ddd );
116+ color: var(--text-color, #333 );
77117 padding: 10px 25px;
78118 border-radius: 10px;
79119 text-align: center;
80120 min-width: 120px;
81- box-shadow: var(--shadow);
121+ box-shadow: var(--shadow, 0 4px 6px rgba(0,0,0,0.1));
122+ }
123+ .high-score-card {
124+ border-color: #f1c40f;
125+ background: rgba(241, 196, 15, 0.05);
82126 }
83127 .score-card span {
84128 font-size: 12px;
@@ -92,15 +136,15 @@ function getsnakeGameHTML() {
92136 .button-group {
93137 display: flex;
94138 justify-content: center;
95- gap: 30px; /* Space between buttons fixed */
139+ gap: 30px;
96140 margin-top: 10px;
97- margin-right: 140px; /* Offset to align with canvas center */
141+ margin-right: 140px;
98142 }
99143 .instruction-box {
100144 margin-top: 20px;
101145 margin-right: 140px;
102146 text-align: center;
103- color: var(--text-secondary);
147+ color: var(--text-secondary, #666 );
104148 font-size: 15px;
105149 }
106150 #game-over-overlay {
@@ -109,31 +153,40 @@ function getsnakeGameHTML() {
109153 left: 0;
110154 width: 100%;
111155 height: 100%;
112- background: var(--overlay-color);
156+ background: var(--overlay-color, rgba(0, 0, 0, 0.75) );
113157 display: flex;
114158 flex-direction: column;
115159 justify-content: center;
116160 align-items: center;
117161 z-index: 10;
118- color: var(--success-color);
162+ color: var(--success-color, #2ecc71 );
119163 }
120164 #game-over-overlay h1 { font-size: 3rem; margin-bottom: 10px; }
121165 .hidden { display: none !important; }
122166 .btn-primary {
123167 padding: 12px 25px;
168+ cursor: pointer;
124169 }
125170 </style>
126171 ` ;
127172}
128173
129- // --- GAME LOGIC ---
174+ // --- GAME LOGIC STATE ---
130175let direction = { x : 0 , y : 0 } ;
131- let speed = 7 ;
176+ let speed = 9 ; // System baseline operational configuration state
177+ let scoreMultiplier = 2 ; // Baseline multiplier scalar state
132178let score = 0 ;
133179let lastPaintTime = 0 ;
134180let snakeArr = [ { x : 13 , y : 10 } ] ;
135181let food = { x : 6 , y : 7 } ;
136182
183+ // Profile configuration mapping matrices
184+ const CONFIG_DIFFICULTY = {
185+ easy : { speed : 5 , multiplier : 1 } ,
186+ medium : { speed : 9 , multiplier : 2 } ,
187+ hard : { speed : 14 , multiplier : 3 }
188+ } ;
189+
137190function main ( ctime ) {
138191 window . requestAnimationFrame ( main ) ;
139192 if ( ( ctime - lastPaintTime ) / 1000 < 1 / speed ) {
@@ -154,11 +207,44 @@ function isCollide(snake) {
154207 return false ;
155208}
156209
210+ function applyDifficultySettings ( ) {
211+ const selector = document . getElementById ( 'difficultySelect' ) ;
212+ if ( selector ) {
213+ const value = selector . value ;
214+ speed = CONFIG_DIFFICULTY [ value ] . speed ;
215+ scoreMultiplier = CONFIG_DIFFICULTY [ value ] . multiplier ;
216+ }
217+ }
218+
219+ function updateBestScoreUI ( ) {
220+ const bestScore = localStorage . getItem ( 'snakeBestScore' ) || 0 ;
221+ const bestScoreElement = document . getElementById ( 'best-score' ) ;
222+ if ( bestScoreElement ) {
223+ bestScoreElement . innerHTML = bestScore ;
224+ }
225+ }
226+
227+ function checkAndSaveHighScore ( ) {
228+ const currentBest = parseInt ( localStorage . getItem ( 'snakeBestScore' ) || '0' , 10 ) ;
229+ if ( score > currentBest ) {
230+ localStorage . setItem ( 'snakeBestScore' , score ) ;
231+ updateBestScoreUI ( ) ;
232+ }
233+ }
234+
157235function gameEngine ( ) {
158236 if ( isCollide ( snakeArr ) ) {
159237 direction = { x : 0 , y : 0 } ;
160238 document . getElementById ( 'final-score' ) . innerHTML = score ;
161239 document . getElementById ( 'game-over-overlay' ) . classList . remove ( 'hidden' ) ;
240+
241+ // Execute persistent local evaluations
242+ checkAndSaveHighScore ( ) ;
243+
244+ // Restore controls visibility states
245+ const selector = document . getElementById ( 'difficultySelect' ) ;
246+ if ( selector ) selector . disabled = false ;
247+
162248 snakeArr = [ { x : 13 , y : 10 } ] ;
163249 score = 0 ;
164250 document . getElementById ( 'score' ) . innerHTML = score ;
@@ -167,7 +253,7 @@ function gameEngine() {
167253
168254 // Eating food
169255 if ( snakeArr [ 0 ] . y === food . y && snakeArr [ 0 ] . x === food . x ) {
170- score += 1 ;
256+ score += ( 1 * scoreMultiplier ) ; // Scaled multiplier calculations
171257 document . getElementById ( 'score' ) . innerHTML = score ;
172258 snakeArr . unshift ( { x : snakeArr [ 0 ] . x + direction . x , y : snakeArr [ 0 ] . y + direction . y } ) ;
173259 let a = 2 , b = 16 ;
@@ -199,11 +285,25 @@ function gameEngine() {
199285 ctx . fillRect ( food . x * 20 , food . y * 20 , 18 , 18 ) ;
200286}
201287
202- // IMPORTANT: Function to initialize listeners after HTML is loaded
288+ // Initialize execution listeners
203289function initSnakeGame ( ) {
204290 window . requestAnimationFrame ( main ) ;
291+
292+ // Set initial historic rendering metrics
293+ updateBestScoreUI ( ) ;
294+
295+ // Map difficulty listener parameters
296+ const selector = document . getElementById ( 'difficultySelect' ) ;
297+ if ( selector ) {
298+ selector . addEventListener ( 'change' , applyDifficultySettings ) ;
299+ }
300+ // Initialize standard values configuration parameters
301+ applyDifficultySettings ( ) ;
205302
206303 document . getElementById ( 'startGameBtn' ) . addEventListener ( 'click' , ( ) => {
304+ applyDifficultySettings ( ) ;
305+ // Prevent changing parameter matrices on an active engine run
306+ if ( selector ) selector . disabled = true ;
207307 direction = { x : 1 , y : 0 } ; // Start moving right
208308 } ) ;
209309
@@ -213,13 +313,21 @@ function initSnakeGame() {
213313
214314 document . getElementById ( 'overlayRestartBtn' ) . addEventListener ( 'click' , ( ) => {
215315 document . getElementById ( 'game-over-overlay' ) . classList . add ( 'hidden' ) ;
316+ if ( selector ) selector . disabled = false ;
216317 direction = { x : 0 , y : 0 } ;
217318 snakeArr = [ { x : 13 , y : 10 } ] ;
218319 score = 0 ;
219320 document . getElementById ( 'score' ) . innerHTML = score ;
220321 } ) ;
221322
222323 window . addEventListener ( 'keydown' , e => {
324+ // Change difficulty selection dynamic evaluations if arrow key registers
325+ if ( [ "ArrowUp" , "ArrowDown" , "ArrowLeft" , "ArrowRight" ] . includes ( e . key ) ) {
326+ if ( selector && ! selector . disabled ) {
327+ selector . disabled = true ;
328+ }
329+ }
330+
223331 switch ( e . key ) {
224332 case "ArrowUp" : if ( direction . y !== 1 ) { direction . x = 0 ; direction . y = - 1 ; } break ;
225333 case "ArrowDown" : if ( direction . y !== - 1 ) { direction . x = 0 ; direction . y = 1 ; } break ;
@@ -228,3 +336,7 @@ function initSnakeGame() {
228336 }
229337 } ) ;
230338}
339+
340+ // Global scope assignments
341+ window . getSnakeGameHTML = getSnakeGameHTML ;
342+ window . initSnakeGame = initSnakeGame ;
0 commit comments