lvl10.html (8352B)
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 movetime = 0; 104 var delayed_moves = []; 105 106 var config = { 107 type: Phaser.AUTO, 108 width: tilesize*10, 109 height: tilesize*10, 110 parent: "game", 111 scene: { 112 preload: preload, 113 create: create 114 } 115 }; 116 117 function preload() { 118 this.load.image("tilemap", "img/tilemap.png") 119 this.load.image("bot", "img/bot.png") 120 this.load.tilemapCSV('map', 'lvl/lvl10.csv'); 121 } 122 123 function create() { 124 map = this.make.tilemap({ key: 'map', tileWidth: 32, tileHeight: 32 }); 125 var tileset = map.addTilesetImage('tilemap'); 126 layer = map.createLayer(0, tileset, 0, 0); 127 128 bot = this.add.image(tilesize * 1.5, tilesize * 1.5, "bot") 129 } 130 131 function get_tile_at(x,y) { 132 return layer.getTileAtWorldXY(x*tilesize, y*tilesize, true).index; 133 } 134 135 function reset_board() { 136 movetime = 0; 137 bot.x = tilesize * 1.5; 138 bot.y = tilesize * 1.5; 139 bot.angle = 0; 140 141 for (move of delayed_moves){ 142 clearTimeout(move) 143 } 144 145 delayed_moves = [] 146 } 147 148 function move_left() { 149 delayed_moves.push( 150 setTimeout( 151 function() { 152 bot.x -= tilesize; 153 bot.angle = 180; 154 }, movetime) 155 ); 156 movetime += delay; 157 } 158 159 function move_right() { 160 delayed_moves.push( 161 setTimeout( 162 function() { 163 bot.x += tilesize; 164 bot.angle = 0; 165 }, movetime) 166 ); 167 movetime += delay; 168 } 169 170 function move_up() { 171 delayed_moves.push( 172 setTimeout( 173 function() { 174 bot.y -= tilesize; 175 bot.angle = -90; 176 }, movetime) 177 ); 178 movetime += delay; 179 } 180 181 function move_down() { 182 delayed_moves.push( 183 setTimeout( 184 function() { 185 bot.y += tilesize; 186 bot.angle = 90; 187 }, movetime) 188 ); 189 movetime += delay; 190 } 191 192 window.onload = function() { 193 loadSCO(); 194 document.getElementById("code").textContent = code; 195 196 game = new Phaser.Game(config); 197 198 brython(); 199 } 200 </script> 201 202 <script type="text/python"> 203 # Requires Brython and Ace editor 204 205 from browser import document, window, html 206 from sys import stderr, stdout, settrace 207 from traceback import print_exc, extract_stack, extract_tb 208 209 def make_max_line_tracer(maxlines): 210 lines = 0 211 def tracer(frame, event, arg): 212 nonlocal lines 213 if event == 'line': 214 lines += 1 215 if lines >= maxlines: 216 raise TimeoutError 217 return tracer 218 return tracer 219 220 def exec_code(editor, id): 221 reset() 222 feedback("Le drapeau n'est pas encore atteint") 223 224 code_lines = editor.session.getLength() 225 if code_lines > max_code_lines: 226 feedback("Trop de lignes utilisées ( " + str(code_lines) + "/" + str(max_code_lines) + ")") 227 return 228 229 console = document[id + "_console"] 230 console.clear() 231 stderr.write = lambda data : console_target(data, console, True) 232 stdout.write = lambda data : console_target(data, console) 233 234 code = editor.getValue() 235 try: 236 compiled = compile(code, "<" + id + ">", "exec") 237 except SyntaxError: 238 print_exc(limit=0) 239 return 240 241 settrace(make_max_line_tracer(10000)) # increase to allow longer execution 242 try: 243 exec(code) 244 except TimeoutError: 245 settrace(None) 246 print("L'exécution prend trop de temps, abandon.", file=stderr) 247 except Exception as e: 248 settrace(None) 249 tb_len = len(extract_tb(e.__traceback__)) - len(extract_stack()) 250 print_exc(limit=-tb_len) 251 finally: 252 settrace(None) 253 254 window.code = code 255 #window.score = check() 256 window.sendSCO() 257 258 def console_target(data, elt, err=False): 259 elt <= html.PRE(data, Class="stderr" if err else "stdout") 260 elt.scrollTop = elt.scrollHeight 261 262 breditors = document.select(".breditor") 263 264 max_code_lines = 10 265 266 for ed_elt in breditors: 267 editor = window.ace.edit(ed_elt.id) 268 editor.session.setMode("ace/mode/python") 269 #editor.setOption('fontSize', '14px') 270 editor.setOption('maxLines', max_code_lines) 271 editor.setOption('minLines', max_code_lines) 272 273 console = html.DIV(Class="console", id=ed_elt.id + "_console") 274 275 ed_elt.insertAdjacentElement('afterend', console) 276 277 exec_button = html.BUTTON("Exécuter →") 278 exec_button.bind("click", lambda ev : exec_code(editor, ed_elt.id)) 279 ed_elt.insertAdjacentElement('afterend', exec_button) 280 281 def feedback(msg): 282 document["feedback"].clear() 283 document["feedback"] <= msg 284 285 coords = [1,1] 286 287 def reset(): 288 global coords 289 window.reset_board() 290 coords = [1,1] 291 292 def gauche(): 293 if coords[0] >= 0: 294 tile = window.get_tile_at(coords[0]-1, coords[1]) 295 if tile in (0,1,3): 296 window.move_left() 297 coords[0] -= 1 298 if tile == 1: 299 win() 300 elif tile == 3: 301 fall() 302 303 def droite(): 304 if coords[0] < 10: 305 tile = window.get_tile_at(coords[0]+1, coords[1]) 306 if tile in (0,1,3): 307 window.move_right() 308 coords[0] += 1 309 if tile == 1: 310 win() 311 elif tile == 3: 312 fall() 313 314 def haut(): 315 if coords[1] >= 0: 316 tile = window.get_tile_at(coords[0], coords[1]-1) 317 if tile in (0,1,3): 318 window.move_up() 319 coords[1] -= 1 320 if tile == 1: 321 win() 322 elif tile == 3: 323 fall() 324 325 def bas(): 326 if coords[1] < 10: 327 tile = window.get_tile_at(coords[0], coords[1]+1) 328 if tile in (0,1,3): 329 window.move_down() 330 coords[1] += 1 331 if tile == 1: 332 win() 333 elif tile == 3: 334 fall() 335 336 def fall(): 337 feedback("Le robot est tombé dans le vide !") 338 raise Exception("Le robot est tombé dans le vide") 339 340 341 def win(): 342 window.score = 100 343 feedback("Bravo !") 344 document["feedback"] <= html.BUTTON("Passer à la suite", onclick="nextSCO();") 345 346 347 </script> 348 349 </head> 350 351 <body> 352 353 <h1>Niveau 10</h1> 354 355 Vous disposez des fonctions 356 <code>droite()</code>, 357 <code>gauche()</code>, 358 <code>haut()</code>, et 359 <code>bas()</code> 360 pour faire avancer le robot. 361 362 <div id="edcontainer"> 363 <div class="edcolumn"> 364 Code python : 365 <pre id="code" class="breditor"></pre> 366 <div id="feedback"></div> 367 </div> 368 <div class="edcolumn"> 369 Plateau : 370 <div id="game"></div> 371 </div> 372 </div> 373 374 375 376 377 378 379 </body> 380 </html>