Last active
February 26, 2021 18:30
-
-
Save derekmc/68b5698944ee1e02b1eeade27ba231bc to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<script src="./src/jszip.min.js"></script> | |
<script src="./src/FileSaver.min.js"></script> | |
<script> | |
// goto targets are capitalized | |
// contemporary programming make the mistake of being easy to debug, not easy to write. | |
// debugging is always hard, deal with it. | |
// | |
// So linguistic "decoupling" is more important, and easier, than "runtime" decoupling, | |
// runtime "decoupling", actually leads to linguistic "coupling", ie interdependence | |
// semantically between the different parts of the program. | |
// | |
// Making debugging easy is trying to control the future, which makes no sense, | |
// and is very hard on top. | |
// Runtime decoupling, is inherently impossible, so it just makes programs very hard to write. | |
// | |
window.addEventListener("load", () => goto(WAR)); | |
//window.addEventListener("load", () => { codeoutput.ap document.documentElement.outerHTML; }); | |
// player decks and discards | |
let DELAY = 0.8; | |
let MINDELAY = 0.012; | |
let D1, D2, TABLE, ROUND; | |
function rank(x){ | |
let r = (x%13) + 1; | |
if(r == 1) r = 14; | |
return r; | |
} | |
function card(x){ | |
let r = rank(x); | |
let suit = Math.floor(x/13); | |
if(r > 10){ | |
r = ["Jack", "Queen", "King", "Ace"][r - 11]; } | |
suit = ["Clubs", "Spades", "Hearts", "Diamonds"][suit]; | |
return `${r} of ${suit}`; | |
} | |
function deck(){ | |
return [...Array(52).keys()]; | |
} | |
function shuffle(d){ | |
if(!d) d=deck(); | |
for(let i=0; i<d.length; ++i){ | |
let j = i + Math.floor((d.length-i) * Math.random()); | |
[d[i], d[j]] = [d[j], d[i]]; | |
} | |
return d; | |
} | |
function draw(d,n,result){ | |
if(!d) d=deck(); | |
if(!n) n = 1; | |
if(!result) result = []; | |
n = Math.min(n, d.length); | |
for(let i=0; i<n; ++i){ | |
result.push(d.shift()); } | |
return result; | |
} | |
function ShowCounts(next){ | |
return next; | |
} | |
function WAR(){ | |
D1 = shuffle(); | |
D2 = draw(D1, 26); | |
console.log(D1, D2); | |
TABLE = []; | |
ROUND = 1; | |
disp(`Welcome to War!`); | |
more(); | |
return WAIT(ANNOUNCE); | |
} | |
function WAIT(next){ | |
if(DELAY == 0) return next; | |
return ()=> { | |
let handlers = []; | |
more(`Press [Enter] or click [ok] to continue.`); | |
wait(handlers, document.getElementById("okaybutton"), 'mousedown', null, next); | |
wait(handlers, document.body, 'keydown', (e)=>(e.keyCode == 13), next); | |
return null; | |
} | |
} | |
function ANNOUNCE(){ | |
disp(`Player 1: ${D1.length} cards`); | |
more(`Player 2: ${D2.length} cards`); | |
more(); | |
more(`Round ${ROUND++}. . .`); | |
return sleep(DELAY, ()=>{ | |
more("Fight!"); | |
return sleep(DELAY, FIGHT); }) | |
} | |
function FIGHT(){ | |
more(); | |
if(D1.length == 0 || D2.length == 0) return END; | |
let a = D1.shift(); | |
let b = D2.shift(); | |
TABLE.push(a); | |
TABLE.push(b); | |
more(` === ${card(a)} ===`) | |
more("Vs") | |
more(` === ${card(b)} ===`); | |
more(); | |
return sleep(3*DELAY, ()=>{ | |
let x = rank(a); | |
let y = rank(b); | |
if(x == y){ | |
return TIE; } | |
let winner = (x > y)? D1 : D2; | |
more(`Player ${x>y? 1 : 2} wins ${TABLE.length} cards.`); | |
more(); | |
draw(shuffle(TABLE), TABLE.length, winner); | |
return WAIT(ANNOUNCE); | |
}) | |
} | |
function TIE(){ | |
more("Round is tied."); | |
more(); | |
more("Each player draws 3 more facedown cards."); | |
draw(D1, 3, TABLE); | |
draw(D2, 3, TABLE); | |
if(D1.length == 0 || D2.length == 0){ | |
return END; } | |
more(); | |
return WAIT(ANNOUNCE); | |
} | |
function END(){ | |
if(D1.length > D2.length){ | |
disp("Player 1 Wins!"); } | |
else{ | |
disp("Player 2 Wins!"); } | |
more(`After ${ROUND} rounds.`); | |
if(DELAY == 0 && Math.random() < 0.18){ | |
ToggleAuto(); } | |
return RESTART; | |
} | |
function RESTART(){ | |
return sleep(__DELAY*4, ()=>{ | |
more("Restarting ..."); | |
sleep(__DELAY*4, WAR)}) | |
} | |
function goto(target){ // targets return the next function to run. | |
while(target){ | |
target = target(); } | |
} | |
function wait(handlers, target, name, test, after){ | |
if(!handlers) handlers = []; | |
let handler = function(evt){ | |
if(test && !test(evt)) return; | |
for(let tuple of handlers){ | |
let [other_target, other_name, other_handler] = tuple; | |
other_target.removeEventListener(other_name, other_handler); | |
} | |
goto(after); | |
} | |
handlers.push([target, name, handler]); | |
target.addEventListener(name, handler); | |
return null; | |
} | |
function sleep(n, after){ | |
setTimeout(()=>goto(after), n*1000); | |
return null; | |
} | |
function disp(x){ | |
if(x == undefined) x = ""; | |
document.getElementById("disptext").innerHTML = x; | |
} | |
function more(x){ | |
if(x == undefined) x = ""; | |
document.getElementById("disptext").innerHTML += "\n" + x; | |
} | |
function randint(n){ | |
return Math.floor(Math.random() * n); | |
} | |
let __DELAY = DELAY; | |
function ToggleAuto(){ | |
if(DELAY == 0){ | |
DELAY = __DELAY; | |
autobutton.value = "Auto: Off"; } | |
else if(DELAY == __DELAY){ | |
autobutton.value = "Auto: Semiauto"; | |
DELAY = MINDELAY; } | |
else { | |
autobutton.value = "Auto: On"; | |
DELAY = 0; } | |
autobutton.blur(); | |
} | |
function Download(){ | |
var zip = new JSZip(); | |
// Generate a directory within the Zip file structure | |
var guessgame = zip.folder("war"); | |
guessgame.file("index.html", document.documentElement.outerHTML); | |
// Generate the zip file asynchronously | |
zip.generateAsync({type:"blob"}).then(function(content){ | |
// Force down of the Zip file | |
saveAs(content, "wargame.zip"); | |
}); | |
} | |
</script> | |
<style> | |
*{ font-size: 108%; font-family: monospace; } | |
hr{ margin-top: 2em; margin-bottom: 0.65em; } | |
#codeoutput{ font-family: monospace; width: 100%; overflow-x: scroll; | |
text-align: left; | |
white-space: pre; | |
} | |
body{ text-align: center; } | |
</style> | |
</head> | |
<body> | |
<p><pre id="disptext"></pre></p> | |
<!--<input id='textinput' type='text'></input>--> | |
<input id='okaybutton' type='button' value="ok"></input> | |
<input id='autobutton' onclick='ToggleAuto();' type='button' value="Auto: Off"></input> | |
<!-- <p style="position: fixed; bottom: 0px; right:8px; text-align: right;"> --> | |
<p> | |
<!-- <h3> Source Code </h3> --> | |
<hr> | |
<button onclick="Download();"> Download Game</button> | |
<button onclick="codeoutput.appendChild(document.createTextNode(document.documentElement.outerHTML)); codeoutput.style.display='block'"> View Source </button> | |
</p> | |
<span id='codeoutput' wrap='off' style="display:none;"><hr></span> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment