A Starknight hacked an old slot machine and turned it into something strange?! I heard that you win a secret message if you manage to get triple cherries, but...
Last updated
This challenge gives us a slot machine, and our goal is to make all the slots become cherries. The main logic of the program is in script.js:
let slotSymbols = [];let m =0; // gets initialised to 32768let awascii32 ='awjelyhosiumpcntbdfgr.,!{}_/;CTF';let spinMode =0; // either 0, 1 or 2let spinCounts = [0,0,0]; // how much we've spun in each mode. reset by reset()let slotIndices = [0,0,0]; // the current index of the character being displayedlet slotSpins = [0,0,0]; // depends on spinModelet ciphertextIndex =0; // modified by change()fetch('static/slotsymbols.txt').then(response =>response.text()).then(text => { slotSymbols =text.split(/(?:)/u); m =slotSymbols.length;}).then(() => {playCoin(0);reset();});functionchange() { ciphertextIndex = (ciphertextIndex +1) %3;reset();}functionreset() {if (ciphertextIndex ==0) slotIndices = [10992,30978,12520];elseif (ciphertextIndex ==1) slotIndices = [30983,7390,481];elseif (ciphertextIndex ==2) slotIndices = [25974,26744,9122]; spinCounts = [0,0,0];updatePlaintextDisplay();doSpinCleanup();}functionspin() {constbuttons=document.querySelectorAll('.button');buttons.forEach((b) =>b.disabled =true); spinCounts[spinMode] +=1;updateModeDisplay();updatePlaintextDisplay();doSpinAnimation();for (let columnIndex =0; columnIndex <3; columnIndex++) { }setTimeout(() => {doSpinCleanup();buttons.forEach((b) =>b.disabled =false); },1)}functionplayCoin(n){ spinMode = n;if (n ==0) slotSpins = [ 19,22,19];elseif (n ==1) slotSpins = [ 32,27,29];elseif (n ==2) slotSpins = [347,349,353];updateModeDisplay();}functionupdatePlaintextDisplay() {letdecToAwascii32= (x) => {returnawascii32.charAt(x %32) +awascii32.charAt((x >>5) %32) +awascii32.charAt((x >>10) %32)};document.getElementById('spinCount0').innerHTML =decToAwascii32(spinCounts[0]);document.getElementById('spinCount1').innerHTML =decToAwascii32(spinCounts[1]);document.getElementById('spinCount2').innerHTML =decToAwascii32(spinCounts[2]);}/** * * NOTE: Everything below this point is purely visual and not needed to solve the challenge. * */functioncreateSymbolElement(symbol) {constdiv=document.createElement('div');div.classList.add('symbol');div.textContent = symbol;return div;}functiondoSpinAnimation() {constslots=document.querySelectorAll('.slot');slots.forEach((slot, columnIndex) => {constsymbols=slot.querySelector('.symbols');symbols.style.transition ='none';symbols.style.top ='0';symbols.replaceChildren();for (let i = slotIndices[columnIndex]; i <= slotIndices[columnIndex] + slotSpins[columnIndex]; i++) {symbols.appendChild(createSymbolElement(slotSymbols[i % m])) }symbols.offsetHeight;symbols.style.transition ='';constsymbolHeight=symbols.querySelector('.symbol')?.clientHeight;constoffset=-(symbols.childElementCount -1) * symbolHeight;symbols.style.top =`${offset}px`; });}functiondoSpinCleanup() {constslots=document.querySelectorAll('.slot');slots.forEach((slot, columnIndex) => {constsymbols=slot.querySelector('.symbols');symbols.style.transition ='none';symbols.style.top ='0';symbols.replaceChildren(createSymbolElement(slotSymbols[slotIndices[columnIndex]]));symbols.offsetHeight;symbols.style.transition =''; }); }functionupdateModeDisplay() {document.getElementById('spinMode').innerHTML = spinMode;}
When the script first runs, m is set to slotSymbols.length, which is the number of symbols available and is always 32768.
Initially, before spinning, the characters we are shown depends on cipherTextIndex. Its value can be 0, 1, or 2. Depending on its value, reset() gives us a different combination of initial indexes to use in slotIndices.
When we spin(), the change of indices also depends on slotSpins. slotSpins is set by the playCoin() function. We can play with either 0, 1, or 2 coins, and each gives us a different array slotSpins.
The equation determining the next indices is given by this line of code:
slotIndices[columnIndex] = (slotIndices[columnIndex] + slotSpins[columnIndex]) % m;
Upon inspecting slotsymbols.txt, we can see that the cherry is at index 0 since it is the first symbol in the file. So our objective is to make slotIndices[0] = 0, slotIndices[1] = 0 and slotIndices[2] = 0.
Let's formulate the problem. For each of the 3 cipherTextIndex values, we can spin with 0 coins i times, spin with 1 coin j times, and spin with 2 coins k times. Hence our equations are:
For each equation, we can solve for i, j and k to find out how many times to roll in each coin state to get 3 cherries.
We can guess that when we get 3 cherries, updatePlaintextDisplay() will make the spinCount0, spinCount1 and spinCount2 elements show part of the flag.
Hence I used z3 to solve the above constraints, then input the individual i j k values into decToAwascii32 to get the characters of the flag.