maze in favicon

This commit is contained in:
Adrien MALINGREY 2023-05-29 00:26:47 +02:00
parent 568645c01e
commit 350c725317
10 changed files with 351 additions and 156 deletions

44
favicon.php Normal file
View File

@ -0,0 +1,44 @@
<?php
header('Content-Type: image/x-icon');
const SIZE = 16;
const WALL = 1;
const GROUND = 0;
$favicon = imagecreatetruecolor(SIZE, SIZE);
$wallColor = imagecolorallocate($favicon, 165, 80, 30);
$groundColor = imagecolorallocate($favicon, 203, 162, 133);
imagefill($favicon, 0, 0, $wallColor);
$maze = array();
for ($y = 0; $y < SIZE; $y++) {
$maze[$y] = array();
for ($x = 0; $x < SIZE; $x++) {
$maze[$y][$x] = WALL;
}
}
function dig($position) {
global $maze;
global $favicon;
global $groundColor;
$directions = [[0, 1], [0, -1], [1, 0], [-1, 0]];
shuffle($directions);
foreach ($directions as $direction) {
$step1 = [$position[0] + $direction[0], $position[1] + $direction[1]];
$step2 = [$step1[0] + $direction[0], $step1[1] + $direction[1]];
if (0 <= $step2[1] and $step2[1] < SIZE and 0 <= $step2[0] and $step2[0] < SIZE and $maze[$step2[1]][$step2[0]] == WALL) {
$maze[$step1[1]][$step1[0]] = GROUND;
imagesetpixel($favicon, $step1[0], $step1[1], $groundColor);
$maze[$step2[1]][$step2[0]] = GROUND;
imagesetpixel($favicon, $step2[0], $step2[1], $groundColor);
dig($step2);
}
}
}
dig([1, 1]);
imagebmp($favicon);
imagedestroy($favicon);
?>

40
index.html Normal file → Executable file
View File

@ -1,29 +1,31 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang='fr' dir="ltr" prefix="og: https://ogp.me/ns#">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8"/>
<title>Labyrinthe</title> <title>Labyrinthe</title>
<script type="text/javascript" src="labyrinthe.js"></script> <script type="text/javascript" src="labyrinthe.js"></script>
<link rel="shortcut icon" type="image/png" href="mur.png"/> <link rel="shortcut icon" type="image/png" href="favicon.php"/>
<link rel="stylesheet" type="text/css" href="style.css" /> <link rel="stylesheet" type="text/css" href="style.css"/>
<link rel=”image_src” href="thumbnail.png" /> <link rel=”image_src” href="thumbnail.png"/>
<meta property="og:title" content="Labyrinthe" /> <link rel="manifest" href="manifest.json">
<meta property="og:type" content="game" /> <meta property="og:title" content="Labyrinthe"/>
<meta property="og:url" content="https://malingrey.fr/laby" /> <meta property="og:type" content="website"/>
<meta property="og:image" content="https://malingrey.fr/laby/thumbnail.png" /> <meta property="og:url" content="https://adrien.malingrey.fr/jeux/laby/"/>
<meta property="og:image:width" content="250" /> <meta property="og:image" content="https://adrien.malingrey.fr/jeux/laby/thumbnail.png"/>
<meta property="og:image:height" content="250" /> <meta property="og:image:width" content="250"/>
<meta property="og:description" content="Trouveras-tu le fromage ?" /> <meta property="og:image:height" content="250"/>
<meta property="og:locale" content="fr_FR" /> <meta property="og:description" content="Trouveras-tu le fromage ?"/>
<meta property="og:locale" content="fr_FR"/>
<meta property="og:site_name" content="adrien.malingrey.fr"/>
</head> </head>
<body> <body>
<div style="display:none;"> <div style="display:none;">
<img id="mur" src="mur.png"> <img id="mur" src="mur.png">
<img id="sol" src="sol.png"> <img id="sol" src="sol.png">
<img id="pas" src="pas.png"> <img id="pas" src="pas.png">
<img id="fromage" src="fromage.png"> <img id="fromage" src="fromage.png">
<img id="souris" src="souris.png"> <img id="souris" src="souris.png">
</div> </div>
<canvas id="canvas" width="795" height="585">Votre navigateur ne supporte pas HTML5, veuillez le mettre à jour pour jouer.</canvas> <canvas id="canvas" width="795" height="585">Votre navigateur ne supporte pas HTML5, veuillez le mettre à jour pour jouer.</canvas>
</body> </body>
</html> </html>

