Skip to content

Commit

Permalink
Update backend to new database
Browse files Browse the repository at this point in the history
  • Loading branch information
oskarrough committed Sep 17, 2023
1 parent b5748f5 commit 71a633b
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 43 deletions.
6 changes: 3 additions & 3 deletions src/game/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ import {dungeonWithMap} from '../content/dungeon-encounters.js'
/**
* The big "game state" object
* @typedef {object} State
* @prop {Number} createdAt
* @prop {Number} endedAt
* @prop {Boolean} won
* @prop {number} createdAt
* @prop {number} endedAt
* @prop {boolean} won
* @prop {number} turn
* @prop {Array} deck
* @prop {Array} drawPile
Expand Down
42 changes: 23 additions & 19 deletions src/game/backend.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,37 @@
import {isDungeonCompleted} from './utils-state.js'
import {produce} from 'immer'

const apiUrl = 'https://api.slaytheweb.cards/api/runs'
// const apiUrl = 'http://localhost:3000/api/runs'
// const apiUrl = 'https://api.slaytheweb.cards/api/runs'
const apiUrl = 'http://localhost:3000/api/runs'

/**
* @typedef {object} Run
* @prop {string} name - user inputted player name
* @prop {boolean} win - whether the player won the game
* @prop {object} state - the final state
* @prop {Array<object>} past - a list of past states
* @prop {string} player - user inputted player name
* @prop {object} gameState - the final state
* @prop {Array<object>} gamePast - a list of past states
*/

/**
* Saves a "game" object into a remote database.
* @param {object} game
* @param {string=} name
* Saves a "game" object into a remote database for highscores.
* @param {import('./new-game.js').Game} game
* @param {string=} playerName
* @returns {Promise}
*/
export async function postRun(game, name) {
// Make sure we have an end time.
if (!game.state.endedAt) game.state.endedAt = new Date().getTime()
export async function postRun(game, playerName) {
console.log('postRun', game.past.list)

/** @type {Run} */
const run = {
name: name || 'Unknown entity',
win: isDungeonCompleted(game.state),
state: game.state,
past: game.past,
player: playerName || 'Unknown entity',
gameState: produce(game.state, (draft) => {
if (!draft.endedAt) draft.endedAt = new Date().getTime()
}),
gamePast: game.past.list.map((item) => {
return {
action: item.action,
turn: item.state.turn,
player: item.state.player,
}
}),
}

return fetch(apiUrl, {
Expand All @@ -40,8 +45,7 @@ export async function postRun(game, name) {
}

/**
* Fetches a list of maximum 100 runs from the remote database.
* @returns {Promise<[]>} list of game runs
* @returns {Promise<Run[]>} list of game runs
*/
export async function getRuns() {
const res = await fetch(apiUrl)
Expand Down
2 changes: 1 addition & 1 deletion src/game/new-game.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import ActionManager from './action-manager.js'
* @prop {Function} dequeue - runs the oldest "future" action, and stores result in the "past"
* @prop {Function} undo - undoes the last "past" action
* @prop {{list: Array<{type: string}>}} future
* @prop {{list: Array<{type: string, state: State}>}} past
* @prop {{list: Array<{action: string, state: State}>}} past
*/

/**
Expand Down
4 changes: 2 additions & 2 deletions src/ui/pages/game-screen.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ export default class App extends Component {
// console.log(this.game.state)
})
},
submitGame() {
backend.postRun(this.game)
submitGame(playerName) {
backend.postRun(this.game, playerName)
},
help() {
console.log(`Welcome to the Slay The Web Console. Some examples:
Expand Down
31 changes: 18 additions & 13 deletions src/ui/pages/stats.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {html, render} from '../lib.js'
import {getRuns} from '../../game/backend.js'
import '../styles/index.css'

const StatsPage = (props) => html`
const StatsPage = ({runs}) => html`
<article class="Splash">
<p><a href="/" class="Button">Back</a></p>
<div class="Article">
Expand All @@ -16,29 +16,34 @@ const StatsPage = (props) => html`
<thead>
<tr>
<th>Date</th>
<th>Name</th>
<th>Player</th>
<th>Win?</th>
<th>Floor</th>
<th>Moves</th>
<th>Health</th>
<th>Cards</th>
<th>Time</th>
</tr>
</thead>
<tbody>
${props.runs?.length
? props.runs.map((run) => {
const date = new Intl.DateTimeFormat('en', {
${runs?.length
? runs.map((run) => {
const state = run.gameState
// const past = run.gamePast
let date = new Intl.DateTimeFormat('en', {
dateStyle: 'long',
timeStyle: 'short',
}).format(new Date(run.createdAt))
const duration = run.state.endedAt
? (run.state.endedAt - run.state.createdAt) / 1000 + 's'
: ''
hour12: false,
}).format(new Date(state.createdAt))
const duration = state.endedAt ? (state.endedAt - state.createdAt) / 1000 + 's' : ''
return html`<tr>
<td>${date}</td>
<td>${run.name}</td>
<td>${run.win ? 'WIN' : 'LOSS'}</td>
<td>${run.state.turn}</td>
<td>${run.state.player.currentHealth}</td>
<td>${run.player}</td>
<td>${state.won ? 'WIN' : 'LOSS'}</td>
<td>${state.turn}</td>
<td>${run.gamePast.length}</td>
<td>${state.player.currentHealth}</td>
<td>${run.gameState.deck.length}</td>
<td>${duration}</td>
</tr>`
})
Expand Down
28 changes: 23 additions & 5 deletions src/ui/save-load.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,33 @@
import superjson from 'superjson'

// Helpers to save and load the entire game state.
// We can't use JSON.stringify/parse because the state contains Set()s and Map()s.
// superjson, however, does support serializing this.
/**
* Helpers to save and load the entire game state.
* We use `superjson` insetad of JSON.stringify/parse,
* because the state contains Set()s and Map()s.
*/

/**
* Encodes a game state into a string.
* @param {object} state
* @returns {string}
*/
export function encode(state) {
return superjson.stringify(state)
}

/**
* Decodes a serialized game state string back into an object.
* @param {string} state
* @returns {object}
*/
export function decode(state) {
return superjson.parse(state)
}

// Encodes a game state and stores it in the URL as a hash parameter.
/**
* Encodes a game state and stores it in the URL as a hash parameter.
* @param {object} state
*/
export function saveToUrl(state) {
try {
location.hash = encodeURIComponent(encode(state))
Expand All @@ -21,7 +36,10 @@ export function saveToUrl(state) {
}
}

// Reads a game state from the URL and decode it.
/**
* Reads a game state from the URL and decodes it.
* @returns {object}
*/
export function loadFromUrl() {
const state = decodeURIComponent(window.location.hash.split('#')[1])
return decode(state)
Expand Down

0 comments on commit 71a633b

Please sign in to comment.