Files
LerningCSW/MainPage/younes/Streichholzreatsel.js
2026-01-21 14:24:29 +01:00

299 lines
7.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const SEG = { a:0, b:1, c:2, d:3, e:4, f:5, g:6 };
const segNames = ["a","b","c","d","e","f","g"];
function maskFromSegments(list){
let m = 0;
for(const s of list) m |= (1 << SEG[s]);
return m;
}
const DIGIT_MASK = [
maskFromSegments(["a","b","c","d","e","f"]),
maskFromSegments(["b","c"]),
maskFromSegments(["a","b","d","e","g"]),
maskFromSegments(["a","b","c","d","g"]),
maskFromSegments(["b","c","f","g"]),
maskFromSegments(["a","c","d","f","g"]),
maskFromSegments(["a","c","d","e","f","g"]),
maskFromSegments(["a","b","c"]),
maskFromSegments(["a","b","c","d","e","f","g"]),
maskFromSegments(["a","b","c","d","f","g"])
];
const MASK_TO_DIGIT = new Map(DIGIT_MASK.map((m,d)=>[m,d]));
function removableTargetsFromDigit(d){
const start = DIGIT_MASK[d];
const res = [];
for(let t=0;t<=9;t++){
const target = DIGIT_MASK[t];
if((target & start) === target){
const removed = popcount(start ^ target);
res.push({to:t, removed});
}
}
return res;
}
function popcount(x){
x = x >>> 0;
let c = 0;
while(x){ x &= (x-1); c++; }
return c;
}
function randInt(min, max){ // inclusive
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function pick(arr){ return arr[randInt(0, arr.length-1)]; }
let level = 1;
let targetRemove = 2;
let current = null;
let solution = null;
let removedSoFar = 0;
let removedSet = new Set();
const elEq = document.getElementById("equation");
const elRemovedGrid = document.getElementById("removedGrid");
const elRemovedCount = document.getElementById("removedCount");
const elPileCount = document.getElementById("pileCount");
const elLvl = document.getElementById("lvl");
const elTarget = document.getElementById("target");
const elGoalN = document.getElementById("goalN");
const elTruthDot = document.getElementById("truthDot");
const elTruthText = document.getElementById("truthText");
const elHint = document.getElementById("hint");
document.getElementById("btnNew").addEventListener("click", () => {
level++;
generateLevel();
});
document.getElementById("btnReset").addEventListener("click", () => {
resetPlayState();
renderEquation();
updateTruthUI();
});
function segmentsFromMask(mask){
const set = new Set();
for(let i=0;i<7;i++){
if(mask & (1<<i)) set.add(segNames[i]);
}
return set;
}
function displayedMaskForDigit(digitValue, digitIndex){
let mask = DIGIT_MASK[digitValue];
for(const s of segNames){
const key = digitIndex + "-" + s;
if(removedSet.has(key)){
mask &= ~(1 << SEG[s]);
}
}
return mask;
}
function displayedDigitValue(digitValue, digitIndex){
const mask = displayedMaskForDigit(digitValue, digitIndex);
return MASK_TO_DIGIT.has(mask) ? MASK_TO_DIGIT.get(mask) : null;
}
function equationIsTrue(){
const a = displayedDigitValue(current.A, 0);
const b = displayedDigitValue(current.B, 1);
const c = displayedDigitValue(current.C, 2);
if(a === null || b === null || c === null) return false;
return (a + b) === c;
}
function updateTruthUI(){
const ok = equationIsTrue();
elTruthDot.classList.toggle("ok", ok);
elTruthText.textContent = ok ? "Equation is TRUE" : "Equation is FALSE";
}
function resetPlayState(){
removedSet.clear();
removedSoFar = 0;
elRemovedGrid.innerHTML = "";
syncRemovedCounts();
}
function syncRemovedCounts(){
elRemovedCount.textContent = String(removedSoFar);
elPileCount.textContent = String(removedSoFar);
}
function renderDigit(digitValue, digitIndex, color){
const digit = document.createElement("div");
digit.className = "digit";
const baseMask = DIGIT_MASK[digitValue];
const baseSegs = segmentsFromMask(baseMask);
for(const s of segNames){
if(!baseSegs.has(s)) continue;
const seg = document.createElement("div");
seg.className = "seg " + s;
seg.style.background = color;
const key = digitIndex + "-" + s;
if(removedSet.has(key)) seg.classList.add("removed");
seg.addEventListener("click", () => {
if(removedSet.has(key)) return;
if(removedSoFar >= targetRemove) return;
removedSet.add(key);
removedSoFar++;
seg.classList.add("removed");
const clone = document.createElement("div");
clone.className = "removedSeg";
clone.style.background = color;
elRemovedGrid.appendChild(clone);
syncRemovedCounts();
updateTruthUI();
if(removedSoFar === targetRemove){
if(equationIsTrue()){
elHint.innerHTML = "<b>Solved!</b> You removed exactly the target and made the equation true. Click <b>New level</b>.";
} else {
elHint.innerHTML = " <b>Not solved.</b> You used all removals but the equation isnt true. Click <b>Reset level</b> to try again.";
}
}
});
digit.appendChild(seg);
}
return digit;
}
function renderEquation(){
elEq.innerHTML = "";
const colors = [
"linear-gradient(180deg,#ff6b6b,#d64545)",
"linear-gradient(180deg,#6bcBff,#3a7bd5)",
"linear-gradient(180deg,#6bffb3,#1fae63)"
];
const g1 = document.createElement("div");
g1.className = "group";
g1.appendChild(renderDigit(current.A, 0, colors[0]));
const plus = document.createElement("div");
plus.className = "symbol";
plus.textContent = "+";
const g2 = document.createElement("div");
g2.className = "group";
g2.appendChild(renderDigit(current.B, 1, colors[1]));
const eq = document.createElement("div");
eq.className = "symbol";
eq.textContent = "=";
const g3 = document.createElement("div");
g3.className = "group";
g3.appendChild(renderDigit(current.C, 2, colors[2]));
elEq.appendChild(g1);
elEq.appendChild(plus);
elEq.appendChild(g2);
elEq.appendChild(eq);
elEq.appendChild(g3);
updateTruthUI();
}
function generateLevel(){
resetPlayState();
targetRemove = Math.min(2 + Math.floor(Math.log2(level + 1)), 6);
let tries = 0;
while(true){
tries++;
if(tries > 5000){
targetRemove = Math.max(2, targetRemove - 1);
tries = 0;
}
const As = randInt(0, 9);
const Bs = randInt(0, 9);
const Cs = As + Bs;
if(Cs < 0 || Cs > 9) continue;
const Achoices = superDigits(As);
const Bchoices = superDigits(Bs);
const Cchoices = superDigits(Cs);
const Ashow = pick(Achoices);
const Bshow = pick(Bchoices);
const Cshow = pick(Cchoices);
const need =
popcount(DIGIT_MASK[Ashow] ^ DIGIT_MASK[As]) +
popcount(DIGIT_MASK[Bshow] ^ DIGIT_MASK[Bs]) +
popcount(DIGIT_MASK[Cshow] ^ DIGIT_MASK[Cs]);
if(need !== targetRemove) continue;
const shownTrue = (Ashow + Bshow) === Cshow;
if(shownTrue) continue;
solution = { A: As, B: Bs, C: Cs };
current = { A: Ashow, B: Bshow, C: Cshow };
break;
}
elLvl.textContent = String(level);
elTarget.textContent = String(targetRemove);
elGoalN.textContent = String(targetRemove);
elHint.innerHTML =
`Level <b>${level}</b>: Make the equation true by removing <b>${targetRemove}</b> match(es). ` +
`You can only remove sticks (click them).`;
renderEquation();
syncRemovedCounts();
updateTruthUI();
}
function superDigits(baseDigit){
const base = DIGIT_MASK[baseDigit];
const res = [];
for(let d=0; d<=9; d++){
const m = DIGIT_MASK[d];
if((m & base) === base){
res.push(d);
}
}
return res;
}
generateLevel();