Skip to content

Commit

Permalink
start tracking everyones score for themselves
Browse files Browse the repository at this point in the history
  • Loading branch information
cigzigwon committed Oct 24, 2021
1 parent aabdda4 commit ecfbd44
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 88 deletions.
221 changes: 135 additions & 86 deletions src/js/App.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import React, { useEffect, useState } from "react"
import interact from "interactjs"
import { EyeIcon, ArrowsExpandIcon } from "@heroicons/react/outline"
import DialogConfirm from "./DialogConfirm"

import '../sass/styles.sass'

const cache_key = key => {
const item = localStorage.getItem(key)
return item ? JSON.parse(item) : item
}

const get_random_integer = (max) => {
return Math.floor(Math.random() * max)
}
Expand All @@ -21,7 +27,6 @@ const colors = [
'yellow'
]
const primary_color = colors[get_random_integer(colors.length)]
const grid = Array.from(x_set).fill(Array.from(y_set).fill(0))

const mine_generator = (prev, curr) => {
const x_key = get_random_integer(x_set.length)
Expand All @@ -36,15 +41,23 @@ const mine_generator = (prev, curr) => {
return prev.concat([[x, y]])
}

const mines = new Array(max_mines).fill().reduce(mine_generator, [])
const build_grid = () => Array.from(x_set).fill(Array.from(y_set).fill(0))
const build_mines = () => new Array(max_mines).fill().reduce(mine_generator, [])

const App = () => {
const [game_state, set_game_state] = useState({
message: "",
const [game_state, set_game_state] = useState(() => {
const score = cache_key('score')
return {
message: "",
score: score ? score : [0, 0]
}
})
const [grid, set_grid] = useState(build_grid)
const [mines, set_mines] = useState(build_mines)
const [is_open, set_isopen] = useState(false)
const [blasts, set_blasts] = useState(0)
const [swept, set_swept] = useState(0)
const [won, lost] = game_state.score
const on_dragmove = event => {
const target = event.target
// keep the dragged position in the data-x/data-y attributes
Expand All @@ -59,100 +72,122 @@ const App = () => {
target.setAttribute('data-y', y)
}

const reset_game = () => {
interact('.dropzone').unset()
interact('.drag-drop').unset()
document.querySelectorAll('.dropzone').forEach(elem => {
elem.classList.replace('bg-gray-300', `bg-${primary_color}-400`)
elem.classList.replace('bg-red-400', `bg-${primary_color}-400`)
elem.innerHTML = '❓'
})
set_isopen(false)
set_blasts(0)
set_swept(0)
set_mines(build_mines)
set_grid(build_grid)
}

// this function is used later in the resizing and gesture demos
window.dragMoveListener = on_dragmove

useEffect(() => {
import("interactjs").then(({ default: interact }) => {
/* The dragging code for '.draggable' from the demo above
* applies to this demo as well so it doesn't have to be repeated. */

// enable draggables to be dropped into this
interact('.dropzone').dropzone({
// only accept elements matching this CSS selector
accept: '#sweeper',
// Require a 75% element overlap for a drop to be possible
overlap: 0.75,

// listen for drop related events:

ondropactivate: function (event) {
// add active dropzone feedback
event.target.classList.add('drop-active')
},
ondragenter: function (event) {
const draggable_elem = event.relatedTarget
const dropzone_elem = event.target

// feedback the possibility of a drop
dropzone_elem.classList.add('drop-target')
dropzone_elem.classList.add(`bg-${primary_color}-600`)
draggable_elem.classList.add('can-drop')
// draggable_elem.textContent = ' '
},
ondragleave: function (event) {
// remove the drop feedback style
event.target.classList.remove('drop-target')
event.target.classList.remove(`bg-${primary_color}-600`)
event.relatedTarget.classList.remove('can-drop')
// event.target.classList.remove('dropped')
// event.relatedTarget.textContent = ' '
},
ondrop: function (event) {
const dropzone_elem = event.target


if (dropzone_elem.classList.contains('xxx')) {
dropzone_elem.innerHTML = '💣'
dropzone_elem.classList.add('bg-red-400')
dropzone_elem.classList.remove('xxx')
set_blasts(prev => prev + 1)
} else {
dropzone_elem.classList.add('bg-gray-300')
dropzone_elem.innerHTML = '✅'
}

if (dropzone_elem.classList.contains(`bg-${primary_color}-400`)) {
set_swept(prev => prev + 1)
}

dropzone_elem.classList.add('dropped')
dropzone_elem.classList.remove(`bg-${primary_color}-400`)
},
ondropdeactivate: function (event) {
// remove active dropzone feedback
event.target.classList.remove('drop-active')
event.target.classList.remove('drop-target')
event.target.classList.remove(`bg-${primary_color}-600`)
}
})

interact('.drag-drop')
.draggable({
inertia: true,
modifiers: [
interact.modifiers.restrictRect({
restriction: 'parent',
endOnly: true
})
],
autoScroll: true,
// dragMoveListener from the dragging demo above
listeners: { move: dragMoveListener }
})
/* The dragging code for '.draggable' from the demo above
* applies to this demo as well so it doesn't have to be repeated.
*/

// enable draggables to be dropped into this
interact('.dropzone').dropzone({
// only accept elements matching this CSS selector
accept: '#sweeper',
// Require a 75% element overlap for a drop to be possible
overlap: 0.75,

// listen for drop related events:

ondropactivate: function (event) {
// add active dropzone feedback
event.target.classList.add('drop-active')
},
ondragenter: function (event) {
const draggable_elem = event.relatedTarget
const dropzone_elem = event.target

// feedback the possibility of a drop
dropzone_elem.classList.add('drop-target')
dropzone_elem.classList.add(`bg-${primary_color}-600`)
draggable_elem.classList.add('can-drop')
// draggable_elem.textContent = ' '
},
ondragleave: function (event) {
// remove the drop feedback style
event.target.classList.remove('drop-target')
event.target.classList.remove(`bg-${primary_color}-600`)
event.relatedTarget.classList.remove('can-drop')
// event.target.classList.remove('dropped')
// event.relatedTarget.textContent = ' '
},
ondrop: function (event) {
const dropzone_elem = event.target


if (dropzone_elem.classList.contains('xxx')) {
dropzone_elem.innerHTML = '💣'
dropzone_elem.classList.add('bg-red-400')
dropzone_elem.classList.remove('xxx')
set_blasts(prev => prev + 1)
} else {
dropzone_elem.classList.add('bg-gray-300')
dropzone_elem.innerHTML = '✅'
}

if (dropzone_elem.classList.contains(`bg-${primary_color}-400`)) {
set_swept(prev => prev + 1)
}

dropzone_elem.classList.add('dropped')
dropzone_elem.classList.remove(`bg-${primary_color}-400`)
},
ondropdeactivate: function (event) {
// remove active dropzone feedback
event.target.classList.remove('drop-active')
event.target.classList.remove('drop-target')
event.target.classList.remove(`bg-${primary_color}-600`)
}
})
}, [])

interact('.drag-drop')
.draggable({
inertia: true,
modifiers: [
interact.modifiers.restrictRect({
restriction: 'parent',
endOnly: true
})
],
autoScroll: true,
// dragMoveListener from the dragging demo above
listeners: { move: dragMoveListener }
})
}, [grid])

useEffect(() => {
if (blasts >= mines.length) {
set_game_state({ message: "You Lose!!!" })
set_game_state(prev => {
const score = [prev.score[0], prev.score[1] + 1]
localStorage.setItem('score', JSON.stringify(score))
return {...prev, message: "You Lose!!!", score: score}
})
set_isopen(true)
}
}, [blasts])

useEffect(() => {
if (swept >= (x_set.length * y_set.length - 1) && blasts < mines.length) {
set_game_state({ message: "You Win!!! Congrats!!" })
set_game_state(prev => {
const score = [prev.score[0] + 1, prev.score[1]]
localStorage.setItem('score', JSON.stringify(score))
return {...prev, message: "You Win!!! Congrats!!", score: score}
})
set_isopen(true)
}
}, [swept])
Expand All @@ -163,7 +198,21 @@ const App = () => {
<EyeIcon className="h-4/5 w-4/5 text-white text-center" />
</div>
<div className="container mt-24 px-4 mx-auto w-full md:w-3/5 lg:w-1/3">
<h1 className={`mb-6 text-3xl text-${primary_color}-600`}>DnD Mine Sweeper</h1>
<div className="flex">
<h1 className={`mb-6 text-3xl text-${primary_color}-600 w-2/3`}>DnD Mine Sweeper</h1>
<div className="flex-grow justify-center">
<div className="flex justify-around border-gray-900 border-b">
<div>Won</div>
<div className="flex-shrink"></div>
<div>Lost</div>
</div>
<div className="flex justify-around">
<strong className={`text-${primary_color}-600 py-1`}>{ won }</strong>
<div className="flex-shrink border-gray-900 border-r"></div>
<strong className="py-1">{ lost }</strong>
</div>
</div>
</div>
<p className="mb-6">Drag and drop the eye icon to uncover the booby traps (mines), you booby! There are <strong className={`font-semibold text-${primary_color}-500`}>{mines.length}</strong> of them.</p>
{grid.map((y, y_key) => (
<div key={y_key} className="flex flex-row">
Expand All @@ -178,7 +227,7 @@ const App = () => {
</div>
))}
</div>
<DialogConfirm is_open={is_open} set_isopen={set_isopen} primary_color={primary_color} {...game_state} />
<DialogConfirm is_open={is_open} set_isopen={set_isopen} primary_color={primary_color} {...game_state} reset_game={reset_game} />
</>
)
}
Expand Down
4 changes: 2 additions & 2 deletions src/js/DialogConfirm.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from "react"
import { Dialog } from "@headlessui/react"

const DialogConfirm = ({ is_open, set_isopen, message, primary_color }) => {
const DialogConfirm = ({ is_open, set_isopen, message, primary_color, reset_game }) => {
return (
<Dialog
open={is_open}
Expand All @@ -16,7 +16,7 @@ const DialogConfirm = ({ is_open, set_isopen, message, primary_color }) => {
<p className="mb-4">Would you like to restart the game?</p>
<div className="flex flex-shrink justify-end">
<button onClick={e => {
location.reload()
reset_game()
}} className={`inline-flex bg-${primary_color}-600 text-white rounded-full h-8 w-1/4 mr-4 px-4 justify-center items-center`}>Yes</button>
<button onClick={e => {
set_isopen(false)
Expand Down

0 comments on commit ecfbd44

Please sign in to comment.