lvl1.html (9707B)
1 <head> 2 3 <meta charset="utf-8"/> 4 5 <link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"/> 6 7 <style> 8 h1,h2 { 9 font-family: Sans; 10 } 11 12 .stderr { 13 background-color: #fee; 14 color: #900; 15 } 16 17 .stderr, .stdout { 18 /* display: contents; */ /* uncomment to make print( end='') work */ 19 margin: 0px; 20 padding: 0px 0.3em; 21 } 22 23 .console { 24 max-height: 20em; 25 overflow: auto; 26 border: medium solid black; 27 } 28 29 .console:empty { 30 display: none; 31 } 32 33 #feedback { 34 border: solid #aaa; 35 background-color: #eee; 36 } 37 38 #feedback:empty { 39 display: none; 40 } 41 42 #edcontainer { 43 display: flex; 44 } 45 .edcolumn { 46 flex: 50%; 47 } 48 #breditor { 49 width: 100%; 50 } 51 52 53 </style> 54 55 <script src="https://cdn.jsdelivr.net/npm/phaser@3.55.0/dist/phaser.min.js"></script> 56 <script src="https://unpkg.com/brython@3.9.3/brython.js"></script> 57 <script src="https://unpkg.com/brython@3.9.3/brython_stdlib.js"></script> 58 <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ace.min.js"></script> 59 <script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/mode-python.min.js"></script> 60 61 <script type="text/javascript"> 62 63 code = "# Écrivez votre code python ici :\nprint(\"Bonjour !\")"; 64 65 score = 0; 66 67 API = window.API || window.parent.API; 68 69 function loadSCO() { 70 if (API) { 71 API.LMSInitialize(""); 72 73 suspend_data = API.LMSGetValue("cmi.suspend_data"); 74 75 if (suspend_data) { 76 code = suspend_data; 77 } 78 } 79 } 80 81 function sendSCO() { 82 if (API) { 83 API.LMSSetValue("cmi.core.score.raw", score); 84 API.LMSSetValue("cmi.suspend_data", code); 85 API.LMSSetValue("cmi.core.score.lesson_status", "completed"); 86 87 API.LMSCommit(""); 88 } 89 } 90 91 function nextSCO() { 92 if (API) { 93 API.LMSSetValue("nav.event","continue"); // Probably Moodle specific 94 API.LMSFinish(""); 95 } 96 } 97 98 // Phaser stuff 99 100 var tilesize = 32; 101 var delay = 250; 102 103 var tiles = []; 104 105 var movetime = 0; 106 var delayed_moves = []; 107 108 var config = { 109 type: Phaser.AUTO, 110 width: tilesize*10, 111 height: tilesize*10, 112 parent: "game", 113 scene: { 114 preload: preload, 115 create: create 116 } 117 }; 118 119 function preload() { 120 this.load.image("tilemap", "img/tilemap.png") 121 this.load.image("bot", "img/bot.png") 122 this.load.tilemapCSV('map', 'lvl/lvl1.csv'); 123 } 124 125 function create() { 126 map = this.make.tilemap({ key: 'map', tileWidth: 32, tileHeight: 32 }); 127 var tileset = map.addTilesetImage('tilemap'); 128 layer = map.createLayer(0, tileset, 0, 0); 129 130 bot = this.add.image(tilesize * 1.5, tilesize * 1.5, "bot"); 131 } 132 133 function gen_tiles() { 134 for (var i = 0 ; i < 10 ; i++) { 135 tiles[i] = []; 136 for (var j = 0 ; j < 10 ; j++) { 137 var id = map.getTileAt(i,j).index; 138 if (id == 4) 139 id = 0; 140 tiles[i][j] = id; 141 } 142 } 143 } 144 145 function get_tile_at(x,y) { 146 return tiles[x][y]; 147 } 148 149 function reset_board() { 150 movetime = 0; 151 bot.x = tilesize * 1.5; 152 bot.y = tilesize * 1.5; 153 bot.angle = 0; 154 155 for (move of delayed_moves){ 156 clearTimeout(move) 157 } 158 159 delayed_moves = [] 160 161 gen_tiles() 162 } 163 164 function move_left() { 165 delayed_moves.push( 166 setTimeout( 167 function() { 168 bot.x -= tilesize; 169 bot.angle = 180; 170 }, movetime) 171 ); 172 movetime += delay; 173 } 174 175 function move_right() { 176 delayed_moves.push( 177 setTimeout( 178 function() { 179 bot.x += tilesize; 180 bot.angle = 0; 181 }, movetime) 182 ); 183 movetime += delay; 184 } 185 186 function move_up() { 187 delayed_moves.push( 188 setTimeout( 189 function() { 190 bot.y -= tilesize; 191 bot.angle = -90; 192 }, movetime) 193 ); 194 movetime += delay; 195 } 196 197 function move_down() { 198 delayed_moves.push( 199 setTimeout( 200 function() { 201 bot.y += tilesize; 202 bot.angle = 90; 203 }, movetime) 204 ); 205 movetime += delay; 206 } 207 208 window.onload = function() { 209 loadSCO(); 210 document.getElementById("code").textContent = code; 211 212 game = new Phaser.Game(config); 213 214 brython(); 215 } 216 </script> 217 218 <script type="text/python"> 219 # Requires Brython and Ace editor 220 221 from browser import document, window, html 222 from sys import stderr, stdout, settrace 223 from traceback import print_exc, extract_stack, extract_tb 224 225 def make_max_line_tracer(maxlines): 226 lines = 0 227 def tracer(frame, event, arg): 228 nonlocal lines 229 if event == 'line': 230 lines += 1 231 if lines >= maxlines: 232 raise TimeoutError 233 return tracer 234 return tracer 235 236 def exec_code(editor, id): 237 reset() 238 feedback("Le drapeau n'est pas encore atteint") 239 240 code_lines = editor.session.getLength() 241 if code_lines > max_code_lines: 242 feedback("Trop de lignes utilisées ( " + str(code_lines) + "/" + str(max_code_lines) + ")") 243 return 244 245 console = document[id + "_console"] 246 console.clear() 247 stderr.write = lambda data : console_target(data, console, True) 248 stdout.write = lambda data : console_target(data, console) 249 250 code = editor.getValue() 251 try: 252 compiled = compile(code, "<" + id + ">", "exec") 253 except SyntaxError: 254 print_exc(limit=0) 255 return 256 257 settrace(make_max_line_tracer(10000)) # increase to allow longer execution 258 try: 259 exec(code) 260 except TimeoutError: 261 settrace(None) 262 print("L'exécution prend trop de temps, abandon.", file=stderr) 263 except Exception as e: 264 settrace(None) 265 tb_len = len(extract_tb(e.__traceback__)) - len(extract_stack()) 266 print_exc(limit=-tb_len) 267 finally: 268 settrace(None) 269 270 window.code = code 271 #window.score = check() 272 window.sendSCO() 273 274 def console_target(data, elt, err=False): 275 elt <= html.PRE(data, Class="stderr" if err else "stdout") 276 elt.scrollTop = elt.scrollHeight 277 278 breditors = document.select(".breditor") 279 280 max_code_lines = 10 281 282 for ed_elt in breditors: 283 editor = window.ace.edit(ed_elt.id) 284 editor.session.setMode("ace/mode/python") 285 #editor.setOption('fontSize', '14px') 286 editor.setOption('maxLines', max_code_lines) 287 editor.setOption('minLines', max_code_lines) 288 289 console = html.DIV(Class="console", id=ed_elt.id + "_console") 290 291 ed_elt.insertAdjacentElement('afterend', console) 292 293 exec_button = html.BUTTON("Exécuter →") 294 exec_button.bind("click", lambda ev : exec_code(editor, ed_elt.id)) 295 ed_elt.insertAdjacentElement('afterend', exec_button) 296 297 def feedback(msg): 298 document["feedback"].clear() 299 document["feedback"] <= msg 300 301 coords = [1,1] 302 303 def reset(): 304 global coords 305 window.reset_board() 306 coords = [1,1] 307 308 def gauche(): 309 if coords[0] >= 0: 310 tile = window.get_tile_at(coords[0]-1, coords[1]) 311 if tile in (0,1,3): 312 window.move_left() 313 coords[0] -= 1 314 if tile == 1: 315 win() 316 elif tile == 3: 317 fall() 318 319 def droite(): 320 if coords[0] < 10: 321 tile = window.get_tile_at(coords[0]+1, coords[1]) 322 if tile in (0,1,3): 323 window.move_right() 324 coords[0] += 1 325 if tile == 1: 326 win() 327 elif tile == 3: 328 fall() 329 330 def haut(): 331 if coords[1] >= 0: 332 tile = window.get_tile_at(coords[0], coords[1]-1) 333 if tile in (0,1,3): 334 window.move_up() 335 coords[1] -= 1 336 if tile == 1: 337 win() 338 elif tile == 3: 339 fall() 340 341 def bas(): 342 if coords[1] < 10: 343 tile = window.get_tile_at(coords[0], coords[1]+1) 344 if tile in (0,1,3): 345 window.move_down() 346 coords[1] += 1 347 if tile == 1: 348 win() 349 elif tile == 3: 350 fall() 351 352 353 def voir_gauche(): 354 if coords[0] == 0: 355 return 3 356 else: 357 return voir(coords[0]-1, coords[1]) 358 359 def voir_droite(): 360 if coords[0] == 10: 361 return 3 362 else: 363 return voir(coords[0]+1, coords[1]) 364 365 def voir_haut(): 366 if coords[1] == 0: 367 return 3 368 else: 369 return voir(coords[0], coords[1]-1) 370 371 def voir_bas(): 372 if coords[1] == 10: 373 return 3 374 else: 375 return voir(coords[0], coords[1]+1) 376 377 def voir(x,y): 378 return window.get_tile_at(x,y) 379 380 def fall(): 381 feedback("Le robot est tombé dans le vide !") 382 raise Exception("Le robot est tombé dans le vide") 383 384 385 def win(): 386 window.score = 100 387 feedback("Bravo !") 388 document["feedback"] <= html.BUTTON("Passer à la suite", onclick="nextSCO();") 389 390 391 </script> 392 393 </head> 394 395 <body> 396 397 <h1>Niveau 1</h1> 398 399 Vous disposez des fonctions 400 <code>droite()</code>, 401 <code>gauche()</code>, 402 <code>haut()</code>, et 403 <code>bas()</code> 404 pour faire avancer le robot. 405 406 </br> 407 408 Vous pouvez aussi utiliser 409 <code>voir_droite()</code>, 410 <code>voir_gauche()</code>, 411 <code>voir_haut()</code>, et 412 <code>voir_bas()</code> 413 pour regarder les cases autour de vous, 414 ces fonctions renvoient le type de la case : 415 <ul> 416 <li>0 pour un chemin</li> 417 <li>1 pour une arrivée</li> 418 <li>2 pour un mur</li> 419 <li>3 pour du vide</li> 420 </ul> 421 422 <p> 423 Les cases point d'interrogation ont un type caché qui est révélé 424 losqu'on les regarde. 425 </p> 426 427 <p> 428 Placez vous devant la case point d'interrogation et faite un 429 <code>print(voir_droite())</code> 430 pour afficher son vrai type. 431 </p> 432 433 434 <div id="edcontainer"> 435 <div class="edcolumn"> 436 Code python : 437 <pre id="code" class="breditor"></pre> 438 <div id="feedback"></div> 439 </div> 440 <div class="edcolumn"> 441 Plateau : 442 <div id="game"></div> 443 </div> 444 </div> 445 446 447 448 449 450 451 </body> 452 </html>