292
labyrinthe.js Normal file → Executable file
View File

@ -1,209 +1,229 @@
// Customize Array to be use as coordinates // Customize Array to be use as coordinates
Object.defineProperty(Array.prototype, "x", { Object.defineProperties(Array.prototype, {
get: function () { return this[0] }, "x": {
set: function (x) { this[0] = x} get: function() { return this[0] },
set: function(x) { this[0] = x }
},
"y": {
get: function() { return this[1] },
set: function(y) { this[1] = y }
}
}) })
Object.defineProperty(Array.prototype, "y", { Array.prototype.plus = function (other) {
get: function () { return this[1] }, return this.map((x, i) => x + other[i]);
set: function (y) { this[1] = y} };
})
Array.prototype.plus = function(other) { return this.map((x, i) => x + other[i]) }
const DIRECTION = { const DIRECTION = {
"BAS": 0, 'BAS': 0,
"GAUCHE": 1, 'GAUCHE': 1,
"DROITE": 2, 'DROITE': 2,
"HAUT": 3 'HAUT': 3,
} };
const MOUVEMENT = { const MOUVEMENT = {
"ARRET": [0, 0], 'ARRET': [0, 0],
"BAS": [0, 1], 'BAS': [0, 1],
"HAUT": [0, -1], 'HAUT': [0, -1],
"GAUCHE": [-1, 0], 'GAUCHE': [-1, 0],
"DROITE": [1, 0] 'DROITE': [1, 0],
} };
const ACTIONS = { const ACTIONS = {
"ArrowUp": {"direction": DIRECTION.HAUT, "mouvement": MOUVEMENT.HAUT}, 'ArrowUp': { 'direction': DIRECTION.HAUT, 'mouvement': MOUVEMENT.HAUT },
"ArrowDown": {"direction": DIRECTION.BAS, "mouvement": MOUVEMENT.BAS}, 'z': { 'direction': DIRECTION.HAUT, 'mouvement': MOUVEMENT.HAUT },
"ArrowLeft": {"direction": DIRECTION.GAUCHE, "mouvement": MOUVEMENT.GAUCHE}, 'ArrowDown': { 'direction': DIRECTION.BAS, 'mouvement': MOUVEMENT.BAS },
"ArrowRight": {"direction": DIRECTION.DROITE, "mouvement": MOUVEMENT.DROITE}, 's': { 'direction': DIRECTION.BAS, 'mouvement': MOUVEMENT.BAS },
} 'ArrowLeft': { 'direction': DIRECTION.GAUCHE, 'mouvement': MOUVEMENT.GAUCHE },
'q': { 'direction': DIRECTION.GAUCHE, 'mouvement': MOUVEMENT.GAUCHE },
'ArrowRight': { 'direction': DIRECTION.DROITE, 'mouvement': MOUVEMENT.DROITE },
'd': { 'direction': DIRECTION.DROITE, 'mouvement': MOUVEMENT.DROITE },
};
const TYPE = { const TYPE = {
"MUR": 1, 'MUR': 1,
"SOL": 2, 'SOL': 2,
"PAS": 3 'PAS': 3,
} };
const DIRECTIONS_LABYRINTHE = [MOUVEMENT.BAS, MOUVEMENT.HAUT, MOUVEMENT.GAUCHE, MOUVEMENT.DROITE];
const TAILLE_TUILE = 15;
const DIRECTIONS_LABYRINTHE = [MOUVEMENT.BAS, MOUVEMENT.HAUT, MOUVEMENT.GAUCHE, MOUVEMENT.DROITE]
const TAILLE_TUILE = 15
function dessinerTuile(context, image, x, y) { function dessinerTuile(context, image, x, y) {
context.drawImage(image, TAILLE_TUILE*x, TAILLE_TUILE*y); context.drawImage(image, TAILLE_TUILE * x, TAILLE_TUILE * y);
} }
class Labyrinthe extends Array { class Labyrinthe extends Array {
constructor(largeur, hauteur, context, tuiles) { constructor(largeur, hauteur, context, tuiles) {
super() super();
this.hauteur = hauteur this.hauteur = hauteur;
this.largeur = largeur this.largeur = largeur;
this.context = context this.context = context;
this.tuiles = tuiles this.tuiles = tuiles;
for (var ligne=0; ligne < hauteur; ligne++) { for (var ligne = 0; ligne < hauteur; ligne++) {
this.push(Array(largeur).fill(TYPE.MUR)) this.push(Array(largeur).fill(TYPE.MUR));
} }
this.positionInitiale = [1, 1] this.positionInitiale = [1, 1];
this.positionFinale = [largeur - 2, hauteur - 2] this.positionFinale = [largeur - 2, hauteur - 2];
this.creuse(this.positionFinale) this.creuse(this.positionFinale);
this.construit(this.positionFinale) this.construit(this.positionFinale);
} }
construit(position) { construit(position) {
for (var direction of Array.from(DIRECTIONS_LABYRINTHE).sort(x => .5 - Math.random())) { for (var direction of Array.from(DIRECTIONS_LABYRINTHE).sort(x => 0.5 - Math.random())) {
var pas1 = position.plus(direction) var pas1 = position.plus(direction);
var pas2 = pas1.plus(direction) var pas2 = pas1.plus(direction);
if (this.type(pas2) == TYPE.MUR) { if (this.type(pas2) == TYPE.MUR) {
this.creuse(pas1) this.creuse(pas1);
this.creuse(pas2) this.creuse(pas2);
this.construit(pas2) this.construit(pas2);
} }
} }
} }
creuse(position) { creuse(position) {
this[position.y][position.x] = TYPE.SOL this[position.y][position.x] = TYPE.SOL;
} }
type(position) { type(position) {
if (0 <= position.x && position.x < this.largeur && 0 <= position.y && position.y < this.hauteur) { if (
return this[position.y][position.x] 0 <= position.x &&
position.x < this.largeur &&
0 <= position.y &&
position.y < this.hauteur
) {
return this[position.y][position.x];
} else { } else {
return -1 return -1;
} }
} }
dessiner() { dessiner() {
this.forEach((ligne, y) => { this.forEach((ligne, y) => {
ligne.forEach((type, x) => { ligne.forEach((type, x) => {
dessinerTuile(this.context, this.tuiles[type], x, y) dessinerTuile(this.context, this.tuiles[type], x, y);
}) });
}) });
} }
} }
class Souris { class Souris {
constructor(position, context, sprites) { constructor(position, context, sprites) {
this.position = position this.position = position;
this.context = context this.context = context;
this.sprites = sprites this.sprites = sprites;
this.futurePosition = this.position this.futurePosition = this.position;
this.direction = DIRECTION.DROITE this.direction = DIRECTION.DROITE;
this.mouvement = MOUVEMENT.ARRET this.mouvement = MOUVEMENT.ARRET;
this.tailleSprite = 48 this.tailleSprite = 48;
this.animationSprite = 0 this.animationSprite = 0;
this.animation = 0 this.animation = 0;
} }
bouger(touche, labyrinthe) { bouger(touche, labyrinthe) {
if (touche in ACTIONS) { if (touche in ACTIONS) {
this.direction = ACTIONS[touche].direction this.direction = ACTIONS[touche].direction;
this.mouvement = ACTIONS[touche].mouvement this.mouvement = ACTIONS[touche].mouvement;
var futurePosition = this.position.plus(this.mouvement) var futurePosition = this.position.plus(this.mouvement);
if ([TYPE.SOL, TYPE.PAS].includes(labyrinthe.type(futurePosition))) { if ([TYPE.SOL, TYPE.PAS].includes(labyrinthe.type(futurePosition))) {
labyrinthe[this.position.y][this.position.x] = TYPE.PAS labyrinthe[this.position.y][this.position.x] = TYPE.PAS;
this.futurePosition = futurePosition this.futurePosition = futurePosition;
return true return true;
} else { } else {
this.mouvement = MOUVEMENT.ARRET this.mouvement = MOUVEMENT.ARRET;
this.animation = 0 this.animation = 0;
return false return false;
} }
} else { } else {
return False return False;
} }
} }
dessiner() { dessiner() {
this.context.drawImage( this.context.drawImage(
this.sprites, this.sprites,
this.tailleSprite * this.animationSprite, this.tailleSprite * this.animationSprite,
this.tailleSprite * this.direction, this.tailleSprite * this.direction,
this.tailleSprite, this.tailleSprite,
this.tailleSprite, this.tailleSprite,
TAILLE_TUILE * this.position.x - 17 + this.mouvement.x * this.animation, TAILLE_TUILE * this.position.x - 17 + this.mouvement.x * this.animation,
TAILLE_TUILE * this.position.y - 12 + this.mouvement.y * this.animation, TAILLE_TUILE * this.position.y - 12 + this.mouvement.y * this.animation,
this.tailleSprite, this.tailleSprite,
this.tailleSprite this.tailleSprite
); );
} }
} }
window.onload = function() { window.onload = function () {
var canvas = document.getElementById('canvas') var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d') var ctx = canvas.getContext('2d');
var fromage = document.getElementById("fromage"); var fromage = document.getElementById('fromage');
var sourisSprites = document.getElementById("souris"); var sourisSprites = document.getElementById('souris');
var tuiles = {} var tuiles = {};
tuiles[TYPE.MUR] = document.getElementById("mur") tuiles[TYPE.MUR] = document.getElementById('mur');
tuiles[TYPE.SOL] = document.getElementById("sol") tuiles[TYPE.SOL] = document.getElementById('sol');
tuiles[TYPE.PAS] = document.getElementById("pas") tuiles[TYPE.PAS] = document.getElementById('pas');
var touchesPressees = new this.Set() var touchesPressees = new this.Set();
var largeur = Math.floor(window.innerWidth / TAILLE_TUILE) var largeur = Math.floor(window.innerWidth / TAILLE_TUILE);
largeur = largeur - ((largeur+1) % 2) largeur = largeur - ((largeur + 1) % 2);
var hauteur = Math.floor(window.innerHeight / TAILLE_TUILE) var hauteur = Math.floor(window.innerHeight / TAILLE_TUILE);
hauteur = hauteur - ((hauteur+1) % 2) hauteur = hauteur - ((hauteur + 1) % 2);
canvas.width = largeur * TAILLE_TUILE; canvas.width = largeur * TAILLE_TUILE;
canvas.height = hauteur * TAILLE_TUILE; canvas.height = hauteur * TAILLE_TUILE;
var labyrinthe = new Labyrinthe(largeur, hauteur, ctx, tuiles) var labyrinthe = new Labyrinthe(largeur, hauteur, ctx, tuiles);
var souris = new Souris(labyrinthe.positionInitiale, ctx, sourisSprites) var souris = new Souris(labyrinthe.positionInitiale, ctx, sourisSprites);
window.onkeydown = function(event) { window.onkeydown = function (event) {
if (event.key in ACTIONS) { if (event.key in ACTIONS) {
touchesPressees.add(event.key) touchesPressees.add(event.key);
return false return false;
} else { } else {
return true return true;
} }
} };
window.onkeyup = function(event) { window.onkeyup = function (event) {
if (event.key in ACTIONS) { if (event.key in ACTIONS) {
touchesPressees.delete(event.key) touchesPressees.delete(event.key);
return false return false;
} else { } else {
return true return true;
} }
} };
var timerID var timerID;
timerID = setInterval(function() { timerID = setInterval(function () {
if (touchesPressees.size > 0) souris.animationSprite = (souris.animationSprite + 1) % 3 if (touchesPressees.size > 0) souris.animationSprite = (souris.animationSprite + 1) % 3;
if (souris.mouvement != MOUVEMENT.ARRET) { if (souris.mouvement != MOUVEMENT.ARRET) {
souris.animation += 5 souris.animation += 5;
if (souris.animation >= TAILLE_TUILE) { if (souris.animation >= TAILLE_TUILE) {
souris.animation = 0 souris.animation = 0;
souris.position = souris.futurePosition souris.position = souris.futurePosition;
if (souris.position.x == labyrinthe.positionFinale.x && souris.position.y == labyrinthe.positionFinale.y) { if (
window.alert("Miam miam !") souris.position.x == labyrinthe.positionFinale.x &&
clearInterval(timerID) souris.position.y == labyrinthe.positionFinale.y
) {
window.alert('Miam miam !');
clearInterval(timerID);
} }
} }
} }
if (souris.animation == 0) { if (souris.animation == 0) {
souris.mouvement = MOUVEMENT.ARRET souris.mouvement = MOUVEMENT.ARRET;
for (touche of Array.from(touchesPressees).reverse()) { for (touche of Array.from(touchesPressees).reverse()) {
if (souris.bouger(touche, labyrinthe)) break if (souris.bouger(touche, labyrinthe)) break;
} }
} }
labyrinthe.dessiner() labyrinthe.dessiner();
dessinerTuile(ctx, fromage, labyrinthe.positionFinale.x, labyrinthe.positionFinale.y) dessinerTuile(ctx, fromage, labyrinthe.positionFinale.x, labyrinthe.positionFinale.y);
souris.dessiner() souris.dessiner();
}, 40); }, 40);
}
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('service-worker.js');
}
};

