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:
Austin Chen 2022-07-20 16:57:51 -07:00 committed by GitHub
parent 528dd2b28a
commit a3f150b1d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 1250 additions and 1 deletions

View File

@ -1,3 +1,4 @@
# Ignore Next artifacts
.next/
out/
public/**/*.json

362
web/public/mtg/app.js Normal file
View 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
View 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>

View 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
View 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>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long