Host Ida and Alex's MTG Guesser game (#656)
* Copy over code from Mtg Guesser * Run Prettier * CSS Tweaks: Hover feedback, button positioning * Hide all but counterspell & burn, for now * Move to /mtg directory * Fix prettierignore * smaller jsons (#673) limited burn to only red cards and also added limited json files to only have fields needed to play * Add Ida's tweak to card position Co-authored-by: marsteralex <bob.masteralex@gmail.com>
This commit is contained in:
parent
528dd2b28a
commit
a3f150b1d9
|
@ -1,3 +1,4 @@
|
|||
# Ignore Next artifacts
|
||||
.next/
|
||||
out/
|
||||
public/**/*.json
|
362
web/public/mtg/app.js
Normal file
362
web/public/mtg/app.js
Normal file
|
@ -0,0 +1,362 @@
|
|||
mode = 'PLAY'
|
||||
allData = {}
|
||||
total = 0
|
||||
unseenTotal = 0
|
||||
probList = []
|
||||
nameList = []
|
||||
k = 12
|
||||
extra = 3
|
||||
artDict = {}
|
||||
totalCorrect = 0
|
||||
totalSeen = 0
|
||||
wordsLeft = k + extra
|
||||
imagesLeft = k
|
||||
maxRounds = 20
|
||||
whichGuesser = 'counterspell'
|
||||
un = false
|
||||
online = false
|
||||
firstPrint = false
|
||||
flag = true
|
||||
page = 1
|
||||
|
||||
document.location.search.split('&').forEach((pair) => {
|
||||
let v = pair.split('=')
|
||||
if (v[0] === '?whichguesser') {
|
||||
whichGuesser = v[1]
|
||||
} else if (v[0] === 'un') {
|
||||
un = v[1]
|
||||
} else if (v[0] === 'digital') {
|
||||
online = v[1]
|
||||
} else if (v[0] === 'original') {
|
||||
firstPrint = v[1]
|
||||
}
|
||||
})
|
||||
|
||||
let firstFetch = fetch('jsons/' + whichGuesser + page + '.json')
|
||||
fetchToResponse(firstFetch)
|
||||
|
||||
function putIntoMapAndFetch(data) {
|
||||
putIntoMap(data.data)
|
||||
if (data.has_more) {
|
||||
page += 1
|
||||
window.setTimeout(() =>
|
||||
fetchToResponse(fetch('jsons/' + whichGuesser + page + '.json'))
|
||||
)
|
||||
} else {
|
||||
for (const [key, value] of Object.entries(allData)) {
|
||||
nameList.push(key)
|
||||
probList.push(
|
||||
value.length +
|
||||
(probList.length === 0 ? 0 : probList[probList.length - 1])
|
||||
)
|
||||
unseenTotal = total
|
||||
}
|
||||
window.console.log(allData)
|
||||
window.console.log(total)
|
||||
window.console.log(probList)
|
||||
window.console.log(nameList)
|
||||
if (whichGuesser === 'counterspell') {
|
||||
document.getElementById('guess-type').innerText = 'Counterspell Guesser'
|
||||
} else if (whichGuesser === 'beast') {
|
||||
document.getElementById('guess-type').innerText =
|
||||
'Finding Fantastic Beasts'
|
||||
} else if (whichGuesser === 'terror') {
|
||||
document.getElementById('guess-type').innerText =
|
||||
"I'm a Terror-able Guesser"
|
||||
} else if (whichGuesser === 'wrath') {
|
||||
document.getElementById('guess-type').innerText = "I'll Clean Sweep"
|
||||
} else if (whichGuesser === 'burn') {
|
||||
document.getElementById('guess-type').innerText = 'Match With Hot Singles'
|
||||
}
|
||||
setUpNewGame()
|
||||
}
|
||||
}
|
||||
|
||||
function getKSamples() {
|
||||
let usedCounters = new Set()
|
||||
let currentTotal = unseenTotal
|
||||
let samples = {}
|
||||
let i = 0
|
||||
while (i < k) {
|
||||
let rand = Math.floor(Math.random() * currentTotal)
|
||||
let count = 0
|
||||
for (const [key, value] of Object.entries(allData)) {
|
||||
if (usedCounters.has(key)) {
|
||||
continue
|
||||
} else if (count >= rand) {
|
||||
usedCounters.add(key)
|
||||
currentTotal -= value.length
|
||||
unseenTotal--
|
||||
let randIndex = Math.floor(Math.random() * value.length)
|
||||
let arts = allData[key].splice(randIndex, 1)
|
||||
samples[arts[0].artImg] = [key, arts[0].normalImg]
|
||||
i++
|
||||
break
|
||||
} else {
|
||||
count += value.length
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const key of usedCounters) {
|
||||
if (allData[key].length === 0) {
|
||||
delete allData[key]
|
||||
}
|
||||
}
|
||||
let count = 0
|
||||
while (count < extra) {
|
||||
let rand = Math.floor(Math.random() * total)
|
||||
for (let j = 0; j < nameList.length; j++) {
|
||||
if (j >= rand) {
|
||||
if (usedCounters.has(nameList[j])) {
|
||||
break
|
||||
}
|
||||
usedCounters.add(nameList[j])
|
||||
count += 1
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return [samples, usedCounters]
|
||||
}
|
||||
|
||||
function fetchToResponse(fetch) {
|
||||
return fetch
|
||||
.then((response) => response.json())
|
||||
.then((json) => {
|
||||
putIntoMapAndFetch(json)
|
||||
})
|
||||
}
|
||||
|
||||
function determineIfSkip(card) {
|
||||
if (!un) {
|
||||
if (card.set_type === 'funny') {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if (!online) {
|
||||
if (card.digital) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if (firstPrint) {
|
||||
if (
|
||||
card.reprint === true ||
|
||||
(card.frame_effects && card.frame_effects.includes('showcase'))
|
||||
) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
// reskinned card names show in art crop
|
||||
if (card.flavor_name) {
|
||||
return true
|
||||
}
|
||||
// don't include racist cards
|
||||
return card.content_warning
|
||||
}
|
||||
|
||||
function putIntoMap(data) {
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
let card = data[i]
|
||||
if (determineIfSkip(card)) {
|
||||
continue
|
||||
}
|
||||
let name = card.name
|
||||
// remove slashes from adventure cards
|
||||
if (card.card_faces) {
|
||||
name = card.card_faces[0].name
|
||||
}
|
||||
let normalImg = ''
|
||||
if (card.image_uris.normal) {
|
||||
normalImg = card.image_uris.normal
|
||||
} else if (card.image_uris.large) {
|
||||
normalImg = card.image_uris.large
|
||||
} else if (card.image_uris.small) {
|
||||
normalImg = card.image_uris.small
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
let artImg = ''
|
||||
if (card.image_uris.art_crop) {
|
||||
artImg = card.image_uris.art_crop
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
total += 1
|
||||
if (!allData[name]) {
|
||||
allData[name] = [{ artImg: artImg, normalImg: normalImg }]
|
||||
} else {
|
||||
allData[name].push({ artImg: artImg, normalImg: normalImg })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function shuffleArray(array) {
|
||||
for (let i = array.length - 1; i > 0; i--) {
|
||||
let j = Math.floor(Math.random() * (i + 1))
|
||||
let temp = array[i]
|
||||
array[i] = array[j]
|
||||
array[j] = temp
|
||||
}
|
||||
}
|
||||
|
||||
function setUpNewGame() {
|
||||
wordsLeft = k + extra
|
||||
imagesLeft = k
|
||||
let currentRound = totalSeen / k
|
||||
if (currentRound + 1 === maxRounds) {
|
||||
document.getElementById('round-number').innerText = 'Final Round'
|
||||
} else {
|
||||
document.getElementById('round-number').innerText =
|
||||
'Round ' + (1 + currentRound)
|
||||
}
|
||||
|
||||
setWordsLeft()
|
||||
// select new cards
|
||||
let sampledData = getKSamples()
|
||||
artDict = sampledData[0]
|
||||
let randomImages = Object.keys(artDict)
|
||||
shuffleArray(randomImages)
|
||||
let namesList = Array.from(sampledData[1]).sort()
|
||||
// fill in the new cards and names
|
||||
for (let cardIndex = 1; cardIndex <= k; cardIndex++) {
|
||||
let currCard = document.getElementById('card-' + cardIndex)
|
||||
currCard.classList.remove('incorrect')
|
||||
currCard.dataset.name = ''
|
||||
currCard.dataset.url = randomImages[cardIndex - 1]
|
||||
currCard.style.backgroundImage = "url('" + currCard.dataset.url + "')"
|
||||
}
|
||||
const nameBank = document.querySelector('.names-bank')
|
||||
for (nameIndex = 1; nameIndex <= k + extra; nameIndex++) {
|
||||
currName = document.getElementById('name-' + nameIndex)
|
||||
// window.console.log(currName)
|
||||
currName.innerText = namesList[nameIndex - 1]
|
||||
nameBank.appendChild(currName)
|
||||
}
|
||||
}
|
||||
|
||||
function checkAnswers() {
|
||||
let score = k
|
||||
// show the correct full cards
|
||||
for (cardIndex = 1; cardIndex <= k; cardIndex++) {
|
||||
currCard = document.getElementById('card-' + cardIndex)
|
||||
let incorrect = true
|
||||
if (currCard.dataset.name) {
|
||||
let guess = document.getElementById(currCard.dataset.name).innerText
|
||||
// window.console.log(artDict[currCard.dataset.url][0], guess);
|
||||
incorrect = artDict[currCard.dataset.url][0] !== guess
|
||||
// decide if their guess was correct
|
||||
}
|
||||
if (incorrect) currCard.classList.add('incorrect')
|
||||
// tally some kind of score
|
||||
if (incorrect) score--
|
||||
// show the correct card
|
||||
currCard.style.backgroundImage =
|
||||
"url('" + artDict[currCard.dataset.url][1] + "')"
|
||||
}
|
||||
totalSeen += k
|
||||
totalCorrect += score
|
||||
document.getElementById('score-amount').innerText = score + '/' + k
|
||||
document.getElementById('score-percent').innerText = Math.round(
|
||||
(totalCorrect * 100) / totalSeen
|
||||
)
|
||||
document.getElementById('score-amount-total').innerText =
|
||||
totalCorrect + '/' + totalSeen
|
||||
}
|
||||
|
||||
function toggleMode() {
|
||||
event.preventDefault()
|
||||
if (mode === 'PLAY') {
|
||||
mode = 'ANSWER'
|
||||
document.querySelector('.play-page').classList.add('answer-page')
|
||||
window.console.log(totalSeen)
|
||||
if (totalSeen / k === maxRounds - 1) {
|
||||
document.getElementById('submit').style.display = 'none'
|
||||
} else {
|
||||
document.getElementById('submit').value = 'Next Round'
|
||||
}
|
||||
checkAnswers()
|
||||
} else {
|
||||
mode = 'PLAY'
|
||||
document.querySelector('.play-page').classList.remove('answer-page')
|
||||
document.getElementById('submit').value = 'Submit'
|
||||
setUpNewGame()
|
||||
}
|
||||
}
|
||||
|
||||
function allowDrop(ev, id) {
|
||||
ev.preventDefault()
|
||||
}
|
||||
|
||||
function drag(ev) {
|
||||
ev.dataTransfer.setData('text', ev.target.id)
|
||||
let nameEl = document.querySelector('.selected')
|
||||
if (nameEl) nameEl.classList.remove('selected')
|
||||
}
|
||||
|
||||
function drop(ev, id) {
|
||||
ev.preventDefault()
|
||||
var data = ev.dataTransfer.getData('text')
|
||||
dropOnCard(id, data)
|
||||
}
|
||||
|
||||
function returnDrop(ev) {
|
||||
ev.preventDefault()
|
||||
var data = ev.dataTransfer.getData('text')
|
||||
returnToNameBank(data)
|
||||
}
|
||||
|
||||
function returnToNameBank(name) {
|
||||
document
|
||||
.querySelector('.names-bank')
|
||||
.appendChild(document.getElementById(name))
|
||||
let prevContainer = document.querySelector('[data-name=' + name + ']')
|
||||
if (prevContainer) {
|
||||
prevContainer.dataset.name = ''
|
||||
wordsLeft += 1
|
||||
imagesLeft += 1
|
||||
setWordsLeft()
|
||||
}
|
||||
}
|
||||
|
||||
function selectName(ev) {
|
||||
if (ev.target.parentNode.classList.contains('names-bank')) {
|
||||
let nameEl = document.querySelector('.selected')
|
||||
if (nameEl) nameEl.classList.remove('selected')
|
||||
ev.target.classList.add('selected')
|
||||
} else {
|
||||
returnToNameBank(ev.target.id)
|
||||
}
|
||||
}
|
||||
|
||||
function dropSelected(ev, id) {
|
||||
ev.preventDefault()
|
||||
let nameEl = document.querySelector('.selected')
|
||||
window.console.log('drop selected', nameEl)
|
||||
if (!nameEl) return
|
||||
nameEl.classList.remove('selected')
|
||||
dropOnCard(id, nameEl.id)
|
||||
}
|
||||
|
||||
function dropOnCard(id, data) {
|
||||
let target = document.getElementById('card-' + id)
|
||||
target.appendChild(document.getElementById(data))
|
||||
// if this already has a name, remove that name
|
||||
if (target.dataset.name) {
|
||||
returnToNameBank(target.dataset.name)
|
||||
}
|
||||
// remove name data from a previous card if there is one
|
||||
let prevContainer = document.querySelector('[data-name=' + data + ']')
|
||||
if (prevContainer) {
|
||||
prevContainer.dataset.name = ''
|
||||
} else {
|
||||
wordsLeft -= 1
|
||||
imagesLeft -= 1
|
||||
setWordsLeft()
|
||||
}
|
||||
target.dataset.name = data
|
||||
}
|
||||
|
||||
function setWordsLeft() {
|
||||
document.getElementById('words-left').innerText =
|
||||
'Unused Card Names: ' + wordsLeft + '/Images: ' + imagesLeft
|
||||
}
|
225
web/public/mtg/choose.html
Normal file
225
web/public/mtg/choose.html
Normal file
|
@ -0,0 +1,225 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<!-- Google Tag Manager -->
|
||||
<script>
|
||||
;(function (w, d, s, l, i) {
|
||||
w[l] = w[l] || []
|
||||
w[l].push({
|
||||
'gtm.start': new Date().getTime(),
|
||||
event: 'gtm.js',
|
||||
})
|
||||
var f = d.getElementsByTagName(s)[0],
|
||||
j = d.createElement(s),
|
||||
dl = l !== 'dataLayer' ? '&l=' + l : ''
|
||||
j.async = true
|
||||
j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl
|
||||
f.parentNode.insertBefore(j, f)
|
||||
})(window, document, 'script', 'dataLayer', 'GTM-M3MBVGG')
|
||||
</script>
|
||||
<!-- End Google Tag Manager -->
|
||||
<meta charset="UTF-8" />
|
||||
<style type="text/css">
|
||||
body {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.play-page {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
font-family: Georgia, 'Times New Roman', Times, serif;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
h1,
|
||||
h3 {
|
||||
font-family: Verdana, Geneva, Tahoma, sans-serif;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#submit {
|
||||
margin-top: 10px;
|
||||
padding: 8px 20px;
|
||||
background-color: cadetblue;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
font-size: 1.1em;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#submit:hover {
|
||||
background-color: rgb(0, 146, 156);
|
||||
}
|
||||
|
||||
[type='radio'] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
[type='radio'] + label.radio-label {
|
||||
background: lightgrey;
|
||||
display: block;
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
label.radio-label:hover {
|
||||
background: darkgrey;
|
||||
}
|
||||
|
||||
[type='radio']:checked + label.radio-label {
|
||||
background: lightcoral;
|
||||
}
|
||||
|
||||
.radio-label h3 {
|
||||
margin: 0;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
width: 220px;
|
||||
}
|
||||
|
||||
.thumbnail {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
width: 67px;
|
||||
height: 48px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 70px 0 30px;
|
||||
}
|
||||
|
||||
#addl-options {
|
||||
position: absolute;
|
||||
top: 30px;
|
||||
right: 30px;
|
||||
background-color: white;
|
||||
padding: 10px;
|
||||
cursor: pointer;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
#addl-options > summary {
|
||||
list-style: none;
|
||||
text-align: right;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Google Tag Manager (noscript) -->
|
||||
<noscript>
|
||||
<iframe
|
||||
src="https://www.googletagmanager.com/ns.html?id=GTM-M3MBVGG"
|
||||
height="0"
|
||||
width="0"
|
||||
style="display: none; visibility: hidden"
|
||||
></iframe>
|
||||
</noscript>
|
||||
<!-- End Google Tag Manager (noscript) -->
|
||||
<h1>Magic the Guessering</h1>
|
||||
<div class="play-page" style="justify-content: center">
|
||||
<form
|
||||
method="get"
|
||||
action="index.html"
|
||||
style="display: flex; flex-direction: column; align-items: center"
|
||||
>
|
||||
<!-- <input type="radio" id="wrath" name="whichguesser" value="wrath" />
|
||||
<label class="radio-label" for="wrath">
|
||||
<img
|
||||
class="thumbnail"
|
||||
src="https://c1.scryfall.com/file/scryfall-cards/art_crop/front/0/6/0619d670-7b53-4185-a25d-2fab5db1aab5.jpg?1562896185"
|
||||
/>
|
||||
<h3>I'll Clean Sweep</h3></label
|
||||
><br /> -->
|
||||
|
||||
<input
|
||||
type="radio"
|
||||
id="counterspell"
|
||||
name="whichguesser"
|
||||
value="counterspell"
|
||||
checked
|
||||
/>
|
||||
<label class="radio-label" for="counterspell">
|
||||
<img
|
||||
class="thumbnail"
|
||||
src="https://c1.scryfall.com/file/scryfall-cards/art_crop/front/7/1/71cfcba5-1571-48b8-a3db-55dca135506e.jpg?1562843855"
|
||||
/>
|
||||
<h3>Counterspell Guesser</h3></label
|
||||
><br />
|
||||
|
||||
<!-- <input type="radio" id="terror" name="whichguesser" value="terror" />
|
||||
<label class="radio-label" for="terror">
|
||||
<img
|
||||
class="thumbnail"
|
||||
src="https://c1.scryfall.com/file/scryfall-cards/art_crop/front/2/d/2dd5d601-aff7-4b7a-ab6c-b89f403af076.jpg?1562905752"
|
||||
/>
|
||||
<h3>I'm a Terror-able Guesser</h3></label
|
||||
><br /> -->
|
||||
|
||||
<input type="radio" id="burn" name="whichguesser" value="burn" />
|
||||
<label class="radio-label" for="burn">
|
||||
<img
|
||||
class="thumbnail"
|
||||
src="https://c1.scryfall.com/file/scryfall-cards/art_crop/front/6/0/60b2fae1-242b-45e0-a757-b1adc02c06f3.jpg?1562760596"
|
||||
/>
|
||||
<h3>Match With Hot Singles</h3></label
|
||||
><br />
|
||||
|
||||
<!-- <input type="radio" id="beast" name="whichguesser" value="beast" />
|
||||
<label class="radio-label" for="beast">
|
||||
<img
|
||||
class="thumbnail"
|
||||
src="https://c1.scryfall.com/file/scryfall-cards/art_crop/front/3/3/33f7e788-8fc7-49f3-804b-2d7f96852d4b.jpg?1562905469"
|
||||
/>
|
||||
<h3>Finding Fantastic Beasts</h3></label
|
||||
>
|
||||
<br /> -->
|
||||
|
||||
<details id="addl-options">
|
||||
<summary>
|
||||
<img
|
||||
src="http://mythicspoiler.com/images/buttons/ustset.png"
|
||||
style="width: 32px; vertical-align: top"
|
||||
/>
|
||||
Options
|
||||
</summary>
|
||||
<input type="checkbox" name="digital" id="digital" checked />
|
||||
<label for="digital">include digital cards</label>
|
||||
<br />
|
||||
<input type="checkbox" name="un" id="un" checked />
|
||||
<label for="un">include un-cards</label>
|
||||
<br />
|
||||
<input type="checkbox" name="original" id="original" />
|
||||
<label for="original">restrict to only original printing</label>
|
||||
</details>
|
||||
<input type="submit" id="submit" value="Play" />
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div style="margin: -40px 0 0; height: 60px">
|
||||
<a href="https://paypal.me/idamayer">Donate, buy us a boba 🧋</a>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style="
|
||||
font-size: 0.9em;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
color: grey;
|
||||
font-style: italic;
|
||||
"
|
||||
>
|
||||
made by
|
||||
<a
|
||||
style="color: rgb(0, 146, 156); font-style: italic"
|
||||
href="https://idamayer.com"
|
||||
>Ida Mayer</a
|
||||
>
|
||||
& Alex Lien 2022
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
92
web/public/mtg/importCards.py
Normal file
92
web/public/mtg/importCards.py
Normal file
|
@ -0,0 +1,92 @@
|
|||
import time
|
||||
import requests
|
||||
import json
|
||||
|
||||
# add category name here
|
||||
allCategories = ['counterspell', 'beast', 'terror', 'wrath', 'burn']
|
||||
|
||||
|
||||
def generate_initial_query(category):
|
||||
string_query = 'https://api.scryfall.com/cards/search?q='
|
||||
if category == 'counterspell':
|
||||
string_query += 'otag%3Acounterspell+t%3Ainstant+not%3Aadventure'
|
||||
elif category == 'beast':
|
||||
string_query += '-type%3Alegendary+type%3Abeast+-type%3Atoken'
|
||||
elif category == 'terror':
|
||||
string_query += 'otag%3Acreature-removal+o%3A%2Fdestroy+target.%2A+%28creature%7Cpermanent%29%2F+%28t' \
|
||||
'%3Ainstant+or+t%3Asorcery%29+o%3Atarget+not%3Aadventure'
|
||||
elif category == 'wrath':
|
||||
string_query += 'otag%3Asweeper-creature+%28t%3Ainstant+or+t%3Asorcery%29+not%3Aadventure'
|
||||
elif category == 'burn':
|
||||
string_query += '%28c>%3Dr+or+mana>%3Dr%29+%28o%3A%2Fdamage+to+them%2F+or+%28o%3Adeals+o%3Adamage+o%3A' \
|
||||
'%2Fcontroller%28%5C.%7C+%29%2F%29+or+o%3A%2F~+deals+%28.%7C..%29+damage+to+%28any+target%7C' \
|
||||
'.*player%28%5C.%7C+or+planeswalker%29%7C.*opponent%28%5C.%7C+or+planeswalker%29%29%2F%29' \
|
||||
'+%28type%3Ainstant+or+type%3Asorcery%29+not%3Aadventure'
|
||||
# add category string query here
|
||||
string_query += '+-%28set%3Asld+%28%28cn>%3D231+cn<%3D233%29+or+%28cn>%3D321+cn<%3D324%29+or+%28cn>%3D185+cn' \
|
||||
'<%3D189%29+or+%28cn>%3D138+cn<%3D142%29+or+%28cn>%3D364+cn<%3D368%29+or+cn%3A669+or+cn%3A670%29' \
|
||||
'%29+-name%3A%2F%5EA-%2F+not%3Adfc+not%3Asplit+-set%3Acmb2+-set%3Acmb1+-set%3Aplist+-set%3Adbl' \
|
||||
'+-frame%3Aextendedart+language%3Aenglish&unique=art&page='
|
||||
print(string_query)
|
||||
return string_query
|
||||
|
||||
|
||||
def fetch_and_write_all(category, query):
|
||||
count = 1
|
||||
will_repeat = True
|
||||
while will_repeat:
|
||||
will_repeat = fetch_and_write(category, query, count)
|
||||
count += 1
|
||||
|
||||
|
||||
def fetch_and_write(category, query, count):
|
||||
query += str(count)
|
||||
response = requests.get(f"{query}").json()
|
||||
time.sleep(0.1)
|
||||
with open('jsons/' + category + str(count) + '.json', 'w') as f:
|
||||
json.dump(to_compact_write_form(response), f)
|
||||
return response['has_more']
|
||||
|
||||
|
||||
def to_compact_write_form(response):
|
||||
fieldsToUse = ['has_more']
|
||||
fieldsInCard = ['name', 'image_uris', 'content_warning', 'flavor_name', 'reprint', 'frame_effects', 'digital',
|
||||
'set_type']
|
||||
smallJson = dict()
|
||||
data = []
|
||||
# write all fields needed in response
|
||||
for field in fieldsToUse:
|
||||
smallJson[field] = response[field]
|
||||
# write all fields needed in card
|
||||
for card in response['data']:
|
||||
write_card = dict()
|
||||
for field in fieldsInCard:
|
||||
if field == 'name' and 'card_faces' in card:
|
||||
write_card['name'] = card['card_faces'][0]['name']
|
||||
elif field == 'image_uris':
|
||||
write_card['image_uris'] = write_image_uris(card['image_uris'])
|
||||
elif field in card:
|
||||
write_card[field] = card[field]
|
||||
data.append(write_card)
|
||||
smallJson['data'] = data
|
||||
return smallJson
|
||||
|
||||
|
||||
# only write images needed
|
||||
def write_image_uris(card_image_uris):
|
||||
image_uris = dict()
|
||||
if 'normal' in card_image_uris:
|
||||
image_uris['normal'] = card_image_uris['normal']
|
||||
elif 'large' in card_image_uris:
|
||||
image_uris['normal'] = card_image_uris['large']
|
||||
elif 'small' in card_image_uris:
|
||||
image_uris['normal'] = card_image_uris['small']
|
||||
if card_image_uris:
|
||||
image_uris['art_crop'] = card_image_uris['art_crop']
|
||||
return image_uris
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
for category in allCategories:
|
||||
print(category)
|
||||
fetch_and_write_all(category, generate_initial_query(category))
|
554
web/public/mtg/index.html
Normal file
554
web/public/mtg/index.html
Normal file
|
@ -0,0 +1,554 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<!-- Google Tag Manager -->
|
||||
<script>
|
||||
;(function (w, d, s, l, i) {
|
||||
w[l] = w[l] || []
|
||||
w[l].push({
|
||||
'gtm.start': new Date().getTime(),
|
||||
event: 'gtm.js',
|
||||
})
|
||||
var f = d.getElementsByTagName(s)[0],
|
||||
j = d.createElement(s),
|
||||
dl = l !== 'dataLayer' ? '&l=' + l : ''
|
||||
j.async = true
|
||||
j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl
|
||||
f.parentNode.insertBefore(j, f)
|
||||
})(window, document, 'script', 'dataLayer', 'GTM-M3MBVGG')
|
||||
</script>
|
||||
<!-- End Google Tag Manager -->
|
||||
<meta charset="UTF-8" />
|
||||
<script type="text/javascript" src="app.js"></script>
|
||||
<style type="text/css">
|
||||
body {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.play-page {
|
||||
display: flex;
|
||||
flex-direction: row-reverse;
|
||||
font-family: Georgia, 'Times New Roman', Times, serif;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: Verdana, Geneva, Tahoma, sans-serif;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-right: 240px;
|
||||
}
|
||||
|
||||
.cards-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.card {
|
||||
width: 230px;
|
||||
height: 208px;
|
||||
border: 5px solid lightgrey;
|
||||
margin: 5px;
|
||||
align-items: flex-end;
|
||||
box-sizing: border-box;
|
||||
border-radius: 11px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
/*background-size: contain;*/
|
||||
background-size: 220px;
|
||||
background-repeat: no-repeat;
|
||||
transition: height 1s, background-image 1s, border 0.4s 0.6s;
|
||||
background-position-y: calc(50% - 20px);
|
||||
}
|
||||
|
||||
.card:not([data-name^='name'])::after {
|
||||
content: '';
|
||||
height: 34px;
|
||||
background: white;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.answer-page .card {
|
||||
height: 350px;
|
||||
/*padding-top: 310px;*/
|
||||
/*background-size: cover;*/
|
||||
overflow: hidden;
|
||||
border-color: rgb(0, 146, 156);
|
||||
}
|
||||
|
||||
.answer-page .card.incorrect {
|
||||
border-color: rgb(216, 27, 96);
|
||||
}
|
||||
|
||||
.names-bank {
|
||||
position: fixed;
|
||||
padding: 10px 10px 40px;
|
||||
}
|
||||
|
||||
.names-bank .name {
|
||||
margin: 6px 0;
|
||||
}
|
||||
|
||||
.answer-page .names-bank .name {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.answer-page .names-bank .word-count {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.word-count {
|
||||
text-align: center;
|
||||
font-style: italic;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.score {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
background-color: rgb(255, 193, 7);
|
||||
width: 200px;
|
||||
font-family: Verdana, Geneva, Tahoma, sans-serif;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.names-bank .score {
|
||||
overflow: hidden;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.answer-page .names-bank .score {
|
||||
height: auto;
|
||||
display: block;
|
||||
opacity: 1;
|
||||
transition: opacity 1.2s 0.2s;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.name {
|
||||
width: 230px;
|
||||
min-height: 36px;
|
||||
border-radius: 2px;
|
||||
background-color: lightgrey;
|
||||
padding: 8px 12px 2px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.card .name {
|
||||
border-radius: 0 0 5px 5px;
|
||||
}
|
||||
|
||||
#submit {
|
||||
margin-top: 10px;
|
||||
padding: 8px 20px;
|
||||
background-color: cadetblue;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
font-size: 1.1em;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#submit:hover {
|
||||
background-color: rgb(0, 146, 156);
|
||||
}
|
||||
|
||||
#newGame {
|
||||
padding: 8px 20px;
|
||||
background-color: lightpink;
|
||||
border: none;
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 20px;
|
||||
border-radius: 3px;
|
||||
font-size: 0.7em;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#newGame:hover {
|
||||
background-color: coral;
|
||||
}
|
||||
|
||||
.selected {
|
||||
background-color: orange;
|
||||
}
|
||||
|
||||
@media screen and (orientation: landscape) and (max-height: 680px) {
|
||||
/* CSS applied when the device is in landscape mode*/
|
||||
.names-bank {
|
||||
padding: 0;
|
||||
top: 0;
|
||||
max-height: 100vh;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
body {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.word-count {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-right: 240px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (orientation: portrait) and (max-width: 1100px) {
|
||||
body {
|
||||
font-size: 1.8em;
|
||||
}
|
||||
|
||||
.play-page {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.names-bank {
|
||||
flex-direction: row;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
/* position: fixed; */
|
||||
padding: 10px 10px 40px;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.answer-page .names-bank {
|
||||
min-width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
form {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.names-bank .name {
|
||||
margin: 6px;
|
||||
}
|
||||
|
||||
.names-bank .score {
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.answer-page .names-bank .score {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.word-count {
|
||||
position: absolute;
|
||||
margin-top: -20px;
|
||||
}
|
||||
|
||||
.name {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.card {
|
||||
width: 300px;
|
||||
background-size: 300px;
|
||||
height: 266px;
|
||||
}
|
||||
|
||||
.answer-page .card {
|
||||
height: 454px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Google Tag Manager (noscript) -->
|
||||
<noscript>
|
||||
<iframe
|
||||
src="https://www.googletagmanager.com/ns.html?id=GTM-M3MBVGG"
|
||||
height="0"
|
||||
width="0"
|
||||
style="display: none; visibility: hidden"
|
||||
></iframe>
|
||||
</noscript>
|
||||
<!-- End Google Tag Manager (noscript) -->
|
||||
|
||||
<h1><span id="guess-type"></span>: <span id="round-number"></span></h1>
|
||||
|
||||
<div class="play-page">
|
||||
<div
|
||||
class="names-bank"
|
||||
ondrop="returnDrop(event)"
|
||||
ondragover="event.preventDefault()"
|
||||
>
|
||||
<div class="score">
|
||||
YOUR SCORE
|
||||
<div>Correct Answers This Round: <span id="score-amount"></span></div>
|
||||
<div>
|
||||
Correct Answers In Total: <span id="score-amount-total"></span>
|
||||
</div>
|
||||
<div>Overall Percent: <span id="score-percent"></span>%</div>
|
||||
</div>
|
||||
<div class="word-count"><span id="words-left"></span></div>
|
||||
<div
|
||||
class="name"
|
||||
draggable="true"
|
||||
ondragstart="drag(event)"
|
||||
onClick="selectName(event)"
|
||||
id="name-1"
|
||||
>
|
||||
Name 1
|
||||
</div>
|
||||
<div
|
||||
class="name"
|
||||
draggable="true"
|
||||
ondragstart="drag(event)"
|
||||
onClick="selectName(event)"
|
||||
id="name-2"
|
||||
>
|
||||
Name 2
|
||||
</div>
|
||||
<div
|
||||
class="name"
|
||||
draggable="true"
|
||||
ondragstart="drag(event)"
|
||||
onClick="selectName(event)"
|
||||
id="name-3"
|
||||
>
|
||||
Name 3
|
||||
</div>
|
||||
<div
|
||||
class="name"
|
||||
draggable="true"
|
||||
ondragstart="drag(event)"
|
||||
onClick="selectName(event)"
|
||||
id="name-4"
|
||||
>
|
||||
Name 4
|
||||
</div>
|
||||
<div
|
||||
class="name"
|
||||
draggable="true"
|
||||
ondragstart="drag(event)"
|
||||
onClick="selectName(event)"
|
||||
id="name-5"
|
||||
>
|
||||
Name 5
|
||||
</div>
|
||||
<div
|
||||
class="name"
|
||||
draggable="true"
|
||||
ondragstart="drag(event)"
|
||||
onClick="selectName(event)"
|
||||
id="name-6"
|
||||
>
|
||||
Name 6
|
||||
</div>
|
||||
<div
|
||||
class="name"
|
||||
draggable="true"
|
||||
ondragstart="drag(event)"
|
||||
onClick="selectName(event)"
|
||||
id="name-7"
|
||||
>
|
||||
Name 7
|
||||
</div>
|
||||
<div
|
||||
class="name"
|
||||
draggable="true"
|
||||
ondragstart="drag(event)"
|
||||
onClick="selectName(event)"
|
||||
id="name-8"
|
||||
>
|
||||
Name 8
|
||||
</div>
|
||||
<div
|
||||
class="name"
|
||||
draggable="true"
|
||||
ondragstart="drag(event)"
|
||||
onClick="selectName(event)"
|
||||
id="name-9"
|
||||
>
|
||||
Name 9
|
||||
</div>
|
||||
<div
|
||||
class="name"
|
||||
draggable="true"
|
||||
ondragstart="drag(event)"
|
||||
onClick="selectName(event)"
|
||||
id="name-10"
|
||||
>
|
||||
Name 10
|
||||
</div>
|
||||
<div
|
||||
class="name"
|
||||
draggable="true"
|
||||
ondragstart="drag(event)"
|
||||
onClick="selectName(event)"
|
||||
id="name-11"
|
||||
>
|
||||
Name 11
|
||||
</div>
|
||||
<div
|
||||
class="name"
|
||||
draggable="true"
|
||||
ondragstart="drag(event)"
|
||||
onClick="selectName(event)"
|
||||
id="name-12"
|
||||
>
|
||||
Name 12
|
||||
</div>
|
||||
<div
|
||||
class="name"
|
||||
draggable="true"
|
||||
ondragstart="drag(event)"
|
||||
onClick="selectName(event)"
|
||||
id="name-13"
|
||||
>
|
||||
Name 13
|
||||
</div>
|
||||
<div
|
||||
class="name"
|
||||
draggable="true"
|
||||
ondragstart="drag(event)"
|
||||
onClick="selectName(event)"
|
||||
id="name-14"
|
||||
>
|
||||
Name 14
|
||||
</div>
|
||||
<div
|
||||
class="name"
|
||||
draggable="true"
|
||||
ondragstart="drag(event)"
|
||||
onClick="selectName(event)"
|
||||
id="name-15"
|
||||
>
|
||||
Name 15
|
||||
</div>
|
||||
</div>
|
||||
<form onsubmit="toggleMode(event)">
|
||||
<div class="cards-container">
|
||||
<div
|
||||
class="card"
|
||||
ondrop="drop(event,1)"
|
||||
ondragover="allowDrop(event,1)"
|
||||
onclick="dropSelected(event, 1)"
|
||||
id="card-1"
|
||||
></div>
|
||||
<div
|
||||
class="card"
|
||||
ondrop="drop(event,2)"
|
||||
ondragover="allowDrop(event,2)"
|
||||
onclick="dropSelected(event, 2)"
|
||||
id="card-2"
|
||||
></div>
|
||||
<div
|
||||
class="card"
|
||||
ondrop="drop(event,3)"
|
||||
ondragover="allowDrop(event,3)"
|
||||
onclick="dropSelected(event, 3)"
|
||||
id="card-3"
|
||||
></div>
|
||||
<div
|
||||
class="card"
|
||||
ondrop="drop(event,4)"
|
||||
ondragover="allowDrop(event,4)"
|
||||
onclick="dropSelected(event, 4)"
|
||||
id="card-4"
|
||||
></div>
|
||||
<div
|
||||
class="card"
|
||||
ondrop="drop(event,5)"
|
||||
ondragover="allowDrop(event,5)"
|
||||
onclick="dropSelected(event, 5)"
|
||||
id="card-5"
|
||||
></div>
|
||||
<div
|
||||
class="card"
|
||||
ondrop="drop(event, 6)"
|
||||
ondragover="allowDrop(event,6)"
|
||||
onclick="dropSelected(event,6)"
|
||||
id="card-6"
|
||||
></div>
|
||||
<div
|
||||
class="card"
|
||||
ondrop="drop(event,7)"
|
||||
ondragover="allowDrop(event,7)"
|
||||
onclick="dropSelected(event, 7)"
|
||||
id="card-7"
|
||||
></div>
|
||||
<div
|
||||
class="card"
|
||||
ondrop="drop(event,8)"
|
||||
ondragover="allowDrop(event,8)"
|
||||
onclick="dropSelected(event, 8)"
|
||||
id="card-8"
|
||||
></div>
|
||||
<div
|
||||
class="card"
|
||||
ondrop="drop(event,9)"
|
||||
ondragover="allowDrop(event,9)"
|
||||
onclick="dropSelected(event, 9)"
|
||||
id="card-9"
|
||||
></div>
|
||||
<div
|
||||
class="card"
|
||||
ondrop="drop(event,10)"
|
||||
ondragover="allowDrop(event,10)"
|
||||
onclick="dropSelected(event, 10)"
|
||||
id="card-10"
|
||||
></div>
|
||||
<div
|
||||
class="card"
|
||||
ondrop="drop(event,11)"
|
||||
ondragover="allowDrop(event,11)"
|
||||
onclick="dropSelected(event, 11)"
|
||||
id="card-11"
|
||||
></div>
|
||||
<div
|
||||
class="card"
|
||||
ondrop="drop(event,12)"
|
||||
ondragover="allowDrop(event,12)"
|
||||
onclick="dropSelected(event, 12)"
|
||||
id="card-12"
|
||||
></div>
|
||||
</div>
|
||||
<input type="submit" id="submit" value="Submit" />
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div style="position: absolute; top: 0; left: 0; right: 0; color: grey">
|
||||
<form method="get" action="choose.html">
|
||||
<input type="submit" id="newGame" value="New Game" />
|
||||
</form>
|
||||
</div>
|
||||
<div style="margin: -40px 0 0; height: 60px">
|
||||
<a href="https://paypal.me/idamayer">Donate, buy us a boba 🧋</a>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style="
|
||||
font-size: 0.9em;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
color: grey;
|
||||
font-style: italic;
|
||||
"
|
||||
>
|
||||
made by
|
||||
<a
|
||||
style="color: rgb(0, 146, 156); font-style: italic"
|
||||
href="https://idamayer.com"
|
||||
>Ida Mayer</a
|
||||
>
|
||||
& Alex Lien 2022
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
1
web/public/mtg/jsons/beast1.json
Normal file
1
web/public/mtg/jsons/beast1.json
Normal file
File diff suppressed because one or more lines are too long
1
web/public/mtg/jsons/beast2.json
Normal file
1
web/public/mtg/jsons/beast2.json
Normal file
File diff suppressed because one or more lines are too long
1
web/public/mtg/jsons/beast3.json
Normal file
1
web/public/mtg/jsons/beast3.json
Normal file
File diff suppressed because one or more lines are too long
1
web/public/mtg/jsons/burn1.json
Normal file
1
web/public/mtg/jsons/burn1.json
Normal file
File diff suppressed because one or more lines are too long
1
web/public/mtg/jsons/burn2.json
Normal file
1
web/public/mtg/jsons/burn2.json
Normal file
File diff suppressed because one or more lines are too long
1
web/public/mtg/jsons/burn3.json
Normal file
1
web/public/mtg/jsons/burn3.json
Normal file
File diff suppressed because one or more lines are too long
1
web/public/mtg/jsons/counterspell1.json
Normal file
1
web/public/mtg/jsons/counterspell1.json
Normal file
File diff suppressed because one or more lines are too long
1
web/public/mtg/jsons/counterspell2.json
Normal file
1
web/public/mtg/jsons/counterspell2.json
Normal file
File diff suppressed because one or more lines are too long
1
web/public/mtg/jsons/counterspell3.json
Normal file
1
web/public/mtg/jsons/counterspell3.json
Normal file
File diff suppressed because one or more lines are too long
1
web/public/mtg/jsons/terror1.json
Normal file
1
web/public/mtg/jsons/terror1.json
Normal file
File diff suppressed because one or more lines are too long
1
web/public/mtg/jsons/terror2.json
Normal file
1
web/public/mtg/jsons/terror2.json
Normal file
File diff suppressed because one or more lines are too long
1
web/public/mtg/jsons/terror3.json
Normal file
1
web/public/mtg/jsons/terror3.json
Normal file
File diff suppressed because one or more lines are too long
1
web/public/mtg/jsons/wrath1.json
Normal file
1
web/public/mtg/jsons/wrath1.json
Normal file
File diff suppressed because one or more lines are too long
1
web/public/mtg/jsons/wrath2.json
Normal file
1
web/public/mtg/jsons/wrath2.json
Normal file
File diff suppressed because one or more lines are too long
1
web/public/mtg/jsons/wrath3.json
Normal file
1
web/public/mtg/jsons/wrath3.json
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user