42
manifest.json Normal file
View File

@ -0,0 +1,42 @@
{
"short_name": "Labyrinthe",
"name": "Labyrinthe",
"description": "Trouveras-tu le fromage ?",
"icons": [
{
"src": "mur.png",
"type": "image/png",
"sizes": "15x15"
},
{
"src": "thumbnail.png",
"type": "image/png",
"sizes": "250x250"
}
],
"start_url": "index.html",
"background_color": "#c55818",
"display": "standalone",
"scope": "index.html",
"theme_color": "#c55818",
"shortcuts": [
{
"name": "Labyrinthe",
"short_name": "Labyrinthe",
"description": "Trouveras-tu le fromage ?",
"url": "index.html",
"icons": [
{
"src": "mur.png",
"type": "image/png",
"sizes": "15x15"
},
{
"src": "thumbnail.png",
"type": "image/png",
"sizes": "250x250"
}
]
}
]
}

0
mur.png Normal file → Executable file
View File

Before

Width:  |  Height:  |  Size: 581 B

After

Width:  |  Height:  |  Size: 581 B

BIN
pas.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 648 B

86
service-worker.js Normal file
View File

@ -0,0 +1,86 @@
/*
Copyright 2015, 2019, 2020 Google LLC. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// Incrementing OFFLINE_VERSION will kick off the install event and force
// previously cached resources to be updated from the network.
const OFFLINE_VERSION = 1;
const CACHE_NAME = "offline";
// Customize this with a different URL if needed.
const OFFLINE_URL = "index.html";
self.addEventListener("install", (event) => {
event.waitUntil(
(async () => {
const cache = await caches.open(CACHE_NAME);
// Setting {cache: 'reload'} in the new request will ensure that the
// response isn't fulfilled from the HTTP cache; i.e., it will be from
// the network.
await cache.add(new Request(OFFLINE_URL, { cache: "reload" }));
})()
);
// Force the waiting service worker to become the active service worker.
self.skipWaiting();
});
self.addEventListener("activate", (event) => {
event.waitUntil(
(async () => {
// Enable navigation preload if it's supported.
// See https://developers.google.com/web/updates/2017/02/navigation-preload
if ("navigationPreload" in self.registration) {
await self.registration.navigationPreload.enable();
}
})()
);
// Tell the active service worker to take control of the page immediately.
self.clients.claim();
});
self.addEventListener("fetch", (event) => {
// We only want to call event.respondWith() if this is a navigation request
// for an HTML page.
if (event.request.mode === "navigate") {
event.respondWith(
(async () => {
try {
// First, try to use the navigation preload response if it's supported.
const preloadResponse = await event.preloadResponse;
if (preloadResponse) {
return preloadResponse;
}
// Always try the network first.
const networkResponse = await fetch(event.request);
return networkResponse;
} catch (error) {
// catch is only triggered if an exception is thrown, which is likely
// due to a network error.
// If fetch() returns a valid HTTP response with a response code in
// the 4xx or 5xx range, the catch() will NOT be called.
console.log("Fetch failed; returning offline page instead.", error);
const cache = await caches.open(CACHE_NAME);
const cachedResponse = await cache.match(OFFLINE_URL);
return cachedResponse;
}
})()
);
}
// If our if() condition is false, then this fetch handler won't intercept the
// request. If there are any other fetch handlers registered, they will get a
// chance to call event.respondWith(). If no fetch handlers call
// event.respondWith(), the request will be handled by the browser as if there
// were no service worker involvement.
});

BIN
sol.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 644 B

BIN
souris.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

3
style.css Normal file → Executable file
View File

@ -1,4 +1,5 @@
body { body {
background: #c55818;
background-image: url("mur.png"); background-image: url("mur.png");
background-position: center; background-position: center;
margin: 0; margin: 0;
@ -7,4 +8,4 @@ body {
canvas { canvas {
display: block; display: block;
margin: 0 auto; margin: 0 auto;
} }