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

292
labyrinthe.js Normal file → Executable file
View File

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