Šachy vylepšení logiky + přidání možnosti hrát online
This commit is contained in:
parent
97349ef57b
commit
eb2cff2f54
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "denim_3001",
|
"name": "denim_3001",
|
||||||
"version": "3001.61.3",
|
"version": "3001.62.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "denim_3001",
|
"name": "denim_3001",
|
||||||
"version": "3001.61.2",
|
"version": "3001.62.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@discordjs/voice": "^0.17.0",
|
"@discordjs/voice": "^0.17.0",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "denim_3001",
|
"name": "denim_3001",
|
||||||
"version": "3001.61.3",
|
"version": "3001.62.0",
|
||||||
"description": "Toto je velmi kvalitní bot.",
|
"description": "Toto je velmi kvalitní bot.",
|
||||||
"repository": {
|
"repository": {
|
||||||
"url": "https://github.com/Histmy/Denim-Bot/"
|
"url": "https://github.com/Histmy/Denim-Bot/"
|
||||||
|
|||||||
40
res/sachy/game.html
Normal file
40
res/sachy/game.html
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="cs">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Hra - $domena</title>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 2em;
|
||||||
|
height: 2em;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nic {
|
||||||
|
width: 2em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>Hra</h1>
|
||||||
|
|
||||||
|
<p>$pecko</p>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
$hra
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@ -98,7 +98,7 @@ function jeCheck(barva: Hra["hraje"], deska: Deska) {
|
|||||||
// od pawnů
|
// od pawnů
|
||||||
[7, 9].forEach(i => {
|
[7, 9].forEach(i => {
|
||||||
const pis = deska[index - i];
|
const pis = deska[index - i];
|
||||||
if (pis?.typ == "pawn" && pis.barva != barva) check = true;
|
if (pis?.typ == "pawn" && pocetKeStrane[index][i == 7 ? 1 : 3] > 0 && pis.barva != barva) check = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
// od králika
|
// od králika
|
||||||
@ -173,6 +173,13 @@ function tahyProPawny(index: number, deska: Deska) {
|
|||||||
if (index % 8 != 7 && deska[index - 7] && deska[index - 7]!.barva != barva)
|
if (index % 8 != 7 && deska[index - 7] && deska[index - 7]!.barva != barva)
|
||||||
tahy.push(index - 7);
|
tahy.push(index - 7);
|
||||||
|
|
||||||
|
// en croassant
|
||||||
|
if (pocetKeStrane[index][3] > 0 && deska[index - 1]?.enPassantovatelna)
|
||||||
|
tahy.push(index - 9);
|
||||||
|
|
||||||
|
if (pocetKeStrane[index][1] > 0 && deska[index + 1]?.enPassantovatelna)
|
||||||
|
tahy.push(index - 7);
|
||||||
|
|
||||||
// Blokáda
|
// Blokáda
|
||||||
if (deska[index - 8])
|
if (deska[index - 8])
|
||||||
return tahy;
|
return tahy;
|
||||||
@ -183,13 +190,6 @@ function tahyProPawny(index: number, deska: Deska) {
|
|||||||
if (deska[index]?.netahnuta && !deska[index - 16])
|
if (deska[index]?.netahnuta && !deska[index - 16])
|
||||||
tahy.push(index - 16);
|
tahy.push(index - 16);
|
||||||
|
|
||||||
// en croassant
|
|
||||||
if (deska[index - 1]?.enPassantovatelna)
|
|
||||||
tahy.push(index - 9);
|
|
||||||
|
|
||||||
if (deska[index + 1]?.enPassantovatelna)
|
|
||||||
tahy.push(index - 7);
|
|
||||||
|
|
||||||
return tahy;
|
return tahy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -218,6 +218,8 @@ function tahyProKrale(index: number, deska: Deska) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Math.abs(i) == 3) continue;
|
||||||
|
|
||||||
const novaDeska = [...deska];
|
const novaDeska = [...deska];
|
||||||
novaDeska[index + i] = deska[index];
|
novaDeska[index + i] = deska[index];
|
||||||
novaDeska[index] = undefined;
|
novaDeska[index] = undefined;
|
||||||
@ -302,6 +304,45 @@ function renderHra(hra: Hra, konec?: true) {
|
|||||||
const deska = [...hra.deska];
|
const deska = [...hra.deska];
|
||||||
const vybranejPis = hra.vybranejPis;
|
const vybranejPis = hra.vybranejPis;
|
||||||
|
|
||||||
|
const policka: Policko[] = [];
|
||||||
|
|
||||||
|
hra.tahy = [];
|
||||||
|
|
||||||
|
if (typeof vybranejPis == "number") hra.tahy = legalniTahy(vybranejPis, deska);
|
||||||
|
|
||||||
|
for (let i = 0; i < 64; i++) {
|
||||||
|
|
||||||
|
const figurka = deska[i];
|
||||||
|
const jeTah = hra.tahy.includes(i);
|
||||||
|
|
||||||
|
const cernyPozadi = (Math.floor(i / 8) + (i % 8)) % 2;
|
||||||
|
|
||||||
|
if (!figurka) {
|
||||||
|
|
||||||
|
policka.push(jeTah
|
||||||
|
? { typ: "tahnutelne", emoutId: cernyPozadi ? "1066376051422404628" : "1066376343807336488" }
|
||||||
|
: { typ: "prazdne", barva: cernyPozadi ? "cerna" : "bila" }
|
||||||
|
);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
let klic = (cernyPozadi ? "g" : "w") + (figurka.barva == "bila" ? "w" : "b") + figurka.typ;
|
||||||
|
if (jeTah) klic += "t";
|
||||||
|
else if (figurka.typ == "king" && figurka.barva == hra.hraje && jeCheck(figurka.barva, deska)) klic += "c";
|
||||||
|
const emoutId = fokinLookupTable[klic];
|
||||||
|
|
||||||
|
const tahnutelny = !konec && figurka.barva == hra.hraje || jeTah;
|
||||||
|
policka.push({ emoutId, typ: tahnutelny ? "tahnutelne" : "figurka" });
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return policka;
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateGameEmbed(hra: Hra, konec?: true) {
|
||||||
|
|
||||||
const embed: APIEmbed = {
|
const embed: APIEmbed = {
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
@ -317,51 +358,64 @@ function renderHra(hra: Hra, konec?: true) {
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
hra.tahy = [];
|
const policka = renderHra(hra, konec);
|
||||||
|
|
||||||
if (typeof vybranejPis == "number") hra.tahy = legalniTahy(vybranejPis, deska);
|
|
||||||
|
|
||||||
for (let i = 0; i < 64; i++) {
|
for (let i = 0; i < 64; i++) {
|
||||||
const figurka = deska[i];
|
const policko = policka[i];
|
||||||
const klikanec = klikance[i];
|
const field = embed.fields![(i % 8) < 4 ? 0 : 1];
|
||||||
|
|
||||||
const prvniDuhy = (i % 8) < 4 ? 0 : 1;
|
|
||||||
const field = embed.fields![prvniDuhy];
|
|
||||||
|
|
||||||
const cernyPozadi = (Math.floor(i / 8) + (i % 8)) % 2;
|
|
||||||
|
|
||||||
if (!figurka) {
|
|
||||||
|
|
||||||
field.value += hra.tahy.includes(i)
|
|
||||||
? (cernyPozadi ? `[<:h:1066376051422404628>](http://${sachyDomena}/${klikanec})` : `[<:h:1066376343807336488>](http://${sachyDomena}/${klikanec})`)
|
|
||||||
: (cernyPozadi ? "🟩" : "⬜");
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
let klic = (cernyPozadi ? "g" : "w") + (figurka.barva == "bila" ? "w" : "b") + figurka.typ;
|
|
||||||
if (hra.tahy.includes(i)) klic += "t";
|
|
||||||
if (figurka.typ == "king" && figurka.barva == hra.hraje && jeCheck(figurka.barva, deska)) klic += "c";
|
|
||||||
const emout = fokinLookupTable[klic];
|
|
||||||
const figurkaStr = `<:h:${emout}>`;
|
|
||||||
|
|
||||||
if (!konec && figurka.barva == hra.hraje || hra.tahy.includes(i)) {
|
|
||||||
field.value += `[${figurkaStr}](http://${sachyDomena}/${klikanec})`;
|
|
||||||
} else {
|
|
||||||
field.value += figurkaStr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (policko.typ == "prazdne")
|
||||||
|
field.value += policko.barva == "bila" ? "⬜" : "🟩";
|
||||||
|
else {
|
||||||
|
const emout = `<:h:${policko.emoutId}>`;
|
||||||
|
field.value += policko.typ == "figurka" ? emout : `[${emout}](http://${sachyDomena}/${klikance[i]})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i % 8 == 3 || i % 8 == 7) field.value += "\n";
|
if ((i % 8 == 3 || i % 8 == 7)) field.value += "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (embed.fields![0].value.length > 1024 || embed.fields![1].value.length > 1024) {
|
||||||
|
embed.fields = [
|
||||||
|
{
|
||||||
|
name: "a je to pici!",
|
||||||
|
value: `Tuta pozice by vobsahovala moc vodkazu a diky pice diskordu se teda neda vykreslit. Tuten tah budes muset bohuzel vodehrat [na webu](http://${sachyDomena}/play).`
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
return embed;
|
return embed;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emiter.on("render", (hrac, respond) => {
|
||||||
|
const gameID = hraci.get(hrac)!;
|
||||||
|
if (!gameID) return respond("Však vůbec nehraješ ty magore", true);
|
||||||
|
const hra = hry.get(gameID)!;
|
||||||
|
const hraje = hra.hraje == (hra.bila == hrac ? "bila" : "cerna");
|
||||||
|
|
||||||
|
const policka = renderHra(hra);
|
||||||
|
let html = "<tr>";
|
||||||
|
|
||||||
|
|
||||||
|
for (let i = 0; i < 64; i++) {
|
||||||
|
const policko = policka[i];
|
||||||
|
|
||||||
|
if (policko.typ == "prazdne")
|
||||||
|
html += policko.barva == "bila" ? `<td><img class="nic" src="https://cdn.jsdelivr.net/gh/twitter/twemoji@latest/assets/svg/2b1c.svg"></td>` : `<td><img class="nic" src="https://cdn.jsdelivr.net/gh/twitter/twemoji@latest/assets/svg/1f7e9.svg"></td>`;
|
||||||
|
else {
|
||||||
|
const obrazek = `<img src="https://cdn.discordapp.com/emojis/${policko.emoutId}.webp">`;
|
||||||
|
html += (policko.typ == "figurka" || !hraje) ? `<td>${obrazek}</td>` : `<td><a href="http://${sachyDomena}/play/${klikance[i]}">${obrazek}</a></td>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i % 8 == 7) html += "</tr>";
|
||||||
|
}
|
||||||
|
|
||||||
|
respond(html);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
function konec(mes: Message, hra: Hra, duvod: string) {
|
function konec(mes: Message, hra: Hra, duvod: string) {
|
||||||
mes.edit({ content: `hra zkoncila ${duvod}`, embeds: [renderHra(hra, true)] });
|
mes.edit({ content: `hra zkoncila ${duvod}`, embeds: [generateGameEmbed(hra, true)] });
|
||||||
|
|
||||||
const gameID = hra.id;
|
const gameID = hra.id;
|
||||||
|
|
||||||
@ -399,7 +453,7 @@ function prekreslitHru(hra: Hra) {
|
|||||||
if (pat)
|
if (pat)
|
||||||
return konec(mes, hra, `achylova sytuace`);
|
return konec(mes, hra, `achylova sytuace`);
|
||||||
|
|
||||||
mes.edit({ content: "", embeds: [renderHra(hra)] });
|
mes.edit({ content: "", embeds: [generateGameEmbed(hra)] });
|
||||||
}
|
}
|
||||||
|
|
||||||
emiter.on("tah", (hrac, policko, respond, promo) => {
|
emiter.on("tah", (hrac, policko, respond, promo) => {
|
||||||
@ -412,7 +466,7 @@ emiter.on("tah", (hrac, policko, respond, promo) => {
|
|||||||
|
|
||||||
const index = klikance.findIndex(e => e == policko);
|
const index = klikance.findIndex(e => e == policko);
|
||||||
|
|
||||||
if (typeof index != "number") return respond("Co to meleš za hovna?");
|
if (index == -1) return respond("Co to meleš za hovna?");
|
||||||
|
|
||||||
// Kliknul na stejnej pis
|
// Kliknul na stejnej pis
|
||||||
if (hra.vybranejPis == index) {
|
if (hra.vybranejPis == index) {
|
||||||
@ -485,7 +539,7 @@ const exp: Modul = {
|
|||||||
hraci.set(mes.author.id, nextGameID);
|
hraci.set(mes.author.id, nextGameID);
|
||||||
hraci.set(druhej, nextGameID);
|
hraci.set(druhej, nextGameID);
|
||||||
|
|
||||||
message.edit({ content: "", embeds: [renderHra(hra)] });
|
message.edit({ content: "", embeds: [generateGameEmbed(hra)] });
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -510,7 +564,7 @@ type Hra = {
|
|||||||
bila: string;
|
bila: string;
|
||||||
cerna: string;
|
cerna: string;
|
||||||
deska: Deska;
|
deska: Deska;
|
||||||
hraje: "bila" | "cerna";
|
hraje: Figurka["barva"];
|
||||||
tahy: number[];
|
tahy: number[];
|
||||||
vybranejPis?: number;
|
vybranejPis?: number;
|
||||||
message: Message;
|
message: Message;
|
||||||
@ -524,3 +578,11 @@ type Figurka = {
|
|||||||
netahnuta: boolean;
|
netahnuta: boolean;
|
||||||
enPassantovatelna: boolean;
|
enPassantovatelna: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type Policko = {
|
||||||
|
typ: "prazdne";
|
||||||
|
barva: Figurka["barva"];
|
||||||
|
} | {
|
||||||
|
typ: "figurka" | "tahnutelne";
|
||||||
|
emoutId: string;
|
||||||
|
};
|
||||||
|
|||||||
@ -14,11 +14,13 @@ const indexStranka = readFileSync(`${basePath}/index.html`).toString();
|
|||||||
const tahStranka = readFileSync(`${basePath}/tah.html`).toString();
|
const tahStranka = readFileSync(`${basePath}/tah.html`).toString();
|
||||||
const promoStranka = readFileSync(`${basePath}/promotion.html`).toString();
|
const promoStranka = readFileSync(`${basePath}/promotion.html`).toString();
|
||||||
const chybaStranka = readFileSync(`${basePath}/error.html`).toString();
|
const chybaStranka = readFileSync(`${basePath}/error.html`).toString();
|
||||||
|
const hraStranka = readFileSync(`${basePath}/game.html`).toString();
|
||||||
|
|
||||||
export const sachyDomena = process.env.sachyDomena ?? "šach.ml";
|
export const sachyDomena = process.env.sachyDomena ?? "šach.ml";
|
||||||
|
|
||||||
interface Eventy {
|
interface Eventy {
|
||||||
tah: (playerId: string, square: string, verify: (err?: string) => void, promotionType?: string) => void;
|
tah: (playerId: string, square: string, verify: (err?: string) => void, promotionType?: string) => void;
|
||||||
|
render: (playerId: string, send: (html: string, err?: true) => void) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const emiter = new TypedEmitter<Eventy>();
|
export const emiter = new TypedEmitter<Eventy>();
|
||||||
@ -101,9 +103,9 @@ function loginErr(res: ServerResponse) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function overeni(url: string, session: Session, res: ServerResponse) {
|
async function overeni(url: URL, session: Session, res: ServerResponse) {
|
||||||
|
|
||||||
const code = (new URL(url, "h:/")).searchParams.get("code");
|
const code = url.searchParams.get("code");
|
||||||
const data = await fetch("https://discord.com/api/v10/oauth2/token", { method: "post", body: `client_id=1064269692165963826&client_secret=8HHKODmb1HTLWoJGVyoinSU_9323dEla&grant_type=authorization_code&code=${code}&redirect_uri=http%3A%2F%2F${encodeURIComponent(sachyDomena)}%2Foauth`, headers: { "Content-type": "application/x-www-form-urlencoded" } })
|
const data = await fetch("https://discord.com/api/v10/oauth2/token", { method: "post", body: `client_id=1064269692165963826&client_secret=8HHKODmb1HTLWoJGVyoinSU_9323dEla&grant_type=authorization_code&code=${code}&redirect_uri=http%3A%2F%2F${encodeURIComponent(sachyDomena)}%2Foauth`, headers: { "Content-type": "application/x-www-form-urlencoded" } })
|
||||||
.then(r => r.json())
|
.then(r => r.json())
|
||||||
.catch(err => log("sachy jednotka:", err));
|
.catch(err => log("sachy jednotka:", err));
|
||||||
@ -146,16 +148,48 @@ function validateMove(res: ServerResponse, session: Session, url: string) {
|
|||||||
emiter.emit("tah", session.discordId!, pismenko, overeni, promoNa);
|
emiter.emit("tah", session.discordId!, pismenko, overeni, promoNa);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderHra(url: URL, session: Session, res: ServerResponse) {
|
||||||
|
if (!session.logedIn) return redirect(res, `/login?redirect=/play${url.search}`);
|
||||||
|
|
||||||
|
let error: string | undefined = undefined;
|
||||||
|
|
||||||
|
function serveHTML(html: string, err?: true) {
|
||||||
|
const vec = hraStranka
|
||||||
|
.replace("$domena", sachyDomena);
|
||||||
|
|
||||||
|
let errForPrint = error ?? err;
|
||||||
|
if (errForPrint) return res.end(vec.replace("$pecko", html).replace("$hra", ""));
|
||||||
|
|
||||||
|
res.end(vec.replace("$hra", html).replace("$pecko", ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
const tah = url.pathname.match(/\/play\/(.)$/);
|
||||||
|
if (!tah) return emiter.emit("render", session.discordId!, serveHTML);
|
||||||
|
const promoNa = url.search[1];
|
||||||
|
|
||||||
|
function handlePromote(err?: string) {
|
||||||
|
if (err == "--promote--")
|
||||||
|
return res.end(promoStranka.replace("$domena", sachyDomena));
|
||||||
|
|
||||||
|
error = err;
|
||||||
|
emiter.emit("render", session.discordId!, serveHTML);
|
||||||
|
}
|
||||||
|
emiter.emit("tah", session.discordId!, tah[1], handlePromote, promoNa);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
const server = createServer((req, res) => {
|
const server = createServer((req, res) => {
|
||||||
|
|
||||||
const session = startSession(req, res);
|
const session = startSession(req, res);
|
||||||
const url = new URL(req.url!, `http://${sachyDomena}`);
|
const url = new URL(req.url!, `http://${sachyDomena}`);
|
||||||
|
|
||||||
|
// log(url.pathname, url.search, url.searchParams, req.url);
|
||||||
|
|
||||||
// Zpracování tahu
|
// Zpracování tahu
|
||||||
if (url.pathname.length == 2 || url.pathname.length == 4) return validateMove(res, session, req.url!);
|
if (url.pathname.length == 2 || url.pathname.length == 4) return validateMove(res, session, req.url!);
|
||||||
|
|
||||||
// Oauth
|
// Hra v prohlížeči
|
||||||
if (req.url?.startsWith("/oauth")) return overeni(req.url, session, res);
|
if (url.pathname.startsWith("/play")) return renderHra(url, session, res);
|
||||||
|
|
||||||
// Jinak
|
// Jinak
|
||||||
switch (url.pathname) {
|
switch (url.pathname) {
|
||||||
@ -172,6 +206,9 @@ const server = createServer((req, res) => {
|
|||||||
return login(session, res);
|
return login(session, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "/oauth":
|
||||||
|
return overeni(url, session, res);
|
||||||
|
|
||||||
case "/logout":
|
case "/logout":
|
||||||
return logout(session, res);
|
return logout(session, res);
|
||||||
|
|
||||||
|
|||||||
@ -55,7 +55,7 @@ const statusTable: SRecord<number> = {
|
|||||||
export function statusToDLOG3(status: ClientPresenceStatusData | null) {
|
export function statusToDLOG3(status: ClientPresenceStatusData | null) {
|
||||||
if (!status) return "-";
|
if (!status) return "-";
|
||||||
|
|
||||||
let tovje = [];
|
const tovje = [];
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(status)) {
|
for (const [key, value] of Object.entries(status)) {
|
||||||
const platform = platformTable[key] ?? key;
|
const platform = platformTable[key] ?? key;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user