{"id":280,"date":"2026-01-31T18:36:03","date_gmt":"2026-01-31T17:36:03","guid":{"rendered":"https:\/\/yb-isn.fr\/2025\/nsi\/?p=280"},"modified":"2026-02-02T08:20:44","modified_gmt":"2026-02-02T07:20:44","slug":"decouverte-de-pygame-de-zero-a-pac-man","status":"publish","type":"post","link":"https:\/\/yb-isn.fr\/2025\/nsi\/2026\/01\/31\/decouverte-de-pygame-de-zero-a-pac-man\/","title":{"rendered":"27-D\u00e9couverte de Pygame \u2014 de z\u00e9ro \u00e0 Pac\u2011Man"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">La librairie Pygame ne fonctionne pas pr\u00e9sente dans capytale.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">IL faut donc utiliser thonny.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Pygame<\/strong>, c\u2019est une biblioth\u00e8que Python qui sert \u00e0 cr\u00e9er facilement des <strong>jeux 2D<\/strong> et des <strong>animations interactives<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Elle fournit des \u201cbriques\u201d pr\u00eates \u00e0 l\u2019emploi pour :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Fen\u00eatre + boucle de jeu<\/strong> : cr\u00e9er une fen\u00eatre, la rafra\u00eechir \u00e0 une certaine vitesse (FPS).<\/li>\n\n\n\n<li><strong>\u00c9v\u00e9nements<\/strong> : lire le clavier, la souris, fermer la fen\u00eatre (<code>pygame.event.get()<\/code>).<\/li>\n\n\n\n<li><strong>Affichage 2D<\/strong> : dessiner des formes (rectangles, cercles\u2026), afficher des images (sprites), g\u00e9rer la transparence.<\/li>\n\n\n\n<li><strong>Collision<\/strong> : gr\u00e2ce aux rectangles (<code>pygame.Rect<\/code>) et \u00e0 <code>colliderect<\/code>.<\/li>\n\n\n\n<li><strong>Texte<\/strong> : afficher du texte avec des polices (<code>pygame.font<\/code>).<\/li>\n\n\n\n<li><strong>Temps<\/strong> : mesurer le temps et rendre le mouvement fluide avec <code>Clock<\/code> et <code>dt<\/code>.<\/li>\n\n\n\n<li><strong>Sons et musique<\/strong> : jouer des effets sonores (<code>pygame.mixer.Sound<\/code>) et de la musique (<code>pygame.mixer.music<\/code>).<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Le principe central : la \u201cboucle de jeu\u201d<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Presque tous les programmes Pygame suivent ce sch\u00e9ma :<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Lire les \u00e9v\u00e9nements<\/strong> (clavier, quitter\u2026)<\/li>\n\n\n\n<li><strong>Mettre \u00e0 jour<\/strong> la position des objets (joueur, ennemis\u2026)<\/li>\n\n\n\n<li><strong>Dessiner<\/strong> la sc\u00e8ne (fond, murs, sprites, score\u2026)<\/li>\n\n\n\n<li><strong>Afficher<\/strong> (<code>pygame.display.flip()<\/code>)<\/li>\n\n\n\n<li><strong>Limiter les FPS<\/strong> (<code>clock.tick(60)<\/code>)<\/li>\n<\/ol>\n\n\n\n<h4 class=\"wp-block-heading\">Pr\u00e9-requis<\/h4>\n\n\n\n<ol start=\"1\" class=\"wp-block-list\">\n<li>Installer&nbsp;<code>pygame<\/code>&nbsp;:&nbsp;<code>pip install pygame<\/code><\/li>\n\n\n\n<li>Avoir un dossier&nbsp;<code>assets<\/code> dans le m\u00eame r\u00e9pertoire que le code python<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/yb-isn.fr\/assets.zip\">T\u00e9l\u00e9charger le dossier assets<\/a><\/p>\n\n\n\n<p class=\"has-black-color has-text-color has-background has-link-color wp-elements-5903345e47bbd3bd692a11c1014f2594 wp-block-paragraph\" style=\"background:linear-gradient(135deg,rgb(216,244,179) 0%,rgb(17,184,81) 100%)\">1) Cr\u00e9ation et fermeture d\u2019une fen\u00eatre<\/p>\n\n\n\n<div class=\"wp-block-esab-accordion esab-gigcv3h3\" data-mode=\"global\"><div class=\"esab__container\">\n<div class=\"wp-block-esab-accordion-child\"><div class=\"esab__head\" role=\"button\" aria-expanded=\"false\"><div class=\"esab__heading_txt\"><p class=\"esab__heading_tag\">code python 1<\/p><\/div><div class=\"esab__icon\"><div class=\"esab__collapse\"> <svg version=\"1.2\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\"><path fill-rule=\"evenodd\" d=\"m3.5 20.5c-4.7-4.7-4.7-12.3 0-17 4.7-4.7 12.3-4.7 17 0 4.6 4.7 4.6 12.3 0 17-4.7 4.6-12.3 4.6-17 0zm0.9-0.9c4.2 4.2 11 4.2 15.2 0 4.2-4.2 4.2-11 0-15.2-4.2-4.3-11-4.3-15.2 0-4.3 4.2-4.3 11 0 15.2z\"><\/path><path d=\"m11.4 15.9v-3.3h-3.3c-0.3 0-0.6-0.3-0.6-0.6 0-0.4 0.3-0.6 0.6-0.6h3.3v-3.3c0-0.3 0.3-0.6 0.6-0.6 0.3 0 0.6 0.3 0.6 0.6v3.3h3.3c0.3 0 0.6 0.2 0.6 0.6q0 0.2-0.2 0.4-0.2 0.2-0.4 0.2h-3.3v3.3q0 0.2-0.2 0.4-0.2 0.2-0.4 0.2c-0.4 0-0.6-0.3-0.6-0.6z\"><\/path><\/svg> <\/div><div class=\"esab__expand\"> <svg version=\"1.2\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\"><path fill-rule=\"evenodd\" d=\"m12 24c-6.6 0-12-5.4-12-12 0-6.6 5.4-12 12-12 6.6 0 12 5.4 12 12 0 6.6-5.4 12-12 12zm10.6-12c0-5.9-4.7-10.6-10.6-10.6-5.9 0-10.6 4.7-10.6 10.6 0 5.9 4.7 10.6 10.6 10.6 5.9 0 10.6-4.7 10.6-10.6z\"><\/path><path d=\"m5.6 11.3h12.8v1.4h-12.8z\"><\/path><\/svg> <\/div><\/div><\/div><div class=\"esab__body\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"godzilla\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import pygame\npygame.init()\nLARGEUR, HAUTEUR = 800, 500\necran = pygame.display.set_mode((LARGEUR, HAUTEUR))\npygame.display.set_caption('1) Fen\u00eatre Pygame')\nhorloge = pygame.time.Clock()\nen_cours = True\nwhile en_cours:\n    for event in pygame.event.get():\n        if event.type == pygame.QUIT:\n            en_cours = False\n        if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:\n            en_cours = False\n    ecran.fill((0, 0, 0))\n    pygame.display.flip()\n    horloge.tick(60)\npygame.quit()\n<\/pre>\n<\/div><\/div>\n<\/div><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"has-black-color has-text-color has-background has-link-color wp-elements-9019588dd187a7add14750fd47fbc3d1 wp-block-paragraph\" style=\"background:linear-gradient(135deg,rgb(216,244,179) 0%,rgb(17,184,81) 100%)\">2) Modification des couleurs<\/p>\n\n\n\n<div class=\"wp-block-esab-accordion esab-p1kmiguy\" data-mode=\"global\"><div class=\"esab__container\">\n<div class=\"wp-block-esab-accordion-child\"><div class=\"esab__head\" role=\"button\" aria-expanded=\"false\"><div class=\"esab__heading_txt\"><p class=\"esab__heading_tag\">code python 2<\/p><\/div><div class=\"esab__icon\"><div class=\"esab__collapse\"> <svg version=\"1.2\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\"><path fill-rule=\"evenodd\" d=\"m3.5 20.5c-4.7-4.7-4.7-12.3 0-17 4.7-4.7 12.3-4.7 17 0 4.6 4.7 4.6 12.3 0 17-4.7 4.6-12.3 4.6-17 0zm0.9-0.9c4.2 4.2 11 4.2 15.2 0 4.2-4.2 4.2-11 0-15.2-4.2-4.3-11-4.3-15.2 0-4.3 4.2-4.3 11 0 15.2z\"><\/path><path d=\"m11.4 15.9v-3.3h-3.3c-0.3 0-0.6-0.3-0.6-0.6 0-0.4 0.3-0.6 0.6-0.6h3.3v-3.3c0-0.3 0.3-0.6 0.6-0.6 0.3 0 0.6 0.3 0.6 0.6v3.3h3.3c0.3 0 0.6 0.2 0.6 0.6q0 0.2-0.2 0.4-0.2 0.2-0.4 0.2h-3.3v3.3q0 0.2-0.2 0.4-0.2 0.2-0.4 0.2c-0.4 0-0.6-0.3-0.6-0.6z\"><\/path><\/svg> <\/div><div class=\"esab__expand\"> <svg version=\"1.2\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\"><path fill-rule=\"evenodd\" d=\"m12 24c-6.6 0-12-5.4-12-12 0-6.6 5.4-12 12-12 6.6 0 12 5.4 12 12 0 6.6-5.4 12-12 12zm10.6-12c0-5.9-4.7-10.6-10.6-10.6-5.9 0-10.6 4.7-10.6 10.6 0 5.9 4.7 10.6 10.6 10.6 5.9 0 10.6-4.7 10.6-10.6z\"><\/path><path d=\"m5.6 11.3h12.8v1.4h-12.8z\"><\/path><\/svg> <\/div><\/div><\/div><div class=\"esab__body\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"godzilla\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import pygame\npygame.init()\nLARGEUR, HAUTEUR = 800, 500\necran = pygame.display.set_mode((LARGEUR, HAUTEUR))\npygame.display.set_caption('2) Couleurs')\nhorloge = pygame.time.Clock()\ncouleur_fond = (20, 20, 30)\nen_cours = True\nwhile en_cours:\n    for event in pygame.event.get():\n        if event.type == pygame.QUIT:\n            en_cours = False\n        if event.type == pygame.KEYDOWN:\n            if event.key == pygame.K_ESCAPE:\n                en_cours = False\n            elif event.key == pygame.K_1:\n                couleur_fond = (30, 30, 40)\n            elif event.key == pygame.K_2:\n                couleur_fond = (60, 20, 20)\n            elif event.key == pygame.K_3:\n                couleur_fond = (20, 60, 30)\n    ecran.fill(couleur_fond)\n    pygame.display.flip()\n    horloge.tick(60)\npygame.quit()\n<\/pre>\n<\/div><\/div>\n<\/div><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"has-black-color has-text-color has-background has-link-color wp-elements-8047419bba6d7735585ac3fccefb5739 wp-block-paragraph\" style=\"background:linear-gradient(135deg,rgb(216,244,179) 0%,rgb(17,184,81) 100%)\">3) Cr\u00e9ation d\u2019un rectangle<\/p>\n\n\n\n<div class=\"wp-block-esab-accordion esab-kzngvoak\" data-mode=\"global\"><div class=\"esab__container\">\n<div class=\"wp-block-esab-accordion-child\"><div class=\"esab__head\" role=\"button\" aria-expanded=\"false\"><div class=\"esab__heading_txt\"><p class=\"esab__heading_tag\">code python 3<\/p><\/div><div class=\"esab__icon\"><div class=\"esab__collapse\"> <svg version=\"1.2\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\"><path fill-rule=\"evenodd\" d=\"m3.5 20.5c-4.7-4.7-4.7-12.3 0-17 4.7-4.7 12.3-4.7 17 0 4.6 4.7 4.6 12.3 0 17-4.7 4.6-12.3 4.6-17 0zm0.9-0.9c4.2 4.2 11 4.2 15.2 0 4.2-4.2 4.2-11 0-15.2-4.2-4.3-11-4.3-15.2 0-4.3 4.2-4.3 11 0 15.2z\"><\/path><path d=\"m11.4 15.9v-3.3h-3.3c-0.3 0-0.6-0.3-0.6-0.6 0-0.4 0.3-0.6 0.6-0.6h3.3v-3.3c0-0.3 0.3-0.6 0.6-0.6 0.3 0 0.6 0.3 0.6 0.6v3.3h3.3c0.3 0 0.6 0.2 0.6 0.6q0 0.2-0.2 0.4-0.2 0.2-0.4 0.2h-3.3v3.3q0 0.2-0.2 0.4-0.2 0.2-0.4 0.2c-0.4 0-0.6-0.3-0.6-0.6z\"><\/path><\/svg> <\/div><div class=\"esab__expand\"> <svg version=\"1.2\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\"><path fill-rule=\"evenodd\" d=\"m12 24c-6.6 0-12-5.4-12-12 0-6.6 5.4-12 12-12 6.6 0 12 5.4 12 12 0 6.6-5.4 12-12 12zm10.6-12c0-5.9-4.7-10.6-10.6-10.6-5.9 0-10.6 4.7-10.6 10.6 0 5.9 4.7 10.6 10.6 10.6 5.9 0 10.6-4.7 10.6-10.6z\"><\/path><path d=\"m5.6 11.3h12.8v1.4h-12.8z\"><\/path><\/svg> <\/div><\/div><\/div><div class=\"esab__body\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"godzilla\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import pygame\npygame.init()\nLARGEUR, HAUTEUR = 800, 500\necran = pygame.display.set_mode((LARGEUR, HAUTEUR))\npygame.display.set_caption('3) Rectangle')\nhorloge = pygame.time.Clock()\nrectangle = pygame.Rect(0, 0, 80, 60)\nrectangle.center = (LARGEUR\/\/2, HAUTEUR\/\/2)\nen_cours = True\nwhile en_cours:\n    for event in pygame.event.get():\n        if event.type == pygame.QUIT:\n            en_cours = False\n        if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:\n            en_cours = False\n    ecran.fill((20, 20, 30))\n    pygame.draw.rect(ecran, (80, 140, 255), rectangle, border_radius=10)\n    pygame.display.flip()\n    horloge.tick(60)\npygame.quit()\n<\/pre>\n<\/div><\/div>\n<\/div><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"has-black-color has-text-color has-background has-link-color wp-elements-380d81f1397eacd05f78ec506f3aed57 wp-block-paragraph\" style=\"background:linear-gradient(135deg,rgb(216,244,179) 0%,rgb(17,184,81) 100%)\">4) D\u00e9placement du rectangle avec le clavier (fl\u00e8ches)<\/p>\n\n\n\n<div class=\"wp-block-esab-accordion esab-na2qc5s0\" data-mode=\"global\"><div class=\"esab__container\">\n<div class=\"wp-block-esab-accordion-child\"><div class=\"esab__head\" role=\"button\" aria-expanded=\"false\"><div class=\"esab__heading_txt\"><p class=\"esab__heading_tag\">code python 4<\/p><\/div><div class=\"esab__icon\"><div class=\"esab__collapse\"> <svg version=\"1.2\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\"><path fill-rule=\"evenodd\" d=\"m3.5 20.5c-4.7-4.7-4.7-12.3 0-17 4.7-4.7 12.3-4.7 17 0 4.6 4.7 4.6 12.3 0 17-4.7 4.6-12.3 4.6-17 0zm0.9-0.9c4.2 4.2 11 4.2 15.2 0 4.2-4.2 4.2-11 0-15.2-4.2-4.3-11-4.3-15.2 0-4.3 4.2-4.3 11 0 15.2z\"><\/path><path d=\"m11.4 15.9v-3.3h-3.3c-0.3 0-0.6-0.3-0.6-0.6 0-0.4 0.3-0.6 0.6-0.6h3.3v-3.3c0-0.3 0.3-0.6 0.6-0.6 0.3 0 0.6 0.3 0.6 0.6v3.3h3.3c0.3 0 0.6 0.2 0.6 0.6q0 0.2-0.2 0.4-0.2 0.2-0.4 0.2h-3.3v3.3q0 0.2-0.2 0.4-0.2 0.2-0.4 0.2c-0.4 0-0.6-0.3-0.6-0.6z\"><\/path><\/svg> <\/div><div class=\"esab__expand\"> <svg version=\"1.2\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\"><path fill-rule=\"evenodd\" d=\"m12 24c-6.6 0-12-5.4-12-12 0-6.6 5.4-12 12-12 6.6 0 12 5.4 12 12 0 6.6-5.4 12-12 12zm10.6-12c0-5.9-4.7-10.6-10.6-10.6-5.9 0-10.6 4.7-10.6 10.6 0 5.9 4.7 10.6 10.6 10.6 5.9 0 10.6-4.7 10.6-10.6z\"><\/path><path d=\"m5.6 11.3h12.8v1.4h-12.8z\"><\/path><\/svg> <\/div><\/div><\/div><div class=\"esab__body\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"godzilla\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import pygame\npygame.init()\nLARGEUR, HAUTEUR = 800, 500\necran = pygame.display.set_mode((LARGEUR, HAUTEUR))\npygame.display.set_caption('4) Rectangle au clavier')\nhorloge = pygame.time.Clock()\nrectangle = pygame.Rect(0, 0, 80, 60)\nrectangle.center = (LARGEUR\/\/2, HAUTEUR\/\/2)\nvitesse = 280.0  # pixels par seconde\nen_cours = True\nwhile en_cours:\n    dt = horloge.tick(60) \/ 1000.0\n    for event in pygame.event.get():\n        if event.type == pygame.QUIT:\n            en_cours = False\n        if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:\n            en_cours = False\n    touches = pygame.key.get_pressed()\n    dx, dy = 0, 0\n    if touches[pygame.K_LEFT]: dx -= 1\n    if touches[pygame.K_RIGHT]: dx += 1\n    if touches[pygame.K_UP]: dy -= 1\n    if touches[pygame.K_DOWN]: dy += 1\n    rectangle.x += int(dx * vitesse * dt)\n    rectangle.y += int(dy * vitesse * dt)\n    # Emp\u00eacher de sortir de la fen\u00eatre\n    rectangle.clamp_ip(pygame.Rect(0, 0, LARGEUR, HAUTEUR))\n    ecran.fill((20, 20, 30))\n    pygame.draw.rect(ecran, (80, 140, 255), rectangle, border_radius=10)\n    pygame.display.flip()\npygame.quit()\n<\/pre>\n<\/div><\/div>\n<\/div><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"has-black-color has-text-color has-background has-link-color wp-elements-910753d5e4bd641d1f484cccf2ff62d5 wp-block-paragraph\" style=\"background:linear-gradient(135deg,rgb(216,244,179) 0%,rgb(17,184,81) 100%)\">5) Remplacer le rectangle par Pac\u2011Man (images pr\u00e9enregistr\u00e9es) + d\u00e9placement au clavier<\/p>\n\n\n\n<div class=\"wp-block-esab-accordion esab-ashqefo3\" data-mode=\"global\"><div class=\"esab__container\">\n<div class=\"wp-block-esab-accordion-child\"><div class=\"esab__head\" role=\"button\" aria-expanded=\"false\"><div class=\"esab__heading_txt\"><p class=\"esab__heading_tag\">code python 5<\/p><\/div><div class=\"esab__icon\"><div class=\"esab__collapse\"> <svg version=\"1.2\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\"><path fill-rule=\"evenodd\" d=\"m3.5 20.5c-4.7-4.7-4.7-12.3 0-17 4.7-4.7 12.3-4.7 17 0 4.6 4.7 4.6 12.3 0 17-4.7 4.6-12.3 4.6-17 0zm0.9-0.9c4.2 4.2 11 4.2 15.2 0 4.2-4.2 4.2-11 0-15.2-4.2-4.3-11-4.3-15.2 0-4.3 4.2-4.3 11 0 15.2z\"><\/path><path d=\"m11.4 15.9v-3.3h-3.3c-0.3 0-0.6-0.3-0.6-0.6 0-0.4 0.3-0.6 0.6-0.6h3.3v-3.3c0-0.3 0.3-0.6 0.6-0.6 0.3 0 0.6 0.3 0.6 0.6v3.3h3.3c0.3 0 0.6 0.2 0.6 0.6q0 0.2-0.2 0.4-0.2 0.2-0.4 0.2h-3.3v3.3q0 0.2-0.2 0.4-0.2 0.2-0.4 0.2c-0.4 0-0.6-0.3-0.6-0.6z\"><\/path><\/svg> <\/div><div class=\"esab__expand\"> <svg version=\"1.2\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\"><path fill-rule=\"evenodd\" d=\"m12 24c-6.6 0-12-5.4-12-12 0-6.6 5.4-12 12-12 6.6 0 12 5.4 12 12 0 6.6-5.4 12-12 12zm10.6-12c0-5.9-4.7-10.6-10.6-10.6-5.9 0-10.6 4.7-10.6 10.6 0 5.9 4.7 10.6 10.6 10.6 5.9 0 10.6-4.7 10.6-10.6z\"><\/path><path d=\"m5.6 11.3h12.8v1.4h-12.8z\"><\/path><\/svg> <\/div><\/div><\/div><div class=\"esab__body\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"godzilla\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import pygame\nfrom pathlib import Path\npygame.init()\nLARGEUR, HAUTEUR = 800, 500\necran = pygame.display.set_mode((LARGEUR, HAUTEUR))\npygame.display.set_caption('5) Pac-Man au clavier')\nhorloge = pygame.time.Clock()\n\n# Charger les images\ndossier_assets = Path('assets')\nfichiers = ['pacman_0.png', 'pacman_1.png', 'pacman_2.png']\nframes = []\nfor nom in fichiers:\n    img = pygame.image.load(str(dossier_assets \/ nom)).convert_alpha()\n    img = pygame.transform.smoothscale(img, (64, 64))\n    frames.append(img)\n\ndef frames_orientees(direction):\n    dx, dy = direction\n    if (dx, dy) == (1, 0):\n        return frames\n    if (dx, dy) == (-1, 0):\n        return [pygame.transform.flip(f, True, False) for f in frames]\n    if (dx, dy) == (0, -1):\n        return [pygame.transform.rotate(f, 90) for f in frames]\n    if (dx, dy) == (0, 1):\n        return [pygame.transform.rotate(f, -90) for f in frames]\n    return frames\n\n# Pac-Man (dictionnaire)\npacman = {\n    'x': LARGEUR\/\/2,\n    'y': HAUTEUR\/\/2,\n    'vitesse': 240.0,\n    'direction_aff': (1, 0),\n    'frame': 0,\n    'temps_anim': 0.0,\n}\n\nen_cours = True\nwhile en_cours:\n    dt = horloge.tick(60) \/ 1000.0\n    for event in pygame.event.get():\n        if event.type == pygame.QUIT:\n            en_cours = False\n        if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:\n            en_cours = False\n\n    touches = pygame.key.get_pressed()\n    dx, dy = 0, 0\n    if touches[pygame.K_LEFT]: dx -= 1\n    if touches[pygame.K_RIGHT]: dx += 1\n    if touches[pygame.K_UP]: dy -= 1\n    if touches[pygame.K_DOWN]: dy += 1\n\n    # D\u00e9placement\n    pacman['x'] += dx * pacman['vitesse'] * dt\n    pacman['y'] += dy * pacman['vitesse'] * dt\n\n    # Limites fen\u00eatre (pour \u00e9viter de sortir)\n    pacman['x'] = max(32, min(LARGEUR-32, pacman['x']))\n    pacman['y'] = max(32, min(HAUTEUR-32, pacman['y']))\n\n    bouge = (dx != 0 or dy != 0)\n    if bouge:\n        pacman['direction_aff'] = (dx, dy)\n        pacman['temps_anim'] += dt\n        if pacman['temps_anim'] >= 1.0\/12:\n            pacman['temps_anim'] = 0.0\n            pacman['frame'] = (pacman['frame'] + 1) % len(frames)\n    else:\n        pacman['frame'] = 0\n        pacman['temps_anim'] = 0.0\n\n    ecran.fill((20, 20, 30))\n    fr = frames_orientees(pacman['direction_aff'])\n    sprite = fr[pacman['frame']]\n    rect = sprite.get_rect(center=(int(pacman['x']), int(pacman['y'])))\n    ecran.blit(sprite, rect.topleft)\n    pygame.display.flip()\n\npygame.quit()\n\n<\/pre>\n<\/div><\/div>\n<\/div><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"has-black-color has-text-color has-background has-link-color wp-elements-1c0325c9f1efa64e2a818f0cee896ce7 wp-block-paragraph\" style=\"background:linear-gradient(135deg,rgb(216,244,179) 0%,rgb(17,184,81) 100%)\">6) Dessiner un labyrinthe tr\u00e8s simple (1 seul niveau)<\/p>\n\n\n\n<div class=\"wp-block-esab-accordion esab-p7k9gbuy\" data-mode=\"global\"><div class=\"esab__container\">\n<div class=\"wp-block-esab-accordion-child\"><div class=\"esab__head\" role=\"button\" aria-expanded=\"false\"><div class=\"esab__heading_txt\"><p class=\"esab__heading_tag\">code python 6<\/p><\/div><div class=\"esab__icon\"><div class=\"esab__collapse\"> <svg version=\"1.2\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\"><path fill-rule=\"evenodd\" d=\"m3.5 20.5c-4.7-4.7-4.7-12.3 0-17 4.7-4.7 12.3-4.7 17 0 4.6 4.7 4.6 12.3 0 17-4.7 4.6-12.3 4.6-17 0zm0.9-0.9c4.2 4.2 11 4.2 15.2 0 4.2-4.2 4.2-11 0-15.2-4.2-4.3-11-4.3-15.2 0-4.3 4.2-4.3 11 0 15.2z\"><\/path><path d=\"m11.4 15.9v-3.3h-3.3c-0.3 0-0.6-0.3-0.6-0.6 0-0.4 0.3-0.6 0.6-0.6h3.3v-3.3c0-0.3 0.3-0.6 0.6-0.6 0.3 0 0.6 0.3 0.6 0.6v3.3h3.3c0.3 0 0.6 0.2 0.6 0.6q0 0.2-0.2 0.4-0.2 0.2-0.4 0.2h-3.3v3.3q0 0.2-0.2 0.4-0.2 0.2-0.4 0.2c-0.4 0-0.6-0.3-0.6-0.6z\"><\/path><\/svg> <\/div><div class=\"esab__expand\"> <svg version=\"1.2\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\"><path fill-rule=\"evenodd\" d=\"m12 24c-6.6 0-12-5.4-12-12 0-6.6 5.4-12 12-12 6.6 0 12 5.4 12 12 0 6.6-5.4 12-12 12zm10.6-12c0-5.9-4.7-10.6-10.6-10.6-5.9 0-10.6 4.7-10.6 10.6 0 5.9 4.7 10.6 10.6 10.6 5.9 0 10.6-4.7 10.6-10.6z\"><\/path><path d=\"m5.6 11.3h12.8v1.4h-12.8z\"><\/path><\/svg> <\/div><\/div><\/div><div class=\"esab__body\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"godzilla\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import pygame\npygame.init()\nLABYRINTHE = [\n    '####################',\n    '#........#.........#',\n    '#.######.#.#####...#',\n    '#.#....#.#.....#...#',\n    '#.#.##.#.#####.#...#',\n    '#...##.#.....#.#...#',\n    '###.##.#####.#.###.#',\n    '#......#.....#.....#',\n    '####################',\n]\ngrille = [list(l) for l in LABYRINTHE]\nH = len(grille)\nW = len(grille[0])\nLARGEUR, HAUTEUR = 900, 520\necran = pygame.display.set_mode((LARGEUR, HAUTEUR))\npygame.display.set_caption('6) Labyrinthe')\nhorloge = pygame.time.Clock()\nmarge = 30\ntaille_tuile = min((LARGEUR - 2*marge)\/\/W, (HAUTEUR - 2*marge)\/\/H)\ntaille_tuile = max(16, int(taille_tuile))\nox = (LARGEUR - W*taille_tuile)\/\/2\noy = (HAUTEUR - H*taille_tuile)\/\/2\nen_cours = True\nwhile en_cours:\n    for event in pygame.event.get():\n        if event.type == pygame.QUIT:\n            en_cours = False\n        if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:\n            en_cours = False\n    ecran.fill((15, 15, 20))\n    for y in range(H):\n        for x in range(W):\n            r = pygame.Rect(ox + x*taille_tuile, oy + y*taille_tuile, taille_tuile, taille_tuile)\n            if grille[y][x] == '#':\n                pygame.draw.rect(ecran, (70, 70, 85), r)\n            else:\n                pygame.draw.rect(ecran, (25, 25, 32), r)\n    pygame.display.flip()\n    horloge.tick(60)\npygame.quit()\n<\/pre>\n<\/div><\/div>\n<\/div><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"has-black-color has-text-color has-background has-link-color wp-elements-b1265406846f6c59f6233809dc676848 wp-block-paragraph\" style=\"background:linear-gradient(135deg,rgb(216,244,179) 0%,rgb(17,184,81) 100%)\">7) Pac\u2011Man d\u00e9pla\u00e7able dans le labyrinthe (au clavier)<\/p>\n\n\n\n<div class=\"wp-block-esab-accordion esab-4q2bdsv6\" data-mode=\"global\" data-close=\"true\"><div class=\"esab__container\">\n<div class=\"wp-block-esab-accordion-child\"><div class=\"esab__head\" role=\"button\" aria-expanded=\"false\"><div class=\"esab__heading_txt\"><p class=\"esab__heading_tag\">code python 7<\/p><\/div><div class=\"esab__icon\"><div class=\"esab__collapse\"> <svg version=\"1.2\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\"><path fill-rule=\"evenodd\" d=\"m3.5 20.5c-4.7-4.7-4.7-12.3 0-17 4.7-4.7 12.3-4.7 17 0 4.6 4.7 4.6 12.3 0 17-4.7 4.6-12.3 4.6-17 0zm0.9-0.9c4.2 4.2 11 4.2 15.2 0 4.2-4.2 4.2-11 0-15.2-4.2-4.3-11-4.3-15.2 0-4.3 4.2-4.3 11 0 15.2z\"><\/path><path d=\"m11.4 15.9v-3.3h-3.3c-0.3 0-0.6-0.3-0.6-0.6 0-0.4 0.3-0.6 0.6-0.6h3.3v-3.3c0-0.3 0.3-0.6 0.6-0.6 0.3 0 0.6 0.3 0.6 0.6v3.3h3.3c0.3 0 0.6 0.2 0.6 0.6q0 0.2-0.2 0.4-0.2 0.2-0.4 0.2h-3.3v3.3q0 0.2-0.2 0.4-0.2 0.2-0.4 0.2c-0.4 0-0.6-0.3-0.6-0.6z\"><\/path><\/svg> <\/div><div class=\"esab__expand\"> <svg version=\"1.2\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\"><path fill-rule=\"evenodd\" d=\"m12 24c-6.6 0-12-5.4-12-12 0-6.6 5.4-12 12-12 6.6 0 12 5.4 12 12 0 6.6-5.4 12-12 12zm10.6-12c0-5.9-4.7-10.6-10.6-10.6-5.9 0-10.6 4.7-10.6 10.6 0 5.9 4.7 10.6 10.6 10.6 5.9 0 10.6-4.7 10.6-10.6z\"><\/path><path d=\"m5.6 11.3h12.8v1.4h-12.8z\"><\/path><\/svg> <\/div><\/div><\/div><div class=\"esab__body\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-theme=\"godzilla\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import pygame\nfrom pathlib import Path\npygame.init()\n\nLABYRINTHE = [\n    '####################',\n    '#........#.........#',\n    '#.######.#.#####...#',\n    '#.#....#.#.....#...#',\n    '#.#.##.#.#####.#...#',\n    '#...##.#.....#.#...#',\n    '###.##.#####.#.###.#',\n    '#......#.....#.....#',\n    '####################',\n]\ngrille = [list(l) for l in LABYRINTHE]\nH = len(grille)\nW = len(grille[0])\n\nLARGEUR, HAUTEUR = 900, 520\necran = pygame.display.set_mode((LARGEUR, HAUTEUR))\npygame.display.set_caption('7) Pac-Man dans un labyrinthe (clavier)')\nhorloge = pygame.time.Clock()\n\nmarge = 30\ntaille_tuile = min((LARGEUR - 2*marge)\/\/W, (HAUTEUR - 2*marge)\/\/H)\ntaille_tuile = max(16, int(taille_tuile))\nox = (LARGEUR - W*taille_tuile)\/\/2\noy = (HAUTEUR - H*taille_tuile)\/\/2\n\ndef rect_tuile(x_case, y_case):\n    return pygame.Rect(ox + x_case*taille_tuile, oy + y_case*taille_tuile, taille_tuile, taille_tuile)\n\n# Pr\u00e9parer la liste des murs (Rect)\nmurs = []\nfor y in range(H):\n    for x in range(W):\n        if grille[y][x] == '#':\n            murs.append(rect_tuile(x, y))\n\n# Charger Pac-Man\ndossier_assets = Path('assets')\nfichiers = ['pacman_0.png', 'pacman_1.png', 'pacman_2.png']\nframes_base = []\nfor nom in fichiers:\n    img = pygame.image.load(str(dossier_assets \/ nom)).convert_alpha()\n    img = pygame.transform.smoothscale(img, (int(taille_tuile*0.95), int(taille_tuile*0.95)))\n    frames_base.append(img)\n\ndef frames_orientees(direction):\n    dx, dy = direction\n    if (dx, dy) == (1, 0):\n        return frames_base\n    if (dx, dy) == (-1, 0):\n        return [pygame.transform.flip(f, True, False) for f in frames_base]\n    if (dx, dy) == (0, -1):\n        return [pygame.transform.rotate(f, 90) for f in frames_base]\n    if (dx, dy) == (0, 1):\n        return [pygame.transform.rotate(f, -90) for f in frames_base]\n    return frames_base\n\ndef rect_pacman(px, py):\n    # hitbox un peu plus petite que la tuile\n    s = int(taille_tuile*0.78)\n    return pygame.Rect(int(px - s\/2), int(py - s\/2), s, s)\n\ndef collision_mur(r):\n    return any(r.colliderect(m) for m in murs)\n\ndef dessiner_labyrinthe():\n    for y in range(H):\n        for x in range(W):\n            r = rect_tuile(x, y)\n            if grille[y][x] == '#':\n                pygame.draw.rect(ecran, (70, 70, 85), r)\n            else:\n                pygame.draw.rect(ecran, (25, 25, 32), r)\n\n# Pac-Man (dictionnaire)\npacman = {\n    'x': ox + 1.5*taille_tuile,\n    'y': oy + 1.5*taille_tuile,\n    'vitesse': 220.0,\n    'direction_aff': (1, 0),\n    'frame': 0,\n    'temps_anim': 0.0,\n}\n\nen_cours = True\nwhile en_cours:\n    dt = horloge.tick(60) \/ 1000.0\n    for event in pygame.event.get():\n        if event.type == pygame.QUIT:\n            en_cours = False\n        if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:\n            en_cours = False\n\n    touches = pygame.key.get_pressed()\n    dx, dy = 0, 0\n    if touches[pygame.K_LEFT]: dx -= 1\n    if touches[pygame.K_RIGHT]: dx += 1\n    if touches[pygame.K_UP]: dy -= 1\n    if touches[pygame.K_DOWN]: dy += 1\n\n    vx = dx * pacman['vitesse'] * dt\n    vy = dy * pacman['vitesse'] * dt\n\n    if dx != 0 or dy != 0:\n        pacman['direction_aff'] = (dx, dy)\n\n    # D\u00e9placement s\u00e9par\u00e9 X puis Y (plus simple pour g\u00e9rer les collisions)\n    nx = pacman['x'] + vx\n    if not collision_mur(rect_pacman(nx, pacman['y'])):\n        pacman['x'] = nx\n    ny = pacman['y'] + vy\n    if not collision_mur(rect_pacman(pacman['x'], ny)):\n        pacman['y'] = ny\n\n    # Animation\n    bouge = (dx != 0 or dy != 0)\n    if bouge:\n        pacman['temps_anim'] += dt\n        if pacman['temps_anim'] >= 1.0\/12:\n            pacman['temps_anim'] = 0.0\n            pacman['frame'] = (pacman['frame'] + 1) % len(frames_base)\n    else:\n        pacman['frame'] = 0\n        pacman['temps_anim'] = 0.0\n\n    ecran.fill((15, 15, 20))\n    dessiner_labyrinthe()\n    fr = frames_orientees(pacman['direction_aff'])\n    sprite = fr[pacman['frame']]\n    rect_sprite = sprite.get_rect(center=(int(pacman['x']), int(pacman['y'])))\n    ecran.blit(sprite, rect_sprite.topleft)\n    pygame.display.flip()\n\npygame.quit()\n\n<\/pre>\n<\/div><\/div>\n<\/div><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"has-black-color has-text-color has-background has-link-color wp-elements-62d5872e083924470007bd500b9fcdfa wp-block-paragraph\" style=\"background:linear-gradient(135deg,rgb(216,244,179) 0%,rgb(17,184,81) 100%)\">8) Pastilles \u00e0 collecter + score<\/p>\n\n\n\n<div class=\"wp-block-esab-accordion esab-joxg6p9y\" data-mode=\"global\" data-close=\"true\"><div class=\"esab__container\">\n<div class=\"wp-block-esab-accordion-child\"><div class=\"esab__head\" role=\"button\" aria-expanded=\"false\"><div class=\"esab__heading_txt\"><p class=\"esab__heading_tag\">code python 8<\/p><\/div><div class=\"esab__icon\"><div class=\"esab__collapse\"> <svg version=\"1.2\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\"><path fill-rule=\"evenodd\" d=\"m3.5 20.5c-4.7-4.7-4.7-12.3 0-17 4.7-4.7 12.3-4.7 17 0 4.6 4.7 4.6 12.3 0 17-4.7 4.6-12.3 4.6-17 0zm0.9-0.9c4.2 4.2 11 4.2 15.2 0 4.2-4.2 4.2-11 0-15.2-4.2-4.3-11-4.3-15.2 0-4.3 4.2-4.3 11 0 15.2z\"><\/path><path d=\"m11.4 15.9v-3.3h-3.3c-0.3 0-0.6-0.3-0.6-0.6 0-0.4 0.3-0.6 0.6-0.6h3.3v-3.3c0-0.3 0.3-0.6 0.6-0.6 0.3 0 0.6 0.3 0.6 0.6v3.3h3.3c0.3 0 0.6 0.2 0.6 0.6q0 0.2-0.2 0.4-0.2 0.2-0.4 0.2h-3.3v3.3q0 0.2-0.2 0.4-0.2 0.2-0.4 0.2c-0.4 0-0.6-0.3-0.6-0.6z\"><\/path><\/svg> <\/div><div class=\"esab__expand\"> <svg version=\"1.2\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\"><path fill-rule=\"evenodd\" d=\"m12 24c-6.6 0-12-5.4-12-12 0-6.6 5.4-12 12-12 6.6 0 12 5.4 12 12 0 6.6-5.4 12-12 12zm10.6-12c0-5.9-4.7-10.6-10.6-10.6-5.9 0-10.6 4.7-10.6 10.6 0 5.9 4.7 10.6 10.6 10.6 5.9 0 10.6-4.7 10.6-10.6z\"><\/path><path d=\"m5.6 11.3h12.8v1.4h-12.8z\"><\/path><\/svg> <\/div><\/div><\/div><div class=\"esab__body\">\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"godzilla\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import pygame\nfrom pathlib import Path\n\npygame.init()\n\nLABYRINTHE = [\n    \"####################\",\n    \"#P.......#.........#\",\n    \"#.######.#.#####...#\",\n    \"#.#....#.#.....#...#\",\n    \"#.#.##.#.#####.#...#\",\n    \"#...##.#.....#.#...#\",\n    \"###.##.#####.#.###.#\",\n    \"#......#.....#.....#\",\n    \"##################D#\",\n]\n\ngrille = [list(l) for l in LABYRINTHE]\nH = len(grille)\nW = len(grille[0])\n\nLARGEUR, HAUTEUR = 900, 520\necran = pygame.display.set_mode((LARGEUR, HAUTEUR))\npygame.display.set_caption(\"8) Pastilles + score\")\nhorloge = pygame.time.Clock()\npolice = pygame.font.SysFont(None, 28)\n\nmarge = 30\ntaille_tuile = min((LARGEUR - 2*marge)\/\/W, (HAUTEUR - 2*marge)\/\/H)\ntaille_tuile = max(16, int(taille_tuile))\nox = (LARGEUR - W*taille_tuile)\/\/2\noy = (HAUTEUR - H*taille_tuile)\/\/2\n\ndef rect_tuile(x_case, y_case):\n    return pygame.Rect(ox + x_case*taille_tuile, oy + y_case*taille_tuile, taille_tuile, taille_tuile)\n\n# Murs + positions sp\u00e9ciales\nmurs = []\ncase_depart = None\ncase_porte = None\nfor y in range(H):\n    for x in range(W):\n        c = grille[y][x]\n        if c == \"#\":\n            murs.append(rect_tuile(x, y))\n        elif c == \"P\":\n            case_depart = (x, y)\n            grille[y][x] = \".\"\n        elif c == \"D\":\n            case_porte = (x, y)\n            grille[y][x] = \".\"\n\n# Pastilles (toutes les cases de sol sauf d\u00e9part\/porte)\npastilles = set()\nfor y in range(H):\n    for x in range(W):\n        if grille[y][x] == \".\" and (x, y) not in (case_depart, case_porte):\n            pastilles.add((x, y))\n\n# Charger Pac-Man\ndossier_assets = Path(\"assets\")\nfichiers = [\"pacman_0.png\", \"pacman_1.png\", \"pacman_2.png\"]\nframes_base = []\nfor nom in fichiers:\n    img = pygame.image.load(str(dossier_assets \/ nom)).convert_alpha()\n    img = pygame.transform.smoothscale(img, (int(taille_tuile*0.95), int(taille_tuile*0.95)))\n    frames_base.append(img)\n\ndef frames_orientees(direction):\n    dx, dy = direction\n    if (dx, dy) == (1, 0):\n        return frames_base\n    if (dx, dy) == (-1, 0):\n        return [pygame.transform.flip(f, True, False) for f in frames_base]\n    if (dx, dy) == (0, -1):\n        return [pygame.transform.rotate(f, 90) for f in frames_base]\n    if (dx, dy) == (0, 1):\n        return [pygame.transform.rotate(f, -90) for f in frames_base]\n    return frames_base\n\ndef rect_pacman(px, py):\n    s = int(taille_tuile*0.78)\n    return pygame.Rect(int(px - s\/2), int(py - s\/2), s, s)\n\ndef collision_mur(r):\n    return any(r.colliderect(m) for m in murs)\n\ndef case_depuis_position(px, py):\n    return (int((px - ox)\/\/taille_tuile), int((py - oy)\/\/taille_tuile))\n\n# Pac-Man\npacman = {\n    \"x\": ox + (case_depart[0] + 0.5)*taille_tuile,\n    \"y\": oy + (case_depart[1] + 0.5)*taille_tuile,\n    \"vitesse\": 220.0,\n    \"direction_aff\": (1, 0),\n    \"frame\": 0,\n    \"temps_anim\": 0.0,\n}\nscore = 0\n\ndef dessiner_labyrinthe():\n    for y in range(H):\n        for x in range(W):\n            r = rect_tuile(x, y)\n            if grille[y][x] == \"#\":\n                pygame.draw.rect(ecran, (70, 70, 85), r)\n            else:\n                pygame.draw.rect(ecran, (25, 25, 32), r)\n    # Porte (orange)\n    r = rect_tuile(case_porte[0], case_porte[1]).inflate(-10, -10)\n    pygame.draw.rect(ecran, (220, 120, 60), r, border_radius=10)\n\ndef dessiner_pastilles():\n    rayon = max(2, taille_tuile\/\/8)\n    for (x, y) in pastilles:\n        cx = ox + x*taille_tuile + taille_tuile\/\/2\n        cy = oy + y*taille_tuile + taille_tuile\/\/2\n        pygame.draw.circle(ecran, (240, 200, 60), (cx, cy), rayon)\n\nen_cours = True\nwhile en_cours:\n    dt = horloge.tick(60) \/ 1000.0\n\n    for event in pygame.event.get():\n        if event.type == pygame.QUIT:\n            en_cours = False\n        if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:\n            en_cours = False\n\n    touches = pygame.key.get_pressed()\n    dx, dy = 0, 0\n    if touches[pygame.K_LEFT]: dx -= 1\n    if touches[pygame.K_RIGHT]: dx += 1\n    if touches[pygame.K_UP]: dy -= 1\n    if touches[pygame.K_DOWN]: dy += 1\n\n    vx = dx * pacman[\"vitesse\"] * dt\n    vy = dy * pacman[\"vitesse\"] * dt\n    if dx != 0 or dy != 0:\n        pacman[\"direction_aff\"] = (dx, dy)\n\n    nx = pacman[\"x\"] + vx\n    if not collision_mur(rect_pacman(nx, pacman[\"y\"])):\n        pacman[\"x\"] = nx\n    ny = pacman[\"y\"] + vy\n    if not collision_mur(rect_pacman(pacman[\"x\"], ny)):\n        pacman[\"y\"] = ny\n\n    # Collecte\n    case_p = case_depuis_position(pacman[\"x\"], pacman[\"y\"])\n    if case_p in pastilles:\n        pastilles.remove(case_p)\n        score += 1\n\n    # Animation\n    bouge = (dx != 0 or dy != 0)\n    if bouge:\n        pacman[\"temps_anim\"] += dt\n        if pacman[\"temps_anim\"] >= 1.0\/12:\n            pacman[\"temps_anim\"] = 0.0\n            pacman[\"frame\"] = (pacman[\"frame\"] + 1) % len(frames_base)\n    else:\n        pacman[\"frame\"] = 0\n        pacman[\"temps_anim\"] = 0.0\n\n    # Dessin\n    ecran.fill((15, 15, 20))\n    dessiner_labyrinthe()\n    dessiner_pastilles()\n\n    fr = frames_orientees(pacman[\"direction_aff\"])\n    sprite = fr[pacman[\"frame\"]]\n    ecran.blit(sprite, sprite.get_rect(center=(int(pacman[\"x\"]), int(pacman[\"y\"]))))\n\n    ecran.blit(police.render(f\"Score : {score}\", True, (235,235,245)), (18, 14))\n    pygame.display.flip()\n\npygame.quit()\n<\/pre>\n<\/div><\/div>\n<\/div><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"has-black-color has-text-color has-background has-link-color wp-elements-f82cd59ebe2967a9a527cfb68e0eac93 wp-block-paragraph\" style=\"background:linear-gradient(135deg,rgb(216,244,179) 0%,rgb(17,184,81) 100%)\">9) Sons : chomp + victoire<\/p>\n\n\n\n<div class=\"wp-block-esab-accordion esab-sory05m3\" data-mode=\"global\" data-close=\"true\"><div class=\"esab__container\">\n<div class=\"wp-block-esab-accordion-child\"><div class=\"esab__head\" role=\"button\" aria-expanded=\"false\"><div class=\"esab__heading_txt\"><p class=\"esab__heading_tag\">code python 9<\/p><\/div><div class=\"esab__icon\"><div class=\"esab__collapse\"> <svg version=\"1.2\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\"><path fill-rule=\"evenodd\" d=\"m3.5 20.5c-4.7-4.7-4.7-12.3 0-17 4.7-4.7 12.3-4.7 17 0 4.6 4.7 4.6 12.3 0 17-4.7 4.6-12.3 4.6-17 0zm0.9-0.9c4.2 4.2 11 4.2 15.2 0 4.2-4.2 4.2-11 0-15.2-4.2-4.3-11-4.3-15.2 0-4.3 4.2-4.3 11 0 15.2z\"><\/path><path d=\"m11.4 15.9v-3.3h-3.3c-0.3 0-0.6-0.3-0.6-0.6 0-0.4 0.3-0.6 0.6-0.6h3.3v-3.3c0-0.3 0.3-0.6 0.6-0.6 0.3 0 0.6 0.3 0.6 0.6v3.3h3.3c0.3 0 0.6 0.2 0.6 0.6q0 0.2-0.2 0.4-0.2 0.2-0.4 0.2h-3.3v3.3q0 0.2-0.2 0.4-0.2 0.2-0.4 0.2c-0.4 0-0.6-0.3-0.6-0.6z\"><\/path><\/svg> <\/div><div class=\"esab__expand\"> <svg version=\"1.2\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\"><path fill-rule=\"evenodd\" d=\"m12 24c-6.6 0-12-5.4-12-12 0-6.6 5.4-12 12-12 6.6 0 12 5.4 12 12 0 6.6-5.4 12-12 12zm10.6-12c0-5.9-4.7-10.6-10.6-10.6-5.9 0-10.6 4.7-10.6 10.6 0 5.9 4.7 10.6 10.6 10.6 5.9 0 10.6-4.7 10.6-10.6z\"><\/path><path d=\"m5.6 11.3h12.8v1.4h-12.8z\"><\/path><\/svg> <\/div><\/div><\/div><div class=\"esab__body\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"godzilla\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import pygame\nfrom pathlib import Path\n\npygame.init()\ntry:\n    pygame.mixer.init()\nexcept Exception:\n    pass\n\nLABYRINTHE = [\n    \"####################\",\n    \"#P.................#\",\n    \"#.######.#.#####...#\",\n    \"#.#....#.#.....#...#\",\n    \"#.#.##.#.#####.#...#\",\n    \"#...##.#.....#.#...#\",\n    \"###.##.#####.#.###.#\",\n    \"#......#.....#.....#\",\n    \"##################D#\",\n]\n\ngrille = [list(l) for l in LABYRINTHE]\nH = len(grille)\nW = len(grille[0])\n\nLARGEUR, HAUTEUR = 900, 520\necran = pygame.display.set_mode((LARGEUR, HAUTEUR))\npygame.display.set_caption(\"9) Sons : chomp + victoire\")\nhorloge = pygame.time.Clock()\npolice = pygame.font.SysFont(None, 28)\n\nmarge = 30\ntaille_tuile = min((LARGEUR - 2*marge)\/\/W, (HAUTEUR - 2*marge)\/\/H)\ntaille_tuile = max(16, int(taille_tuile))\nox = (LARGEUR - W*taille_tuile)\/\/2\noy = (HAUTEUR - H*taille_tuile)\/\/2\n\ndef rect_tuile(x_case, y_case):\n    return pygame.Rect(ox + x_case*taille_tuile, oy + y_case*taille_tuile, taille_tuile, taille_tuile)\n\nmurs = []\ncase_depart = None\ncase_porte = None\nfor y in range(H):\n    for x in range(W):\n        c = grille[y][x]\n        if c == \"#\":\n            murs.append(rect_tuile(x, y))\n        elif c == \"P\":\n            case_depart = (x, y); grille[y][x] = \".\"\n        elif c == \"D\":\n            case_porte = (x, y); grille[y][x] = \".\"\n\npastilles = set((x,y) for y in range(H) for x in range(W) if grille[y][x]==\".\" and (x,y) not in (case_depart, case_porte))\n\ndossier_assets = Path(\"assets\")\n\ndef charger_son(nom, volume=0.6):\n    try:\n        if pygame.mixer.get_init() and (dossier_assets \/ nom).exists():\n            s = pygame.mixer.Sound(str(dossier_assets \/ nom))\n            s.set_volume(volume)\n            return s\n    except Exception:\n        pass\n    return None\n\nson_chomp = charger_son(\"chomp.wav\", 0.6)\nson_victoire = charger_son(\"win.wav\", 0.8)\n\n# Sprites Pac-Man\nfichiers = [\"pacman_0.png\", \"pacman_1.png\", \"pacman_2.png\"]\nframes_base = []\nfor nom in fichiers:\n    img = pygame.image.load(str(dossier_assets \/ nom)).convert_alpha()\n    img = pygame.transform.smoothscale(img, (int(taille_tuile*0.95), int(taille_tuile*0.95)))\n    frames_base.append(img)\n\ndef frames_orientees(direction):\n    dx, dy = direction\n    if (dx, dy) == (1, 0): return frames_base\n    if (dx, dy) == (-1, 0): return [pygame.transform.flip(f, True, False) for f in frames_base]\n    if (dx, dy) == (0, -1): return [pygame.transform.rotate(f, 90) for f in frames_base]\n    if (dx, dy) == (0, 1): return [pygame.transform.rotate(f, -90) for f in frames_base]\n    return frames_base\n\ndef rect_pacman(px, py):\n    s = int(taille_tuile*0.78)\n    return pygame.Rect(int(px - s\/2), int(py - s\/2), s, s)\n\ndef collision_mur(r):\n    return any(r.colliderect(m) for m in murs)\n\ndef case_depuis_position(px, py):\n    return (int((px - ox)\/\/taille_tuile), int((py - oy)\/\/taille_tuile))\n\npacman = {\n    \"x\": ox + (case_depart[0] + 0.5)*taille_tuile,\n    \"y\": oy + (case_depart[1] + 0.5)*taille_tuile,\n    \"vitesse\": 220.0,\n    \"direction_aff\": (1, 0),\n    \"frame\": 0,\n    \"temps_anim\": 0.0,\n}\nscore = 0\nmessage = \"\"\nvictoire_jouee = False\n\ndef dessiner_labyrinthe():\n    for y in range(H):\n        for x in range(W):\n            r = rect_tuile(x, y)\n            pygame.draw.rect(ecran, (70,70,85) if grille[y][x]==\"#\" else (25,25,32), r)\n    r = rect_tuile(case_porte[0], case_porte[1]).inflate(-10, -10)\n    pygame.draw.rect(ecran, (220,120,60), r, border_radius=10)\n\ndef dessiner_pastilles():\n    rayon = max(2, taille_tuile\/\/8)\n    for (x, y) in pastilles:\n        cx = ox + x*taille_tuile + taille_tuile\/\/2\n        cy = oy + y*taille_tuile + taille_tuile\/\/2\n        pygame.draw.circle(ecran, (240,200,60), (cx, cy), rayon)\n\nen_cours = True\nwhile en_cours:\n    dt = horloge.tick(60) \/ 1000.0\n\n    for event in pygame.event.get():\n        if event.type == pygame.QUIT:\n            en_cours = False\n        if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:\n            en_cours = False\n\n    touches = pygame.key.get_pressed()\n    dx, dy = 0, 0\n    if touches[pygame.K_LEFT]: dx -= 1\n    if touches[pygame.K_RIGHT]: dx += 1\n    if touches[pygame.K_UP]: dy -= 1\n    if touches[pygame.K_DOWN]: dy += 1\n\n    vx = dx * pacman[\"vitesse\"] * dt\n    vy = dy * pacman[\"vitesse\"] * dt\n    if dx != 0 or dy != 0:\n        pacman[\"direction_aff\"] = (dx, dy)\n\n    nx = pacman[\"x\"] + vx\n    if not collision_mur(rect_pacman(nx, pacman[\"y\"])):\n        pacman[\"x\"] = nx\n    ny = pacman[\"y\"] + vy\n    if not collision_mur(rect_pacman(pacman[\"x\"], ny)):\n        pacman[\"y\"] = ny\n\n    case_p = case_depuis_position(pacman[\"x\"], pacman[\"y\"])\n    if case_p in pastilles:\n        pastilles.remove(case_p)\n        score += 1\n        if son_chomp: son_chomp.play()\n\n    if (len(pastilles) == 0) and (not victoire_jouee):\n        victoire_jouee = True\n        message = \"Bravo ! Toutes les pastilles sont mang\u00e9es.\"\n        if son_victoire: son_victoire.play()\n\n    bouge = (dx != 0 or dy != 0)\n    if bouge:\n        pacman[\"temps_anim\"] += dt\n        if pacman[\"temps_anim\"] >= 1.0\/12:\n            pacman[\"temps_anim\"] = 0.0\n            pacman[\"frame\"] = (pacman[\"frame\"] + 1) % len(frames_base)\n    else:\n        pacman[\"frame\"] = 0\n        pacman[\"temps_anim\"] = 0.0\n\n    ecran.fill((15,15,20))\n    dessiner_labyrinthe()\n    dessiner_pastilles()\n\n    fr = frames_orientees(pacman[\"direction_aff\"])\n    sprite = fr[pacman[\"frame\"]]\n    ecran.blit(sprite, sprite.get_rect(center=(int(pacman[\"x\"]), int(pacman[\"y\"]))))\n\n    ecran.blit(police.render(f\"Score : {score}\", True, (235,235,245)), (18,14))\n    if message:\n        ecran.blit(police.render(message, True, (245,245,245)), (18,40))\n\n    pygame.display.flip()\n\npygame.quit()\n<\/pre>\n<\/div><\/div>\n<\/div><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"has-black-color has-text-color has-background has-link-color wp-elements-c891ee9339f1128e1289d0fc6cc29a2d wp-block-paragraph\" style=\"background:linear-gradient(135deg,rgb(216,244,179) 0%,rgb(17,184,81) 100%)\">10) Ennemi + collision<\/p>\n\n\n\n<div class=\"wp-block-esab-accordion esab-2mcajy9w\" data-mode=\"global\" data-close=\"true\"><div class=\"esab__container\">\n<div class=\"wp-block-esab-accordion-child\"><div class=\"esab__head\" role=\"button\" aria-expanded=\"false\"><div class=\"esab__heading_txt\"><p class=\"esab__heading_tag\">code python 10<\/p><\/div><div class=\"esab__icon\"><div class=\"esab__collapse\"> <svg version=\"1.2\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\"><path fill-rule=\"evenodd\" d=\"m3.5 20.5c-4.7-4.7-4.7-12.3 0-17 4.7-4.7 12.3-4.7 17 0 4.6 4.7 4.6 12.3 0 17-4.7 4.6-12.3 4.6-17 0zm0.9-0.9c4.2 4.2 11 4.2 15.2 0 4.2-4.2 4.2-11 0-15.2-4.2-4.3-11-4.3-15.2 0-4.3 4.2-4.3 11 0 15.2z\"><\/path><path d=\"m11.4 15.9v-3.3h-3.3c-0.3 0-0.6-0.3-0.6-0.6 0-0.4 0.3-0.6 0.6-0.6h3.3v-3.3c0-0.3 0.3-0.6 0.6-0.6 0.3 0 0.6 0.3 0.6 0.6v3.3h3.3c0.3 0 0.6 0.2 0.6 0.6q0 0.2-0.2 0.4-0.2 0.2-0.4 0.2h-3.3v3.3q0 0.2-0.2 0.4-0.2 0.2-0.4 0.2c-0.4 0-0.6-0.3-0.6-0.6z\"><\/path><\/svg> <\/div><div class=\"esab__expand\"> <svg version=\"1.2\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\"><path fill-rule=\"evenodd\" d=\"m12 24c-6.6 0-12-5.4-12-12 0-6.6 5.4-12 12-12 6.6 0 12 5.4 12 12 0 6.6-5.4 12-12 12zm10.6-12c0-5.9-4.7-10.6-10.6-10.6-5.9 0-10.6 4.7-10.6 10.6 0 5.9 4.7 10.6 10.6 10.6 5.9 0 10.6-4.7 10.6-10.6z\"><\/path><path d=\"m5.6 11.3h12.8v1.4h-12.8z\"><\/path><\/svg> <\/div><\/div><\/div><div class=\"esab__body\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"godzilla\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import pygame\nimport random\nfrom pathlib import Path\n\npygame.init()\ntry:\n    pygame.mixer.init()\nexcept Exception:\n    pass\n\nLABYRINTHE = [\n    \"####################\",\n    \"#P.......#.........#\",\n    \"#.######.#.#####...#\",\n    \"#.#....#.#.....#...#\",\n    \"#.#.##.#.#####.#...#\",\n    \"#...##.#.....#.#...#\",\n    \"###.##.#####.#.###.#\",\n    \"#......#.....#..E..#\",\n    \"##################D#\",\n]\n\ngrille = [list(l) for l in LABYRINTHE]\nH = len(grille)\nW = len(grille[0])\n\nLARGEUR, HAUTEUR = 900, 520\necran = pygame.display.set_mode((LARGEUR, HAUTEUR))\npygame.display.set_caption(\"10) Ennemi + collision\")\nhorloge = pygame.time.Clock()\npolice = pygame.font.SysFont(None, 28)\n\nmarge = 30\ntaille_tuile = min((LARGEUR - 2*marge)\/\/W, (HAUTEUR - 2*marge)\/\/H)\ntaille_tuile = max(16, int(taille_tuile))\nox = (LARGEUR - W*taille_tuile)\/\/2\noy = (HAUTEUR - H*taille_tuile)\/\/2\n\ndef rect_tuile(x_case, y_case):\n    return pygame.Rect(ox + x_case*taille_tuile, oy + y_case*taille_tuile, taille_tuile, taille_tuile)\n\ndef centre_case(x_case, y_case):\n    return (ox + (x_case + 0.5)*taille_tuile, oy + (y_case + 0.5)*taille_tuile)\n\n# Parse\nmurs = []\ncase_depart = None\ncase_porte = None\ncase_ennemi = None\nfor y in range(H):\n    for x in range(W):\n        c = grille[y][x]\n        if c == \"#\":\n            murs.append(rect_tuile(x, y))\n        elif c == \"P\":\n            case_depart = (x, y); grille[y][x] = \".\"\n        elif c == \"D\":\n            case_porte = (x, y); grille[y][x] = \".\"\n        elif c == \"E\":\n            case_ennemi = (x, y); grille[y][x] = \".\"\n\ndef est_mur_case(x, y):\n    return grille[y][x] == \"#\"\n\npastilles = set((x,y) for y in range(H) for x in range(W) if grille[y][x]==\".\" and (x,y) not in (case_depart, case_porte))\n\n# Sons\ndossier_assets = Path(\"assets\")\ndef charger_son(nom, volume=0.6):\n    try:\n        if pygame.mixer.get_init() and (dossier_assets \/ nom).exists():\n            s = pygame.mixer.Sound(str(dossier_assets \/ nom))\n            s.set_volume(volume)\n            return s\n    except Exception:\n        pass\n    return None\n\nson_chomp = charger_son(\"chomp.wav\", 0.6)\nson_mort = charger_son(\"death.wav\", 0.7)\n\n# Pac-Man sprites\nfichiers = [\"pacman_0.png\", \"pacman_1.png\", \"pacman_2.png\"]\nframes_base = []\nfor nom in fichiers:\n    img = pygame.image.load(str(dossier_assets \/ nom)).convert_alpha()\n    img = pygame.transform.smoothscale(img, (int(taille_tuile*0.95), int(taille_tuile*0.95)))\n    frames_base.append(img)\n\ndef frames_orientees(direction):\n    dx, dy = direction\n    if (dx, dy) == (1, 0): return frames_base\n    if (dx, dy) == (-1, 0): return [pygame.transform.flip(f, True, False) for f in frames_base]\n    if (dx, dy) == (0, -1): return [pygame.transform.rotate(f, 90) for f in frames_base]\n    if (dx, dy) == (0, 1): return [pygame.transform.rotate(f, -90) for f in frames_base]\n    return frames_base\n\ndef rect_pacman(px, py):\n    s = int(taille_tuile*0.78)\n    return pygame.Rect(int(px - s\/2), int(py - s\/2), s, s)\n\ndef collision_mur(r):\n    return any(r.colliderect(m) for m in murs)\n\ndef case_depuis_position(px, py):\n    return (int((px - ox)\/\/taille_tuile), int((py - oy)\/\/taille_tuile))\n\n# Pac-Man\npx0, py0 = centre_case(*case_depart)\npacman = {\"x\": px0, \"y\": py0, \"vitesse\": 220.0, \"direction_aff\": (1,0), \"frame\": 0, \"temps_anim\": 0.0}\nscore = 0\n\n# Ennemi (d\u00e9placement sur la grille)\nDIRECTIONS = [(1,0), (-1,0), (0,1), (0,-1)]\nOPPOSE = {(1,0):(-1,0), (-1,0):(1,0), (0,1):(0,-1), (0,-1):(0,1)}\nennemi = {\"case\": case_ennemi, \"direction\": random.choice(DIRECTIONS), \"progression\": 0.0, \"vitesse_cases\": 4.5}\n\ndef direction_possible(case, direction):\n    x, y = case\n    dx, dy = direction\n    nx, ny = x + dx, y + dy\n    if nx &lt; 0 or nx >= W or ny &lt; 0 or ny >= H:\n        return False\n    return not est_mur_case(nx, ny)\n\ndef mettre_a_jour_ennemi(dt):\n    distance = ennemi[\"vitesse_cases\"] * dt\n    eps = 1e-6\n    while distance > 0:\n        if ennemi[\"progression\"] &lt;= eps:\n            if not direction_possible(ennemi[\"case\"], ennemi[\"direction\"]):\n                choix = DIRECTIONS[:]\n                random.shuffle(choix)\n                opp = OPPOSE.get(ennemi[\"direction\"])\n                if opp in choix:\n                    choix.remove(opp)\n                    choix.append(opp)\n                for d in choix:\n                    if direction_possible(ennemi[\"case\"], d):\n                        ennemi[\"direction\"] = d\n                        break\n        restant = 1.0 - ennemi[\"progression\"]\n        pas = min(distance, restant)\n        ennemi[\"progression\"] += pas\n        distance -= pas\n        if ennemi[\"progression\"] >= 1.0 - eps:\n            x, y = ennemi[\"case\"]\n            dx, dy = ennemi[\"direction\"]\n            ennemi[\"case\"] = (x+dx, y+dy)\n            ennemi[\"progression\"] = 0.0\n\ndef position_ennemi_pixels():\n    x, y = ennemi[\"case\"]\n    dx, dy = ennemi[\"direction\"]\n    p = ennemi[\"progression\"]\n    return (ox + (x + 0.5 + dx*p)*taille_tuile, oy + (y + 0.5 + dy*p)*taille_tuile)\n\ndef dessiner_labyrinthe():\n    for y in range(H):\n        for x in range(W):\n            r = rect_tuile(x, y)\n            pygame.draw.rect(ecran, (70,70,85) if grille[y][x]==\"#\" else (25,25,32), r)\n    r = rect_tuile(case_porte[0], case_porte[1]).inflate(-10, -10)\n    pygame.draw.rect(ecran, (220,120,60), r, border_radius=10)\n\ndef dessiner_pastilles():\n    rayon = max(2, taille_tuile\/\/8)\n    for (x, y) in pastilles:\n        cx = ox + x*taille_tuile + taille_tuile\/\/2\n        cy = oy + y*taille_tuile + taille_tuile\/\/2\n        pygame.draw.circle(ecran, (240,200,60), (cx, cy), rayon)\n\netat = \"jeu\"\nmessage = \"\"\n\nen_cours = True\nwhile en_cours:\n    dt = horloge.tick(60) \/ 1000.0\n\n    for event in pygame.event.get():\n        if event.type == pygame.QUIT:\n            en_cours = False\n        if event.type == pygame.KEYDOWN:\n            if event.key == pygame.K_ESCAPE:\n                en_cours = False\n            if event.key == pygame.K_r and etat != \"jeu\":\n                # reset\n                px0, py0 = centre_case(*case_depart)\n                pacman.update({\"x\": px0, \"y\": py0, \"direction_aff\": (1,0), \"frame\": 0, \"temps_anim\": 0.0})\n                score = 0\n                pastilles = set((x,y) for y in range(H) for x in range(W) if grille[y][x]==\".\" and (x,y) not in (case_depart, case_porte))\n                ennemi.update({\"case\": case_ennemi, \"direction\": random.choice(DIRECTIONS), \"progression\": 0.0})\n                etat = \"jeu\"\n                message = \"\"\n\n    if etat == \"jeu\":\n        touches = pygame.key.get_pressed()\n        dx, dy = 0, 0\n        if touches[pygame.K_LEFT]: dx -= 1\n        if touches[pygame.K_RIGHT]: dx += 1\n        if touches[pygame.K_UP]: dy -= 1\n        if touches[pygame.K_DOWN]: dy += 1\n\n        vx = dx * pacman[\"vitesse\"] * dt\n        vy = dy * pacman[\"vitesse\"] * dt\n        if dx != 0 or dy != 0:\n            pacman[\"direction_aff\"] = (dx, dy)\n\n        nx = pacman[\"x\"] + vx\n        if not collision_mur(rect_pacman(nx, pacman[\"y\"])):\n            pacman[\"x\"] = nx\n        ny = pacman[\"y\"] + vy\n        if not collision_mur(rect_pacman(pacman[\"x\"], ny)):\n            pacman[\"y\"] = ny\n\n        case_p = case_depuis_position(pacman[\"x\"], pacman[\"y\"])\n        if case_p in pastilles:\n            pastilles.remove(case_p)\n            score += 1\n            if son_chomp: son_chomp.play()\n\n        bouge = (dx != 0 or dy != 0)\n        if bouge:\n            pacman[\"temps_anim\"] += dt\n            if pacman[\"temps_anim\"] >= 1.0\/12:\n                pacman[\"temps_anim\"] = 0.0\n                pacman[\"frame\"] = (pacman[\"frame\"] + 1) % len(frames_base)\n        else:\n            pacman[\"frame\"] = 0\n            pacman[\"temps_anim\"] = 0.0\n\n        # Ennemi + collision\n        mettre_a_jour_ennemi(dt)\n        ex, ey = position_ennemi_pixels()\n        dxp = pacman[\"x\"] - ex\n        dyp = pacman[\"y\"] - ey\n        if (dxp*dxp + dyp*dyp) &lt; (0.45*taille_tuile)**2:\n            etat = \"perdu\"\n            message = \"Perdu ! (ennemi) \u2014 R pour recommencer\"\n            if son_mort: son_mort.play()\n\n    # Dessin\n    ecran.fill((15,15,20))\n    dessiner_labyrinthe()\n    dessiner_pastilles()\n\n    ex, ey = position_ennemi_pixels()\n    pygame.draw.circle(ecran, (220,60,60), (int(ex), int(ey)), max(5, taille_tuile\/\/3))\n\n    fr = frames_orientees(pacman[\"direction_aff\"])\n    sprite = fr[pacman[\"frame\"]]\n    ecran.blit(sprite, sprite.get_rect(center=(int(pacman[\"x\"]), int(pacman[\"y\"]))))\n\n    ecran.blit(police.render(f\"Score : {score}\", True, (235,235,245)), (18,14))\n    if message:\n        ecran.blit(police.render(message, True, (245,245,245)), (18,40))\n\n    pygame.display.flip()\n\npygame.quit()\n<\/pre>\n<\/div><\/div>\n<\/div><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"has-black-color has-text-color has-background has-link-color wp-elements-57635ab970fa8551ab4dcefd09e1ff18 wp-block-paragraph\" style=\"background:linear-gradient(135deg,rgb(216,244,179) 0%,rgb(17,184,81) 100%)\">11) Cl\u00e9 + porte + victoire (avec sons)<\/p>\n\n\n\n<div class=\"wp-block-esab-accordion esab-2b2wb9cj\" data-mode=\"global\" data-close=\"true\"><div class=\"esab__container\">\n<div class=\"wp-block-esab-accordion-child\"><div class=\"esab__head\" role=\"button\" aria-expanded=\"false\"><div class=\"esab__heading_txt\"><p class=\"esab__heading_tag\">code python 11<\/p><\/div><div class=\"esab__icon\"><div class=\"esab__collapse\"> <svg version=\"1.2\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\"><path fill-rule=\"evenodd\" d=\"m3.5 20.5c-4.7-4.7-4.7-12.3 0-17 4.7-4.7 12.3-4.7 17 0 4.6 4.7 4.6 12.3 0 17-4.7 4.6-12.3 4.6-17 0zm0.9-0.9c4.2 4.2 11 4.2 15.2 0 4.2-4.2 4.2-11 0-15.2-4.2-4.3-11-4.3-15.2 0-4.3 4.2-4.3 11 0 15.2z\"><\/path><path d=\"m11.4 15.9v-3.3h-3.3c-0.3 0-0.6-0.3-0.6-0.6 0-0.4 0.3-0.6 0.6-0.6h3.3v-3.3c0-0.3 0.3-0.6 0.6-0.6 0.3 0 0.6 0.3 0.6 0.6v3.3h3.3c0.3 0 0.6 0.2 0.6 0.6q0 0.2-0.2 0.4-0.2 0.2-0.4 0.2h-3.3v3.3q0 0.2-0.2 0.4-0.2 0.2-0.4 0.2c-0.4 0-0.6-0.3-0.6-0.6z\"><\/path><\/svg> <\/div><div class=\"esab__expand\"> <svg version=\"1.2\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\"><path fill-rule=\"evenodd\" d=\"m12 24c-6.6 0-12-5.4-12-12 0-6.6 5.4-12 12-12 6.6 0 12 5.4 12 12 0 6.6-5.4 12-12 12zm10.6-12c0-5.9-4.7-10.6-10.6-10.6-5.9 0-10.6 4.7-10.6 10.6 0 5.9 4.7 10.6 10.6 10.6 5.9 0 10.6-4.7 10.6-10.6z\"><\/path><path d=\"m5.6 11.3h12.8v1.4h-12.8z\"><\/path><\/svg> <\/div><\/div><\/div><div class=\"esab__body\">\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"godzilla\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import pygame\nimport random\nfrom pathlib import Path\n\npygame.init()\ntry:\n    pygame.mixer.init()\nexcept Exception:\n    pass\n\nLABYRINTHE = [\n    \"####################\",\n    \"#P.......#.....K...#\",\n    \"#.######.#.#####...#\",\n    \"#.#....#.#.....#...#\",\n    \"#.#.##.#.#####.#...#\",\n    \"#...##.#.....#.#...#\",\n    \"###.##.#####.#.###.#\",\n    \"#......#.....#..E..#\",\n    \"##################D#\",\n]\n\ngrille = [list(l) for l in LABYRINTHE]\nH = len(grille)\nW = len(grille[0])\n\nLARGEUR, HAUTEUR = 900, 520\necran = pygame.display.set_mode((LARGEUR, HAUTEUR))\npygame.display.set_caption(\"12) Jeu complet Pac-Man (1 niveau)\")\nhorloge = pygame.time.Clock()\npolice = pygame.font.SysFont(None, 28)\n\nmarge = 30\ntaille_tuile = min((LARGEUR - 2*marge)\/\/W, (HAUTEUR - 2*marge)\/\/H)\ntaille_tuile = max(16, int(taille_tuile))\nox = (LARGEUR - W*taille_tuile)\/\/2\noy = (HAUTEUR - H*taille_tuile)\/\/2\n\ndef rect_tuile(x_case, y_case):\n    return pygame.Rect(ox + x_case*taille_tuile, oy + y_case*taille_tuile, taille_tuile, taille_tuile)\n\ndef centre_case(x_case, y_case):\n    return (ox + (x_case + 0.5)*taille_tuile, oy + (y_case + 0.5)*taille_tuile)\n\n# Parse\nmurs = []\ncase_depart = None\ncase_porte = None\ncase_ennemi = None\ncase_cle = None\nfor y in range(H):\n    for x in range(W):\n        c = grille[y][x]\n        if c == \"#\":\n            murs.append(rect_tuile(x, y))\n        elif c == \"P\":\n            case_depart = (x, y); grille[y][x] = \".\"\n        elif c == \"D\":\n            case_porte = (x, y); grille[y][x] = \".\"\n        elif c == \"E\":\n            case_ennemi = (x, y); grille[y][x] = \".\"\n        elif c == \"K\":\n            case_cle = (x, y); grille[y][x] = \".\"\n\ndef est_mur_case(x, y):\n    return grille[y][x] == \"#\"\n\ndef creer_pastilles():\n    return set((x,y) for y in range(H) for x in range(W) if grille[y][x]==\".\" and (x,y) not in (case_depart, case_porte, case_cle))\n\n# Sons + musique\ndossier_assets = Path(\"assets\")\n\ndef charger_son(nom, volume=0.6):\n    try:\n        if pygame.mixer.get_init() and (dossier_assets \/ nom).exists():\n            s = pygame.mixer.Sound(str(dossier_assets \/ nom))\n            s.set_volume(volume)\n            return s\n    except Exception:\n        pass\n    return None\n\nson_chomp = charger_son(\"chomp.wav\", 0.6)\nson_cle = charger_son(\"key.wav\", 0.7)\nson_porte = charger_son(\"door.wav\", 0.7)\nson_mort = charger_son(\"death.wav\", 0.7)\nson_victoire = charger_son(\"win.wav\", 0.8)\n\nmusique = dossier_assets \/ \"music.ogg\"\nif pygame.mixer.get_init() and musique.exists():\n    try:\n        pygame.mixer.music.load(str(musique))\n        pygame.mixer.music.set_volume(0.25)\n        pygame.mixer.music.play(-1)\n    except Exception:\n        pass\n\n# Sprites Pac-Man\nfichiers = [\"pacman_0.png\", \"pacman_1.png\", \"pacman_2.png\"]\nframes_base = []\nfor nom in fichiers:\n    img = pygame.image.load(str(dossier_assets \/ nom)).convert_alpha()\n    img = pygame.transform.smoothscale(img, (int(taille_tuile*0.95), int(taille_tuile*0.95)))\n    frames_base.append(img)\n\ndef frames_orientees(direction):\n    dx, dy = direction\n    if (dx, dy) == (1, 0): return frames_base\n    if (dx, dy) == (-1, 0): return [pygame.transform.flip(f, True, False) for f in frames_base]\n    if (dx, dy) == (0, -1): return [pygame.transform.rotate(f, 90) for f in frames_base]\n    if (dx, dy) == (0, 1): return [pygame.transform.rotate(f, -90) for f in frames_base]\n    return frames_base\n\ndef rect_pacman(px, py):\n    s = int(taille_tuile*0.78)\n    return pygame.Rect(int(px - s\/2), int(py - s\/2), s, s)\n\ndef collision_mur(r):\n    return any(r.colliderect(m) for m in murs)\n\ndef case_depuis_position(px, py):\n    return (int((px - ox)\/\/taille_tuile), int((py - oy)\/\/taille_tuile))\n\n# Ennemi (grid)\nDIRECTIONS = [(1,0), (-1,0), (0,1), (0,-1)]\nOPPOSE = {(1,0):(-1,0), (-1,0):(1,0), (0,1):(0,-1), (0,-1):(0,1)}\n\ndef direction_possible(case, direction):\n    x, y = case\n    dx, dy = direction\n    nx, ny = x + dx, y + dy\n    if nx &lt; 0 or nx >= W or ny &lt; 0 or ny >= H:\n        return False\n    return not est_mur_case(nx, ny)\n\ndef mettre_a_jour_ennemi(ennemi, dt):\n    distance = ennemi[\"vitesse_cases\"] * dt\n    eps = 1e-6\n    while distance > 0:\n        if ennemi[\"progression\"] &lt;= eps:\n            if not direction_possible(ennemi[\"case\"], ennemi[\"direction\"]):\n                choix = DIRECTIONS[:]\n                random.shuffle(choix)\n                opp = OPPOSE.get(ennemi[\"direction\"])\n                if opp in choix:\n                    choix.remove(opp); choix.append(opp)\n                for d in choix:\n                    if direction_possible(ennemi[\"case\"], d):\n                        ennemi[\"direction\"] = d\n                        break\n        restant = 1.0 - ennemi[\"progression\"]\n        pas = min(distance, restant)\n        ennemi[\"progression\"] += pas\n        distance -= pas\n        if ennemi[\"progression\"] >= 1.0 - eps:\n            x, y = ennemi[\"case\"]\n            dx, dy = ennemi[\"direction\"]\n            ennemi[\"case\"] = (x+dx, y+dy)\n            ennemi[\"progression\"] = 0.0\n\ndef position_ennemi_pixels(ennemi):\n    x, y = ennemi[\"case\"]\n    dx, dy = ennemi[\"direction\"]\n    p = ennemi[\"progression\"]\n    return (ox + (x + 0.5 + dx*p)*taille_tuile, oy + (y + 0.5 + dy*p)*taille_tuile)\n\ndef dessiner_labyrinthe(porte_ouverte):\n    for y in range(H):\n        for x in range(W):\n            r = rect_tuile(x, y)\n            pygame.draw.rect(ecran, (70,70,85) if grille[y][x]==\"#\" else (25,25,32), r)\n    r = rect_tuile(case_porte[0], case_porte[1]).inflate(-10, -10)\n    couleur = (80,220,140) if porte_ouverte else (220,120,60)\n    pygame.draw.rect(ecran, couleur, r, border_radius=10)\n\ndef dessiner_pastilles(pastilles):\n    rayon = max(2, taille_tuile\/\/8)\n    for (x, y) in pastilles:\n        cx = ox + x*taille_tuile + taille_tuile\/\/2\n        cy = oy + y*taille_tuile + taille_tuile\/\/2\n        pygame.draw.circle(ecran, (240,200,60), (cx, cy), rayon)\n\ndef dessiner_cle(inventaire):\n    if inventaire[\"cle\"] == 0:\n        cx = ox + case_cle[0]*taille_tuile + taille_tuile\/\/2\n        cy = oy + case_cle[1]*taille_tuile + taille_tuile\/\/2\n        pygame.draw.rect(ecran, (80,220,140), pygame.Rect(cx-6, cy-6, 12, 12), border_radius=3)\n\ndef reinitialiser():\n    px0, py0 = centre_case(*case_depart)\n    pac = {\"x\": px0, \"y\": py0, \"vitesse\": 220.0, \"direction_aff\": (1,0), \"frame\": 0, \"temps_anim\": 0.0}\n    inv = {\"cle\": 0}\n    pts = creer_pastilles()\n    sc = 0\n    ene = {\"case\": case_ennemi, \"direction\": random.choice(DIRECTIONS), \"progression\": 0.0, \"vitesse_cases\": 4.5}\n    return pac, inv, pts, sc, ene\n\npacman, inventaire, pastilles, score, ennemi = reinitialiser()\netat = \"jeu\"\nmessage = \"\"\n\nen_cours = True\nwhile en_cours:\n    dt = horloge.tick(60) \/ 1000.0\n\n    for event in pygame.event.get():\n        if event.type == pygame.QUIT:\n            en_cours = False\n        if event.type == pygame.KEYDOWN:\n            if event.key == pygame.K_ESCAPE:\n                en_cours = False\n            if event.key == pygame.K_r and etat != \"jeu\":\n                pacman, inventaire, pastilles, score, ennemi = reinitialiser()\n                etat = \"jeu\"\n                message = \"\"\n\n    porte_ouverte = (inventaire[\"cle\"] > 0) and (len(pastilles) == 0)\n\n    if etat == \"jeu\":\n        touches = pygame.key.get_pressed()\n        dx, dy = 0, 0\n        if touches[pygame.K_LEFT]: dx -= 1\n        if touches[pygame.K_RIGHT]: dx += 1\n        if touches[pygame.K_UP]: dy -= 1\n        if touches[pygame.K_DOWN]: dy += 1\n\n        vx = dx * pacman[\"vitesse\"] * dt\n        vy = dy * pacman[\"vitesse\"] * dt\n        if dx != 0 or dy != 0:\n            pacman[\"direction_aff\"] = (dx, dy)\n\n        nx = pacman[\"x\"] + vx\n        if not collision_mur(rect_pacman(nx, pacman[\"y\"])):\n            pacman[\"x\"] = nx\n        ny = pacman[\"y\"] + vy\n        if not collision_mur(rect_pacman(pacman[\"x\"], ny)):\n            pacman[\"y\"] = ny\n\n        case_p = case_depuis_position(pacman[\"x\"], pacman[\"y\"])\n\n        if case_p in pastilles:\n            pastilles.remove(case_p)\n            score += 1\n            if son_chomp: son_chomp.play()\n\n        if inventaire[\"cle\"] == 0 and case_p == case_cle:\n            inventaire[\"cle\"] = 1\n            if son_cle: son_cle.play()\n\n        porte_ouverte = (inventaire[\"cle\"] > 0) and (len(pastilles) == 0)\n        if porte_ouverte and case_p == case_porte:\n            etat = \"gagne\"\n            message = \"Victoire ! Appuie sur R pour rejouer\"\n            if son_porte: son_porte.play()\n            if son_victoire: son_victoire.play()\n\n        # Animation\n        bouge = (dx != 0 or dy != 0)\n        if bouge:\n            pacman[\"temps_anim\"] += dt\n            if pacman[\"temps_anim\"] >= 1.0\/12:\n                pacman[\"temps_anim\"] = 0.0\n                pacman[\"frame\"] = (pacman[\"frame\"] + 1) % len(frames_base)\n        else:\n            pacman[\"frame\"] = 0\n            pacman[\"temps_anim\"] = 0.0\n\n        # Ennemi + collision\n        mettre_a_jour_ennemi(ennemi, dt)\n        ex, ey = position_ennemi_pixels(ennemi)\n        dxp = pacman[\"x\"] - ex\n        dyp = pacman[\"y\"] - ey\n        if (dxp*dxp + dyp*dyp) &lt; (0.45*taille_tuile)**2:\n            etat = \"perdu\"\n            message = \"Perdu ! Appuie sur R pour recommencer\"\n            if son_mort: son_mort.play()\n\n    # Dessin\n    ecran.fill((15,15,20))\n    dessiner_labyrinthe(porte_ouverte)\n    dessiner_pastilles(pastilles)\n    dessiner_cle(inventaire)\n\n    ex, ey = position_ennemi_pixels(ennemi)\n    pygame.draw.circle(ecran, (220,60,60), (int(ex), int(ey)), max(5, taille_tuile\/\/3))\n\n    fr = frames_orientees(pacman[\"direction_aff\"])\n    sprite = fr[pacman[\"frame\"]]\n    ecran.blit(sprite, sprite.get_rect(center=(int(pacman[\"x\"]), int(pacman[\"y\"]))))\n\n    hud = f\"Score : {score}   Cl\u00e9 : {inventaire['cle']}   Pastilles : {len(pastilles)}\"\n    ecran.blit(police.render(hud, True, (235,235,245)), (18,14))\n    if message:\n        ecran.blit(police.render(message, True, (245,245,245)), (18,40))\n\n    pygame.display.flip()\n\npygame.quit()\n<\/pre>\n<\/div><\/div>\n<\/div><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"has-black-color has-text-color has-background has-link-color wp-elements-88832cae355fb3f31bedcee72aed58f1 wp-block-paragraph\" style=\"background:linear-gradient(135deg,rgb(216,244,179) 0%,rgb(17,184,81) 100%)\">12) Jeu complet + musique (optionnelle)<\/p>\n\n\n\n<div class=\"wp-block-esab-accordion esab-gxvvcgad\" data-mode=\"global\" data-close=\"true\"><div class=\"esab__container\">\n<div class=\"wp-block-esab-accordion-child\"><div class=\"esab__head\" role=\"button\" aria-expanded=\"false\"><div class=\"esab__heading_txt\"><p class=\"esab__heading_tag\">code python 12<\/p><\/div><div class=\"esab__icon\"><div class=\"esab__collapse\"> <svg version=\"1.2\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\"><path fill-rule=\"evenodd\" d=\"m3.5 20.5c-4.7-4.7-4.7-12.3 0-17 4.7-4.7 12.3-4.7 17 0 4.6 4.7 4.6 12.3 0 17-4.7 4.6-12.3 4.6-17 0zm0.9-0.9c4.2 4.2 11 4.2 15.2 0 4.2-4.2 4.2-11 0-15.2-4.2-4.3-11-4.3-15.2 0-4.3 4.2-4.3 11 0 15.2z\"><\/path><path d=\"m11.4 15.9v-3.3h-3.3c-0.3 0-0.6-0.3-0.6-0.6 0-0.4 0.3-0.6 0.6-0.6h3.3v-3.3c0-0.3 0.3-0.6 0.6-0.6 0.3 0 0.6 0.3 0.6 0.6v3.3h3.3c0.3 0 0.6 0.2 0.6 0.6q0 0.2-0.2 0.4-0.2 0.2-0.4 0.2h-3.3v3.3q0 0.2-0.2 0.4-0.2 0.2-0.4 0.2c-0.4 0-0.6-0.3-0.6-0.6z\"><\/path><\/svg> <\/div><div class=\"esab__expand\"> <svg version=\"1.2\" viewBox=\"0 0 24 24\" width=\"24\" height=\"24\"><path fill-rule=\"evenodd\" d=\"m12 24c-6.6 0-12-5.4-12-12 0-6.6 5.4-12 12-12 6.6 0 12 5.4 12 12 0 6.6-5.4 12-12 12zm10.6-12c0-5.9-4.7-10.6-10.6-10.6-5.9 0-10.6 4.7-10.6 10.6 0 5.9 4.7 10.6 10.6 10.6 5.9 0 10.6-4.7 10.6-10.6z\"><\/path><path d=\"m5.6 11.3h12.8v1.4h-12.8z\"><\/path><\/svg> <\/div><\/div><\/div><div class=\"esab__body\">\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"godzilla\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import pygame\nimport random\nfrom pathlib import Path\n\n# ============================================================\n# 1) INITIALISATION DE PYGAME\n# ============================================================\n\npygame.init()\ntry:\n    pygame.mixer.init()  # audio (peut \u00e9chouer sur certaines machines)\nexcept Exception:\n    pass\n\n# ============================================================\n# 2) DESCRIPTION DU NIVEAU (LABYRINTHE)\n#    # : mur\n#    . : sol (o\u00f9 on peut marcher)\n#    P : position de d\u00e9part du joueur\n#    K : cl\u00e9\n#    E : ennemi\n#    D : porte de sortie\n#\n# CORRECTION DU BUG \"LABYRINTHE FERM\u00c9\"\n# - Dans la version d'origine, le labyrinthe \u00e9tait s\u00e9par\u00e9 en 2 zones non connect\u00e9es :\n#   Pac-Man d\u00e9marrait dans une zone, mais la cl\u00e9 + la porte \u00e9taient dans l'autre,\n#   donc impossible de gagner.\n# - Ici, on a cr\u00e9\u00e9 un passage en rempla\u00e7ant un seul '#' par '.' (ligne 4).\n# ============================================================\n\nLABYRINTHE = [\n    \"####################\",\n    \"#P.......#.....K...#\",\n    \"#.######.#.#####...#\",\n    \"#.#....#.......#...#\",  # &lt;-- ouverture (\u00e0 la place du # en colonne 10)\n    \"#.#.##.#.#####.#...#\",\n    \"#...##.#.....#.#...#\",\n    \"###.##.#####.#.###.#\",\n    \"#......#.....#..E..#\",\n    \"##################D#\",\n]\n\n# On transforme chaque ligne (str) en liste de caract\u00e8res modifiables\ngrille = [list(ligne) for ligne in LABYRINTHE]\nH = len(grille)       # hauteur en cases\nW = len(grille[0])    # largeur en cases\n\n# ============================================================\n# 3) FEN\u00caTRE \/ AFFICHAGE\n# ============================================================\n\nLARGEUR, HAUTEUR = 900, 520\necran = pygame.display.set_mode((LARGEUR, HAUTEUR))\npygame.display.set_caption(\"12) Jeu complet Pac-Man (1 niveau)\")\nhorloge = pygame.time.Clock()\npolice = pygame.font.SysFont(None, 28)\n\n# Marges et taille des tuiles (cases) en pixels\nmarge = 30\ntaille_tuile = min((LARGEUR - 2 * marge) \/\/ W, (HAUTEUR - 2 * marge) \/\/ H)\ntaille_tuile = max(16, int(taille_tuile))  # s\u00e9curit\u00e9 : jamais trop petit\n\n# D\u00e9calage pour centrer le labyrinthe dans la fen\u00eatre\nox = (LARGEUR - W * taille_tuile) \/\/ 2\noy = (HAUTEUR - H * taille_tuile) \/\/ 2\n\ndef rect_tuile(x_case: int, y_case: int) -> pygame.Rect:\n    \"\"\"Rectangle en pixels correspondant \u00e0 la case (x_case, y_case).\"\"\"\n    return pygame.Rect(\n        ox + x_case * taille_tuile,\n        oy + y_case * taille_tuile,\n        taille_tuile,\n        taille_tuile\n    )\n\ndef centre_case(x_case: int, y_case: int) -> tuple[float, float]:\n    \"\"\"Coordonn\u00e9es (pixels) du centre de la case (x_case, y_case).\"\"\"\n    return (\n        ox + (x_case + 0.5) * taille_tuile,\n        oy + (y_case + 0.5) * taille_tuile\n    )\n\n# ============================================================\n# 4) PARSING DU LABYRINTHE : on rep\u00e8re murs, d\u00e9part, porte, ennemi, cl\u00e9\n# ============================================================\n\nmurs: list[pygame.Rect] = []\ncase_depart = None\ncase_porte = None\ncase_ennemi = None\ncase_cle = None\n\nfor y in range(H):\n    for x in range(W):\n        c = grille[y][x]\n        if c == \"#\":\n            murs.append(rect_tuile(x, y))  # mur : on stocke son rectangle pour les collisions\n        elif c == \"P\":\n            case_depart = (x, y)\n            grille[y][x] = \".\"  # on remet du sol \u00e0 la place de 'P'\n        elif c == \"D\":\n            case_porte = (x, y)\n            grille[y][x] = \".\"\n        elif c == \"E\":\n            case_ennemi = (x, y)\n            grille[y][x] = \".\"\n        elif c == \"K\":\n            case_cle = (x, y)\n            grille[y][x] = \".\"\n\ndef est_mur_case(x: int, y: int) -> bool:\n    \"\"\"Vrai si la case (x, y) est un mur.\"\"\"\n    return grille[y][x] == \"#\"\n\n# ============================================================\n# 5) PASTILLES (PI\u00c8CES) \u00c0 RAMASSER\n#\n# CORRECTION \"TROP DE PI\u00c8CES\"\n# - Avant : une pastille sur TOUTES les cases '.' (donc \u00e9norm\u00e9ment).\n# - Maintenant : on met une pastille sur ~1 case sur 2 en damier (moins long,\n#   mais on conserve l'id\u00e9e d'exploration).\n#\n# IMPORTANT : on ne met des pastilles que sur les cases r\u00e9ellement accessibles\n# depuis le d\u00e9part, pour \u00e9viter une situation o\u00f9 il resterait des pastilles\n# dans une zone isol\u00e9e (ce qui bloquerait la victoire).\n# ============================================================\n\nDIRECTIONS = [(1, 0), (-1, 0), (0, 1), (0, -1)]\n\ndef cases_accessibles_depuis(depart: tuple[int, int]) -> set[tuple[int, int]]:\n    \"\"\"Retourne l'ensemble des cases atteignables depuis 'depart' (BFS).\"\"\"\n    a_visiter = [depart]\n    vues = {depart}\n    while a_visiter:\n        x, y = a_visiter.pop(0)\n        for dx, dy in DIRECTIONS:\n            nx, ny = x + dx, y + dy\n            if 0 &lt;= nx &lt; W and 0 &lt;= ny &lt; H and not est_mur_case(nx, ny):\n                if (nx, ny) not in vues:\n                    vues.add((nx, ny))\n                    a_visiter.append((nx, ny))\n    return vues\n\ndef creer_pastilles() -> set[tuple[int, int]]:\n    \"\"\"Cr\u00e9e l'ensemble des positions de pastilles \u00e0 ramasser.\"\"\"\n    accessibles = cases_accessibles_depuis(case_depart)\n\n    pastilles = set()\n    for y in range(H):\n        for x in range(W):\n            # Une pastille peut exister uniquement sur du sol ('.')\n            if grille[y][x] != \".\":\n                continue\n\n            # On \u00e9vite les cases sp\u00e9ciales\n            if (x, y) in (case_depart, case_porte, case_cle):\n                continue\n\n            # S\u00e9curit\u00e9 : uniquement dans la zone atteignable\n            if (x, y) not in accessibles:\n                continue\n\n            # R\u00e9duction : \"damier\" => environ 50% des cases seulement\n            if (x + y) % 2 == 0:\n                pastilles.add((x, y))\n\n    return pastilles\n\n# ============================================================\n# 6) SONS + MUSIQUE\n# ============================================================\n\ndossier_assets = Path(\"assets\")\n\ndef charger_son(nom: str, volume: float = 0.6):\n    \"\"\"Charge un son si possible, sinon renvoie None.\"\"\"\n    try:\n        if pygame.mixer.get_init() and (dossier_assets \/ nom).exists():\n            s = pygame.mixer.Sound(str(dossier_assets \/ nom))\n            s.set_volume(volume)\n            return s\n    except Exception:\n        pass\n    return None\n\nson_chomp = charger_son(\"chomp.wav\", 0.6)\nson_cle = charger_son(\"key.wav\", 0.7)\nson_porte = charger_son(\"door.wav\", 0.7)\nson_mort = charger_son(\"death.wav\", 0.7)\nson_victoire = charger_son(\"win.wav\", 0.8)\n\nmusique = dossier_assets \/ \"music.ogg\"\nif pygame.mixer.get_init() and musique.exists():\n    try:\n        pygame.mixer.music.load(str(musique))\n        pygame.mixer.music.set_volume(0.25)\n        pygame.mixer.music.play(-1)  # boucle infinie\n    except Exception:\n        pass\n\n# ============================================================\n# 7) SPRITES PAC-MAN (images)\n# ============================================================\n\nfichiers = [\"pacman_0.png\", \"pacman_1.png\", \"pacman_2.png\"]\nframes_base = []\nfor nom in fichiers:\n    img = pygame.image.load(str(dossier_assets \/ nom)).convert_alpha()\n    img = pygame.transform.smoothscale(\n        img,\n        (int(taille_tuile * 0.95), int(taille_tuile * 0.95))\n    )\n    frames_base.append(img)\n\ndef frames_orientees(direction: tuple[int, int]) -> list[pygame.Surface]:\n    \"\"\"Retourne la liste d'images tourn\u00e9e selon la direction affich\u00e9e.\"\"\"\n    dx, dy = direction\n    if (dx, dy) == (1, 0):\n        return frames_base\n    if (dx, dy) == (-1, 0):\n        return [pygame.transform.flip(f, True, False) for f in frames_base]\n    if (dx, dy) == (0, -1):\n        return [pygame.transform.rotate(f, 90) for f in frames_base]\n    if (dx, dy) == (0, 1):\n        return [pygame.transform.rotate(f, -90) for f in frames_base]\n    return frames_base\n\ndef rect_pacman(px: float, py: float) -> pygame.Rect:\n    \"\"\"Rectangle de collision du Pac-Man (plus petit que la case).\"\"\"\n    s = int(taille_tuile * 0.78)\n    return pygame.Rect(int(px - s \/ 2), int(py - s \/ 2), s, s)\n\ndef collision_mur(r: pygame.Rect) -> bool:\n    \"\"\"Vrai si le rectangle r touche au moins un mur.\"\"\"\n    return any(r.colliderect(m) for m in murs)\n\ndef case_depuis_position(px: float, py: float) -> tuple[int, int]:\n    \"\"\"Transforme des coordonn\u00e9es pixels en coordonn\u00e9es de case (x, y).\"\"\"\n    return (int((px - ox) \/\/ taille_tuile), int((py - oy) \/\/ taille_tuile))\n\n# ============================================================\n# 8) ENNEMI (MOUVEMENT SUR LA GRILLE)\n# ============================================================\n\nOPPOSE = {(1, 0): (-1, 0), (-1, 0): (1, 0), (0, 1): (0, -1), (0, -1): (0, 1)}\n\ndef direction_possible(case: tuple[int, int], direction: tuple[int, int]) -> bool:\n    \"\"\"Vrai si on peut aller de 'case' dans 'direction' sans sortir ni toucher un mur.\"\"\"\n    x, y = case\n    dx, dy = direction\n    nx, ny = x + dx, y + dy\n    if nx &lt; 0 or nx >= W or ny &lt; 0 or ny >= H:\n        return False\n    return not est_mur_case(nx, ny)\n\ndef mettre_a_jour_ennemi(ennemi: dict, dt: float) -> None:\n    \"\"\"\n    Met \u00e0 jour la position de l'ennemi.\n    - ennemi[\"case\"] : la case actuelle (grille)\n    - ennemi[\"direction\"] : direction actuelle (dx, dy)\n    - ennemi[\"progression\"] : avancement (0.0 -> 1.0) pour passer \u00e0 la case suivante\n    - ennemi[\"vitesse_cases\"] : nombre de cases par seconde\n    \"\"\"\n    distance = ennemi[\"vitesse_cases\"] * dt  # en \"cases\"\n    eps = 1e-6\n\n    while distance > 0:\n        # Si l'ennemi est pile au centre d'une case, on peut d\u00e9cider de tourner\n        if ennemi[\"progression\"] &lt;= eps:\n            if not direction_possible(ennemi[\"case\"], ennemi[\"direction\"]):\n                # Mur devant : on choisit une direction possible\n                choix = DIRECTIONS[:]\n                random.shuffle(choix)\n\n                # On \u00e9vite de faire demi-tour si possible (mais on le garde en dernier recours)\n                opp = OPPOSE.get(ennemi[\"direction\"])\n                if opp in choix:\n                    choix.remove(opp)\n                    choix.append(opp)\n\n                for d in choix:\n                    if direction_possible(ennemi[\"case\"], d):\n                        ennemi[\"direction\"] = d\n                        break\n\n        # Avancer vers la case suivante\n        restant = 1.0 - ennemi[\"progression\"]     # ce qu'il reste \u00e0 parcourir avant la prochaine case\n        pas = min(distance, restant)              # on avance au max jusqu'\u00e0 la prochaine case\n        ennemi[\"progression\"] += pas\n        distance -= pas\n\n        # Si on a atteint (ou d\u00e9pass\u00e9) la case suivante, on \"valide\" le d\u00e9placement\n        if ennemi[\"progression\"] >= 1.0 - eps:\n            x, y = ennemi[\"case\"]\n            dx, dy = ennemi[\"direction\"]\n            ennemi[\"case\"] = (x + dx, y + dy)\n            ennemi[\"progression\"] = 0.0\n\ndef position_ennemi_pixels(ennemi: dict) -> tuple[float, float]:\n    \"\"\"Calcule la position en pixels de l'ennemi (interpol\u00e9e entre 2 cases).\"\"\"\n    x, y = ennemi[\"case\"]\n    dx, dy = ennemi[\"direction\"]\n    p = ennemi[\"progression\"]\n    return (\n        ox + (x + 0.5 + dx * p) * taille_tuile,\n        oy + (y + 0.5 + dy * p) * taille_tuile\n    )\n\n# ============================================================\n# 9) DESSIN (LABYRINTHE, PASTILLES, CL\u00c9)\n# ============================================================\n\ndef dessiner_labyrinthe(porte_ouverte: bool) -> None:\n    \"\"\"Dessine les murs et le sol + la porte (ouverte\/ferm\u00e9e).\"\"\"\n    for y in range(H):\n        for x in range(W):\n            r = rect_tuile(x, y)\n            pygame.draw.rect(\n                ecran,\n                (70, 70, 85) if grille[y][x] == \"#\" else (25, 25, 32),\n                r\n            )\n\n    # La porte est un rectangle plus petit dans sa case\n    r = rect_tuile(case_porte[0], case_porte[1]).inflate(-10, -10)\n    couleur = (80, 220, 140) if porte_ouverte else (220, 120, 60)\n    pygame.draw.rect(ecran, couleur, r, border_radius=10)\n\ndef dessiner_pastilles(pastilles: set[tuple[int, int]]) -> None:\n    \"\"\"Dessine toutes les pastilles encore pr\u00e9sentes.\"\"\"\n    rayon = max(2, taille_tuile \/\/ 8)\n    for (x, y) in pastilles:\n        cx = ox + x * taille_tuile + taille_tuile \/\/ 2\n        cy = oy + y * taille_tuile + taille_tuile \/\/ 2\n        pygame.draw.circle(ecran, (240, 200, 60), (cx, cy), rayon)\n\ndef dessiner_cle(inventaire: dict) -> None:\n    \"\"\"Dessine la cl\u00e9 si elle n'a pas encore \u00e9t\u00e9 ramass\u00e9e.\"\"\"\n    if inventaire[\"cle\"] == 0:\n        cx = ox + case_cle[0] * taille_tuile + taille_tuile \/\/ 2\n        cy = oy + case_cle[1] * taille_tuile + taille_tuile \/\/ 2\n        pygame.draw.rect(\n            ecran,\n            (80, 220, 140),\n            pygame.Rect(cx - 6, cy - 6, 12, 12),\n            border_radius=3\n        )\n\n# ============================================================\n# 10) R\u00c9INITIALISATION (RECOMMENCER UNE PARTIE)\n# ============================================================\n\ndef reinitialiser():\n    \"\"\"Remet le jeu dans son \u00e9tat de d\u00e9part.\"\"\"\n    px0, py0 = centre_case(*case_depart)\n\n    pac = {\n        \"x\": px0,\n        \"y\": py0,\n        \"vitesse\": 220.0,          # pixels par seconde\n        \"direction_aff\": (1, 0),   # direction affich\u00e9e (sprite)\n        \"frame\": 0,                # image actuelle (animation)\n        \"temps_anim\": 0.0,         # accumulateur de temps pour l'animation\n    }\n\n    inv = {\"cle\": 0}\n\n    pts = creer_pastilles()\n    sc = 0\n\n    ene = {\n        \"case\": case_ennemi,\n        \"direction\": random.choice(DIRECTIONS),\n        \"progression\": 0.0,\n        \"vitesse_cases\": 4.5,      # cases par seconde\n    }\n\n    return pac, inv, pts, sc, ene\n\npacman, inventaire, pastilles, score, ennemi = reinitialiser()\n\netat = \"jeu\"      # \"jeu\" \/ \"gagne\" \/ \"perdu\"\nmessage = \"\"\n\n# ============================================================\n# 11) BOUCLE PRINCIPALE DU JEU\n# ============================================================\n\nen_cours = True\nwhile en_cours:\n    dt = horloge.tick(60) \/ 1000.0  # temps \u00e9coul\u00e9 depuis la frame pr\u00e9c\u00e9dente (en secondes)\n\n    # -----------------------------\n    # 11a) GESTION DES \u00c9V\u00c9NEMENTS\n    # -----------------------------\n    for event in pygame.event.get():\n        if event.type == pygame.QUIT:\n            en_cours = False\n\n        if event.type == pygame.KEYDOWN:\n            if event.key == pygame.K_ESCAPE:\n                en_cours = False\n            if event.key == pygame.K_r and etat != \"jeu\":\n                pacman, inventaire, pastilles, score, ennemi = reinitialiser()\n                etat = \"jeu\"\n                message = \"\"\n\n    # La porte s'ouvre quand on a la cl\u00e9 ET qu'il ne reste plus de pastilles\n    porte_ouverte = (inventaire[\"cle\"] > 0) and (len(pastilles) == 0)\n\n    # -----------------------------\n    # 11b) LOGIQUE DE JEU (si on joue)\n    # -----------------------------\n    if etat == \"jeu\":\n        touches = pygame.key.get_pressed()\n        dx, dy = 0, 0\n\n        if touches[pygame.K_LEFT]:\n            dx -= 1\n        if touches[pygame.K_RIGHT]:\n            dx += 1\n        if touches[pygame.K_UP]:\n            dy -= 1\n        if touches[pygame.K_DOWN]:\n            dy += 1\n\n        # Vitesse * dt => d\u00e9placement en pixels\n        vx = dx * pacman[\"vitesse\"] * dt\n        vy = dy * pacman[\"vitesse\"] * dt\n\n        # Direction affich\u00e9e du sprite\n        if dx != 0 or dy != 0:\n            pacman[\"direction_aff\"] = (dx, dy)\n\n        # D\u00e9placement + collisions : on teste s\u00e9par\u00e9ment X puis Y\n        nx = pacman[\"x\"] + vx\n        if not collision_mur(rect_pacman(nx, pacman[\"y\"])):\n            pacman[\"x\"] = nx\n\n        ny = pacman[\"y\"] + vy\n        if not collision_mur(rect_pacman(pacman[\"x\"], ny)):\n            pacman[\"y\"] = ny\n\n        # On r\u00e9cup\u00e8re la case o\u00f9 se trouve le joueur\n        case_p = case_depuis_position(pacman[\"x\"], pacman[\"y\"])\n\n        # Ramassage d'une pastille\n        if case_p in pastilles:\n            pastilles.remove(case_p)\n            score += 1\n            if son_chomp:\n                son_chomp.play()\n\n        # Ramassage de la cl\u00e9\n        if inventaire[\"cle\"] == 0 and case_p == case_cle:\n            inventaire[\"cle\"] = 1\n            if son_cle:\n                son_cle.play()\n\n        # Victoire si la porte est ouverte et qu'on marche dessus\n        porte_ouverte = (inventaire[\"cle\"] > 0) and (len(pastilles) == 0)\n        if porte_ouverte and case_p == case_porte:\n            etat = \"gagne\"\n            message = \"Victoire ! Appuie sur R pour rejouer\"\n            if son_porte:\n                son_porte.play()\n            if son_victoire:\n                son_victoire.play()\n\n        # Animation du Pac-Man (change d'image quand il bouge)\n        bouge = (dx != 0 or dy != 0)\n        if bouge:\n            pacman[\"temps_anim\"] += dt\n            if pacman[\"temps_anim\"] >= 1.0 \/ 12:  # 12 images par seconde\n                pacman[\"temps_anim\"] = 0.0\n                pacman[\"frame\"] = (pacman[\"frame\"] + 1) % len(frames_base)\n        else:\n            pacman[\"frame\"] = 0\n            pacman[\"temps_anim\"] = 0.0\n\n        # Ennemi + collision avec le joueur\n        mettre_a_jour_ennemi(ennemi, dt)\n        ex, ey = position_ennemi_pixels(ennemi)\n\n        dxp = pacman[\"x\"] - ex\n        dyp = pacman[\"y\"] - ey\n        if (dxp * dxp + dyp * dyp) &lt; (0.45 * taille_tuile) ** 2:\n            etat = \"perdu\"\n            message = \"Perdu ! Appuie sur R pour recommencer\"\n            if son_mort:\n                son_mort.play()\n\n    # -----------------------------\n    # 11c) DESSIN\n    # -----------------------------\n    ecran.fill((15, 15, 20))\n    dessiner_labyrinthe(porte_ouverte)\n    dessiner_pastilles(pastilles)\n    dessiner_cle(inventaire)\n\n    # Ennemi (cercle rouge)\n    ex, ey = position_ennemi_pixels(ennemi)\n    pygame.draw.circle(\n        ecran,\n        (220, 60, 60),\n        (int(ex), int(ey)),\n        max(5, taille_tuile \/\/ 3)\n    )\n\n    # Pac-Man (sprite orient\u00e9)\n    fr = frames_orientees(pacman[\"direction_aff\"])\n    sprite = fr[pacman[\"frame\"]]\n    ecran.blit(sprite, sprite.get_rect(center=(int(pacman[\"x\"]), int(pacman[\"y\"]))))\n\n    # HUD (infos en haut)\n    hud = f\"Score : {score}   Cl\u00e9 : {inventaire['cle']}   Pastilles : {len(pastilles)}\"\n    ecran.blit(police.render(hud, True, (235, 235, 245)), (18, 14))\n\n    if message:\n        ecran.blit(police.render(message, True, (245, 245, 245)), (18, 40))\n\n    pygame.display.flip()\n\npygame.quit()\n\n<\/pre>\n<\/div><\/div>\n<\/div><\/div>\n","protected":false},"excerpt":{"rendered":"<p>La librairie Pygame ne fonctionne pas pr\u00e9sente dans capytale. IL faut donc utiliser thonny. Pygame, c\u2019est une biblioth\u00e8que Python qui [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_crdt_document":"","footnotes":""},"categories":[1],"tags":[],"class_list":["post-280","post","type-post","status-publish","format-standard","hentry","category-non-classe"],"_links":{"self":[{"href":"https:\/\/yb-isn.fr\/2025\/nsi\/wp-json\/wp\/v2\/posts\/280","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/yb-isn.fr\/2025\/nsi\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/yb-isn.fr\/2025\/nsi\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/yb-isn.fr\/2025\/nsi\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/yb-isn.fr\/2025\/nsi\/wp-json\/wp\/v2\/comments?post=280"}],"version-history":[{"count":35,"href":"https:\/\/yb-isn.fr\/2025\/nsi\/wp-json\/wp\/v2\/posts\/280\/revisions"}],"predecessor-version":[{"id":355,"href":"https:\/\/yb-isn.fr\/2025\/nsi\/wp-json\/wp\/v2\/posts\/280\/revisions\/355"}],"wp:attachment":[{"href":"https:\/\/yb-isn.fr\/2025\/nsi\/wp-json\/wp\/v2\/media?parent=280"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/yb-isn.fr\/2025\/nsi\/wp-json\/wp\/v2\/categories?post=280"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/yb-isn.fr\/2025\/nsi\/wp-json\/wp\/v2\/tags?post=280"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}