rajout des textes explicatifs

This commit is contained in:
Didictateur 2025-03-28 21:20:06 +01:00
parent d686d6559a
commit ac2825a7cb
15 changed files with 432 additions and 55 deletions

View file

@ -1,6 +1,3 @@
DISPLAY = $(wildcard src/display/*.ts)
OUTFILES = $(patsubst src/display/%.ts,build/%.js,$(DISPLAY))
all:
npx webpack --mode development

View file

@ -57,6 +57,10 @@
.menu-item:hover .dropdown {
display: block;
}
.container {
display: flex;
justify-content: space-betwenne;
}
</style>
</head>
<body>
@ -108,11 +112,31 @@
</ul>
</nav>
<div id="canvasContainer"></div>
<div class="container">
<div id="canvasContainer"></div>
<div id="anotherCanvasContainer"></div>
</div>
<script>
let currentScript = null;
function loadText(scriptName) {
if (window.cleanup) {
window.cleanup();
}
const container = document.getElementById("anotherCanvasContainer");
container.innerHTML = `<canvas id="myTextCanvas" width="1000" height="1000"></canvas>`;
const timestamp = new Date().getTime();
currentScript = document.createElement("script");
currentScript.type = "module";
currentScript.src = `build/${scriptName}?t=${timestamp}`;
document.body.appendChild(currentScript);
}
function loadScript(scriptName) {
if (window.cleanup) {
window.cleanup();
@ -128,6 +152,9 @@
currentScript.src = `build/${scriptName}?t=${timestamp}`;
document.body.appendChild(currentScript);
const number = scriptName.substring(2, scriptName.length - 3);
loadText("txt" + number + ".js");
}
//script initial

View file

@ -1,3 +1,5 @@
import { Tile } from "./tile"
type button_t = (
arg0: CanvasRenderingContext2D,
arg1: number,
@ -37,7 +39,6 @@ export function clickAction(
) {
return buttons.filter(c => c[0])[q][1] as number;
}
console.log(q, r, "\n");
return -1;
}
@ -72,6 +73,66 @@ export function drawButtons(
}
}
export function clickChii(
x: number,
y: number,
chiis: Array<Array<Tile>>
): number {
let xmin = 960 - (chiis.length + 1) * 120;
let inside = 838 < y && y < 888;
let q = Math.floor((x - xmin) / 120);
let r = (x - xmin) - 120 * q;
if (
q >= 0 &&
q < (chiis.length + 1) &&
r > 10 &&
inside
) {
return q === chiis.length ? 0 : q + 1;
}
return -1;
}
export function drawChiis(
ctx: CanvasRenderingContext2D,
chiis: Array<Array<Tile>>
): void {
const r = 8;
const w = 110;
const h = 50;
button(ctx, 850, 835, r, w, h, "#FF9030");
ctx.fillStyle = "black";
ctx.font = "30px garamond";
ctx.fillText("Retour", 850 + w * 0.1, 835 + h/2 * 1.3);
let dx = 1;
console.log("length: ", chiis.length, "\n");
for (let i = 0; i < chiis.length; i++) {
console.log("trying to draw\n");
drawOneChii(
ctx,
850 - dx * 120,
835,
chiis[i]
);
dx++;
}
}
function drawOneChii(
ctx: CanvasRenderingContext2D,
x: number,
y: number,
tiles: Array<Tile>
): void {
const r = 8;
const w = 110;
const h = 50;
button(ctx, x, y, r, w, h, "#FFCC33");
ctx.fillStyle = "black";
ctx.font = "30px garamond";
}
function button(
ctx: CanvasRenderingContext2D,
x: number,

View file

@ -27,7 +27,7 @@ async function display() {
let x = 180;
let y = 80;
let size = 0.75;
let xos = 50;
let xos = 40;
let yos = 100;
const deck = new Deck(false);
await preloadDeck(deck);

View file

@ -2,7 +2,7 @@ import { Deck } from "./deck";
import { Hand } from "./hand";
import { Tile } from "./tile";
import { Group } from "./group";
import { drawButtons, clickAction } from "./button";
import { drawButtons, clickAction, drawChiis, clickChii } from "./button";
import { drawState } from "./state";
export type mousePos = { x: number, y: number};
@ -23,6 +23,7 @@ export class Game {
private hasPicked: boolean = false;
private hasPlayed: boolean = false;
private lastPlayed: number = Date.now();
private chooseChii: boolean = false;
private end: boolean = false;
// display parameter
@ -100,38 +101,59 @@ export class Game {
mp: mousePos,
): void {
const rect = this.cv.getBoundingClientRect();
let action = clickAction(
mp.x - rect.left,
mp.y - rect.top,
this.canDoAChii().length > 0,
this.canDoAPon(),
false && this.level > 1,
false && this.level > 0,
false && this.level > 0
);
if (this.canCall && action !== -1) { // can call
if (action === 0) { // pass
this.canCall = false;
if (this.turn === 3) {
this.turn = 0;
this.pick(0);
} else {
this.turn++;
}
this.hasPicked = true;
this.hasPlayed = false;
} else if (action == 2) { // pon
this.pon(this.turn);
if (this.chooseChii) { // is choosing
let allChii = this.getChii(0);
let c = clickChii(
mp.x - rect.x,
mp.y - rect.y,
allChii
);
console.log("chii action:", c, "\n");
if (c === 0) {
this.chooseChii = false;
}
} else {
let action = clickAction(
mp.x - rect.left,
mp.y - rect.top,
this.canDoAChii().length > 0,
this.canDoAPon(),
false && this.level > 1,
false && this.level > 0,
false && this.level > 0
);
} else { // nothing unusual
if (this.turn === 0 && this.selectedTile !== undefined) {
this.discard(0, this.selectedTile as NonNullable<number>);
this.checkPon();
console.log("turn", this.turn, "\n");
this.turn = (this.turn + 1) % 4;
console.log("new turn", this.turn, "\n");
if (this.canCall && action !== -1) { // can call
if (action === 0) { // pass
this.canCall = false;
if (this.turn === 3) {
this.turn = 0;
this.pick(0);
} else {
this.turn++;
}
this.hasPicked = true;
this.hasPlayed = false;
} else if (action === 1) { // chii
let chiis = this.canDoAChii();
if (chiis.length === 0) { // only one possible
this.chii(chiis[0], 0); // TODO not 0
} else {
this.chooseChii = true;
this.drawGame();
}
} else if (action == 2) { // pon
this.pon(this.turn);
}
} else { // nothing unusual
if (this.turn === 0 && this.selectedTile !== undefined) {
this.discard(0, this.selectedTile as NonNullable<number>);
this.checkPon();
this.turn = (this.turn + 1) % 4;
}
}
}
}
@ -166,7 +188,6 @@ export class Game {
if (
this.turn !== 0
) { // bot playing
console.log(this.turn, '\n');
if (!this.hasPicked) { // begin of his turn
this.lastPlayed = Date.now();
this.pick(this.turn);
@ -214,16 +235,16 @@ export class Game {
this.lastPlayed = Date.now();
}
private canDoAChii(): Array<number> {
private canDoAChii(p: number = 0): Array<number> {
let chii = [] as Array<number>;
if (
this.lastDiscard !== undefined &&
this.lastDiscard === 3 &&
this.turn === 3 &&
(this.lastDiscard + 1) % 4 === p &&
(this.turn + 1) % 4 === p &&
this.discards[this.lastDiscard][this.discards[this.lastDiscard].length-1].getFamily() < 4
) {
let t = this.discards[this.lastDiscard][this.discards[this.lastDiscard].length-1];
let h = this.hands[0];
let h = this.hands[p];
if (
h.count(t.getFamily(), t.getValue()-2) > 0 &&
h.count(t.getFamily(), t.getValue()-1) > 0
@ -244,14 +265,57 @@ export class Game {
return chii;
}
private chii(minValue: number): void {
console.log("Chii !\n");
private chii(minValue: number, p: number): void {
let t = this.discards[p === 0 ? 3 : p - 1].pop() as NonNullable<Tile>;
this.lastDiscard = undefined;
let tn = 0;
let v = minValue;
let tt: Array<Tile> = [];
while (tn < 2) {
if (v === t.getValue()) {
v++;
} else {
tt[tn] = this.hands[p].find(t.getFamily(), v) as NonNullable<Tile>;
tn++;
v++;
}
}
[t, tt[0], tt[1]].forEach(t => t.setTilt());
this.groups[p].push(new Group([t, tt[0], tt[1]], p === 0 ? 3 : p - 1, p));
this.turn = p;
this.hasPicked = true;
this.hasPlayed = false;
}
private getChii(p: number): Array<Array<Tile>> {
let chiis = [] as Array<Array<Tile>>;
let numChii = this.canDoAChii();
let d = this.discards[p === 0 ? 3 : p - 1];
let t = d[d.length - 1]
for (let i = 0; i < numChii.length; i++) {
let v = numChii[i];
let chii = [];
for (let dv = 0; dv < 3; dv++) {
if (v + dv === t.getValue()) {
chii.push(t);
} else {
let tt = this.hands[p].find(t.getFamily(), v + dv) as NonNullable<Tile>;
chii.push(tt);
this.hands[p].push(tt);
}
}
chiis.push(chii);
}
return chiis;
}
private checkPon(): void {
for (var p = 1; p < 4; p++) {
if (this.canDoAPon(p)) {
console.log(p, '\n');
this.pon(this.lastDiscard as NonNullable<number>, p);
break;
}
@ -272,7 +336,6 @@ export class Game {
}
private pon(p: number, thief: number = 0): void {
console.log(thief, "stole", p, '\n');
let t = this.discards[p].pop() as NonNullable<Tile>;
this.lastDiscard = undefined;
let t2 = this.hands[thief].find(t.getFamily(), t.getValue()) as NonNullable<Tile>;
@ -308,14 +371,18 @@ export class Game {
}
// called
drawButtons(
this.staticCtx,
this.canDoAChii().length > 0,
this.canDoAPon(),
false && this.level > 1,
false && this.level > 0,
false && this.level > 0
);
if (this.chooseChii) {
drawChiis(this.staticCtx, this.getChii(0));
} else {
drawButtons(
this.staticCtx,
this.canDoAChii().length > 0,
this.canDoAPon(),
false && this.level > 1,
false && this.level > 0,
false && this.level > 0
);
}
}
private drawHands() {

57
src/text/parse.ts Normal file
View file

@ -0,0 +1,57 @@
export async function drawText(
filePath: string,
ctx: CanvasRenderingContext2D,
): Promise<void> {
console.log(filePath, "\n");
const fileContent = await fetch(filePath)
.then(response => response.text());
const size = 30;
const dl = 5;
const ll = 50;
const xx = 10;
const defaultColor = "#ffffff";
ctx.fillStyle = defaultColor;
ctx.font = size + "px Garamond";
let readingColor = false;
let color = "";
let gras = "";
let italic = "";
let line = 1;
let x = 0;
for (var c of fileContent) {
if (c === '*') {
if (gras === "") {
gras = "bold ";
} else {
gras = "";
}
ctx.font = italic + gras + size + "px Garamond";
} else if (c === '~') {
if (italic === "") {
italic = "italic ";
} else {
italic = "";
}
ctx.font = italic + gras + size + "px Garamond";
} else if (c === '#') {
color = "#";
readingColor = true;
} else if (c === '{') {
readingColor = false;
ctx.fillStyle = color;
} else if (c === '}') {
color = "";
ctx.fillStyle = defaultColor;
} else if (readingColor) {
color += c;
} else if (c === '\n') {
line++;
x = 0;
} else {
ctx.fillText(c, xx + x, ll + line * (size + dl));
x += ctx.measureText(c).width;
}
}
}

18
src/text/txt1.ts Normal file
View file

@ -0,0 +1,18 @@
import { drawText } from "./parse"
const CANVAS_ID = "myTextCanvas";
const BG_RECT = { x: 0, y: 0, w: 800, h: 1050, color: "#007733" };
const canvas = document.getElementById(CANVAS_ID) as HTMLCanvasElement;
const ctx = canvas.getContext("2d") as NonNullable<CanvasRenderingContext2D>;
canvas.width = BG_RECT.w;
canvas.height = BG_RECT.h;
const path = "../src/text/";
ctx.fillStyle = BG_RECT.color;
ctx.fillRect(BG_RECT.x, BG_RECT.y, BG_RECT.w, BG_RECT.h);
drawText(path + "txt1.txt", ctx).catch(error => console.error(error));
export {};

16
src/text/txt1.txt Normal file
View file

@ -0,0 +1,16 @@
Le *Riichi Mahjong* est un jeu qui se joue avec des *tuiles*.
Elles sont similaires aux cartes d'un jeu de Tarot dans la mesure
où elles se divisent en deux catégories:
- Les #ff00ff{familles}
Nous pouvons retrouver dans ce jeu *3* familles distinctes:
- Les *Man*, appelées les #ff00ff{Caractères}
- Les *Pin*, appelées les #ff00ff{Ronds}
- Les *Sou*, appelées les #ff00ff{Bambous}
Comme dans un jeu de cartes, ils sont tous numérotées
de *1* jusqu'à *9*.
- Les #ff00ff{honneurs}
Ils sont séparés selon *2* catégories:
- Les *Dragons*: #ff0000{Rouge}, #ffffff{Blanc} et #00ff00{Vert}
- Les *Vents*: #0000e0{Est}, #0000e0{Sud}, #0000e0{Ouest} et #0000e0{Nord}

18
src/text/txt2.ts Normal file
View file

@ -0,0 +1,18 @@
import { drawText } from "./parse"
const CANVAS_ID = "myTextCanvas";
const BG_RECT = { x: 0, y: 0, w: 800, h: 1050, color: "#007733" };
const canvas = document.getElementById(CANVAS_ID) as HTMLCanvasElement;
const ctx = canvas.getContext("2d") as NonNullable<CanvasRenderingContext2D>;
canvas.width = BG_RECT.w;
canvas.height = BG_RECT.h;
const path = "../src/text/";
ctx.fillStyle = BG_RECT.color;
ctx.fillRect(BG_RECT.x, BG_RECT.y, BG_RECT.w, BG_RECT.h);
drawText(path + "txt2.txt", ctx).catch(error => console.error(error));
export {};

23
src/text/txt2.txt Normal file
View file

@ -0,0 +1,23 @@
Durant une partie, un joueur possède dans sa main un total
de *13 tuiles*.
Lors de son tour, un joueur commence par *récupérer* une
tuile supplémentaire, avant d'en *défausser* une (il peut
s'agir de la même).
~Une main interactive est mise à disposition pour s'entrainer
à cette mécanique~

18
src/text/txt3.ts Normal file
View file

@ -0,0 +1,18 @@
import { drawText } from "./parse"
const CANVAS_ID = "myTextCanvas";
const BG_RECT = { x: 0, y: 0, w: 800, h: 1050, color: "#007733" };
const canvas = document.getElementById(CANVAS_ID) as HTMLCanvasElement;
const ctx = canvas.getContext("2d") as NonNullable<CanvasRenderingContext2D>;
canvas.width = BG_RECT.w;
canvas.height = BG_RECT.h;
const path = "../src/text/";
ctx.fillStyle = BG_RECT.color;
ctx.fillRect(BG_RECT.x, BG_RECT.y, BG_RECT.w, BG_RECT.h);
drawText(path + "txt3.txt", ctx).catch(error => console.error(error));
export {};

24
src/text/txt3.txt Normal file
View file

@ -0,0 +1,24 @@
Dans le but de gagner, un joueur doit réussir à créer une
main avec une forme particulière. en effet, elle doit être
constituée de:
- *4 groupes distincts* constituées de *3 tuiles*
- *1 paire*
~Ci-contre des exemples de groupes valides et non valides~
Nous y distinguons:
- Les #ff00ff{Chii}, correspondant aux *Suites*
- Les #ff00ff{Pon}, correspondant aux *Brelans*
Ainsi, pour gagner, un joueur doit posseder *3 x 4 + 2* tuiles,
soit *14* tuiles au total.
De ce fait, il n'est possible de gagner uniquement lorsqu'une
tuile est récupérée
Lorsque tous ces groupes sont présents, nous dirons que la
main est #ff00ff{Valide}
~De même, il est possible de s'entraîner cette fois à piocher
et défausser des tuiles jusqu'à l'obtention d'une main valide
PS: un message le fera savoir à ce moment là~

18
src/text/txt4.ts Normal file
View file

@ -0,0 +1,18 @@
import { drawText } from "./parse"
const CANVAS_ID = "myTextCanvas";
const BG_RECT = { x: 0, y: 0, w: 800, h: 1050, color: "#007733" };
const canvas = document.getElementById(CANVAS_ID) as HTMLCanvasElement;
const ctx = canvas.getContext("2d") as NonNullable<CanvasRenderingContext2D>;
canvas.width = BG_RECT.w;
canvas.height = BG_RECT.h;
const path = "../src/text/";
ctx.fillStyle = BG_RECT.color;
ctx.fillRect(BG_RECT.x, BG_RECT.y, BG_RECT.w, BG_RECT.h);
drawText(path + "txt4.txt", ctx).catch(error => console.error(error));
export {};

25
src/text/txt4.txt Normal file
View file

@ -0,0 +1,25 @@
Voici votre *première partie* !
Il est temps de mettre en oeuvre tout ce que vous avez appris.
Il est cependant important de noter dorénavant une mécanique
essentielle pour l'obtention de nouvelles tuiles:
- Lorsqu'une personne défausse une tuile permettant à un joueur
de compléter un *brelan*, il peut l'annoncer avec #ff00ff{Pon !} et la
récupérer pour lui
- Lorsque le joueur *précédent* défausse une tuile permettant au
joueur de compléter une *suite*, il peut l'annoncer avec #ff00ff{Chii !} et
de la même manière la récupérer pour lui
#ff0000{Attention !}
Cette action est appelée un #ff00ff{appel}. Ce dernier est *définitif* et est
*visible par tout le monde*
PS: si un joueur veut faire un *Chii* en même temps qu'un autre
veut faire un *Pon*, alors le *Pon* a *toujours* la priorité
~Il est maintenant tant de choisir une tuile à défausser !~

View file

@ -4,7 +4,9 @@ const fs = require('fs');
// Fonction pour détecter automatiquement les fichiers dp*.ts
function getEntryPoints() {
const displayDir = path.resolve(__dirname, 'src', 'display');
const textDir = path.resolve(__dirname, 'src', 'text');
const files = fs.readdirSync(displayDir); // Lire les fichiers du répertoire
const texts = fs.readdirSync(textDir);
const entryPoints = {};
files.forEach((file) => {
@ -13,6 +15,12 @@ function getEntryPoints() {
entryPoints[name] = path.join(displayDir, file); // Chemin complet du fichier
}
});
texts.forEach((file) => {
if (file.startsWith('txt') && file.endsWith('.ts')) {
const name = path.basename(file, '.ts');
entryPoints[name] = path.join(textDir, file);
}
});
return entryPoints;
}