initial commit

trunk
vilmibm 2020-11-25 03:54:38 +00:00
commit 2995f40d62
4 changed files with 307 additions and 0 deletions

100
cards.js 100644
View File

@ -0,0 +1,100 @@
function cardDB() {
return {
// Major arcana
"the fool": {
"arcana": "major",
"index": 1
},
"the magician": {
"arcana": "major",
"index": 2
},
"the high priestess": {
"arcana": "major",
"index": 3
},
"the empress": {
"arcana": "major",
"index": 4
},
"the emperor": {
"arcana": "major",
"index": 5
},
"the hierophant": {
"arcana": "major",
"index": 6
},
"the lovers": {
"arcana": "major",
"index": 7
},
"the chariot": {
"arcana": "major",
"index": 8
},
"justice": {
"arcana": "major",
"index": 9
},
"the hermit": {
"arcana": "major",
"index": 10
},
"wheel of fortune": {
"arcana": "major",
"index": 11
},
"strength": {
"arcana": "major",
"index": 12
},
"death": {
"arcana": "major",
"index": 13
},
"temperance": {
"arcana": "major",
"index": 14
},
"the devil": {
"arcana": "major",
"index": 15
},
"the tower": {
"arcana": "major",
"index": 16
},
"the star": {
"arcana": "major",
"index": 17
},
"the moon": {
"arcana": "major",
"index": 18
},
"the sun": {
"arcana": "major",
"index": 19
},
"judgement": {
"arcana": "major",
"index": 20
},
"the world": {
"arcana": "major",
"index": 21
},
// Minor arcana
"ace of cups": {
"arcana": "minor",
"index": 1,
"suit": "cups"
},
// TODO
}
}
export default cardDB;

32
index.html 100644
View File

@ -0,0 +1,32 @@
<html>
<head>
<title>tarot</title>
<style>
body {
background-color: black;
color: white;
}
</style>
</head>
<body>
<h1>hermetic</h1>
<button id="reset">reset</button>
<br>
<div id="deck"></div>
<div id="info" style="height: 325px; width: 500px;"></div>
<div id="table"></div>
<div class="blueprint card">
<pre></pre>
<span></span>
</div>
<script type="module" src="main.js"></script>
<style>
.blueprint {
display: none;
}
</style>
</body>
</html>

4
main.js 100644
View File

@ -0,0 +1,4 @@
import Tarot from './tarot.js'
window.tarot = new Tarot();
window.tarot.render();

171
tarot.js 100644
View File

@ -0,0 +1,171 @@
import cardDB from './cards.js';
// TODO reset state button
class Tarot {
constructor() {
this.cardDB = cardDB();
this.deck = new CardPile();
for (const cardName in this.cardDB) {
this.deck.add(cardName);
}
this.table = new CardPile();
const deckElem = document.querySelector("#deck");
const tableElem = document.querySelector("#table");
const infoElem = document.querySelector("#info");
const resetElem = document.querySelector("#reset");
// TODO bring those top level functions in as methods
this.renderers = [
new Renderer(
deckElem,
deckRender(this.deck)),
new Renderer(
tableElem,
tableRender(this, this.table)),
new Renderer(
infoElem,
infoRender(tableElem, deckElem))
];
// handlers
// TODO make it feel similar to the renderers? or just have a general way to list out events
// that should trigger a render
tableElem.addEventListener("mouseenter", this.render.bind(this));
tableElem.addEventListener("mouseleave", this.render.bind(this));
deckElem.addEventListener("click", this.drawCard.bind(this));
resetElem.addEventListener("click", this.reset.bind(this));
}
reset() {
let card = this.table.drawRandom();
while (card != null) {
this.deck.add(card);
card = this.table.drawRandom();
}
this.render();
}
drawCard() {
let cardName = this.deck.drawRandom();
if (cardName === null) {
this.render();
return;
}
this.table.add(cardName);
this.render();
}
render() {
for (const renderer of this.renderers) {
renderer.render();
}
}
}
function infoRender(tableElem) {
return function(elem) {
const cardElem = tableElem.querySelector(".card:hover");
if (cardElem == null) {
elem.innerHTML = "";
return
}
elem.innerHTML = cardElem.querySelector("span").innerHTML;
}
}
function tableRender(tarot, table) {
return function(elem) {
const cardsOut = elem.querySelectorAll('.card');
for (let cardElem of cardsOut) {
if (!table.has(cardElem.getAttribute('data-cardName'))) {
cardElem.remove();
}
}
for (let cardName of table.cards) {
const found = elem.querySelector(`[data-cardName="${cardName}"]`);
if (found != null) {
continue;
}
let bp = document.querySelector(".card.blueprint");
let cardElem = bp.cloneNode(true);
cardElem.classList.remove("blueprint");
cardElem.setAttribute("data-cardName", cardName)
cardElem.setAttribute("style", "float:left; width: 150px; height: 250px; border: 1px solid pink;");
cardElem.querySelector("span").innerHTML = cardName;
cardElem.addEventListener("mouseenter", tarot.render.bind(tarot));
elem.append(cardElem);
}
}
}
function deckRender(deck) {
return function(elem) {
const width = deck.size;
elem.setAttribute("style", `float:left; height: 250px; width: 150px; border-left: 1px solid white; border-top: 1px solid white; border-bottom: ${width}px solid white; border-right: ${width}px solid white`);
}
}
function deckClick(deckElem, deck) {
return function() {
console.log(deckElem, deck);
}
}
class Renderer {
constructor(element, renderFn) {
this.element = element;
this.renderFn = renderFn;
}
render() {
this.renderFn(this.element);
}
}
class CardPile {
constructor() {
this.cards = new Set();
}
add(cardName) {
this.cards.add(cardName);
}
has(cardName) {
return this.cards.has(cardName);
}
get size() {
return this.cards.size;
}
drawRandom() {
const size = this.cards.size
if (size === 0) {
return null;
}
const index = Math.floor(Math.random() * Math.floor(size));
let i = 0;
let cardName = "";
for (let card of this.cards) {
if (i === index) {
cardName = card;
break
}
i++;
}
this.cards.delete(cardName);
return cardName;
}
}
export default Tarot;