some more type hinting etc

This commit is contained in:
Zutatensuppe 2021-05-17 02:32:33 +02:00
parent 432e1b6668
commit ee7804a594
18 changed files with 161 additions and 150 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -2,7 +2,7 @@
<head>
<title>🧩 jigsaw.hyottoko.club</title>
<script type="module" crossorigin src="/assets/index.2f18bf13.js"></script>
<script type="module" crossorigin src="/assets/index.85898c1b.js"></script>
<link rel="modulepreload" href="/assets/vendor.00b608ff.js">
<link rel="stylesheet" href="/assets/index.421011a7.css">
</head>

View file

@ -74,9 +74,6 @@ const logger = (...pre) => {
// get a unique id
const uniqId = () => Date.now().toString(36) + Math.random().toString(36).substring(2);
function encodeShape(data) {
if (typeof data === 'number') {
return data;
}
/* encoded in 1 byte:
00000000
^^ top
@ -90,9 +87,6 @@ function encodeShape(data) {
| ((data.left + 1) << 6);
}
function decodeShape(data) {
if (typeof data !== 'number') {
return data;
}
return {
top: (data >> 0 & 0b11) - 1,
right: (data >> 2 & 0b11) - 1,
@ -101,15 +95,9 @@ function decodeShape(data) {
};
}
function encodeTile(data) {
if (Array.isArray(data)) {
return data;
}
return [data.idx, data.pos.x, data.pos.y, data.z, data.owner, data.group];
}
function decodeTile(data) {
if (!Array.isArray(data)) {
return data;
}
return {
idx: data[0],
pos: {
@ -122,9 +110,6 @@ function decodeTile(data) {
};
}
function encodePlayer(data) {
if (Array.isArray(data)) {
return data;
}
return [
data.id,
data.x,
@ -138,9 +123,6 @@ function encodePlayer(data) {
];
}
function decodePlayer(data) {
if (!Array.isArray(data)) {
return data;
}
return {
id: data[0],
x: data[1],
@ -461,8 +443,17 @@ var Time = {
durationStr,
};
const SCORE_MODE_FINAL = 0;
const SCORE_MODE_ANY = 1;
var PieceEdge;
(function (PieceEdge) {
PieceEdge[PieceEdge["Flat"] = 0] = "Flat";
PieceEdge[PieceEdge["Out"] = 1] = "Out";
PieceEdge[PieceEdge["In"] = -1] = "In";
})(PieceEdge || (PieceEdge = {}));
var ScoreMode;
(function (ScoreMode) {
ScoreMode[ScoreMode["FINAL"] = 0] = "FINAL";
ScoreMode[ScoreMode["ANY"] = 1] = "ANY";
})(ScoreMode || (ScoreMode = {}));
const IDLE_TIMEOUT_SEC = 30;
// Map<gameId, Game>
const GAMES = {};
@ -502,11 +493,11 @@ function getPlayerIdByIndex(gameId, playerIndex) {
return null;
}
function getPlayer(gameId, playerId) {
let idx = getPlayerIndexById(gameId, playerId);
const idx = getPlayerIndexById(gameId, playerId);
return Util.decodePlayer(GAMES[gameId].players[idx]);
}
function setPlayer(gameId, playerId, player) {
let idx = getPlayerIndexById(gameId, playerId);
const idx = getPlayerIndexById(gameId, playerId);
if (idx === -1) {
GAMES[gameId].players.push(Util.encodePlayer(player));
}
@ -580,7 +571,7 @@ function setImageUrl(gameId, imageUrl) {
GAMES[gameId].puzzle.info.imageUrl = imageUrl;
}
function getScoreMode(gameId) {
return GAMES[gameId].scoreMode || SCORE_MODE_FINAL;
return GAMES[gameId].scoreMode || ScoreMode.FINAL;
}
function isFinished(gameId) {
return getFinishedTileCount(gameId) === getTileCount(gameId);
@ -601,6 +592,7 @@ function getTilesSortedByZIndex(gameId) {
function changePlayer(gameId, playerId, change) {
const player = getPlayer(gameId, playerId);
for (let k of Object.keys(change)) {
// @ts-ignore
player[k] = change[k];
}
setPlayer(gameId, playerId, player);
@ -614,6 +606,7 @@ function changeData(gameId, change) {
function changeTile(gameId, tileIdx, change) {
for (let k of Object.keys(change)) {
const tile = Util.decodeTile(GAMES[gameId].puzzle.tiles[tileIdx]);
// @ts-ignore
tile[k] = change[k];
GAMES[gameId].puzzle.tiles[tileIdx] = Util.encodeTile(tile);
}
@ -832,7 +825,7 @@ const getPlayerName = (gameId, playerId) => {
};
const getPlayerPoints = (gameId, playerId) => {
const p = getPlayer(gameId, playerId);
return p ? p.points : null;
return p ? p.points : 0;
};
// determine if two tiles are grouped together
const areGrouped = (gameId, tileIdx1, tileIdx2) => {
@ -1023,10 +1016,10 @@ function handleInput$1(gameId, playerId, input, ts) {
finishTiles(gameId, tileIdxs);
_tileChanges(tileIdxs);
let points = getPlayerPoints(gameId, playerId);
if (getScoreMode(gameId) === SCORE_MODE_FINAL) {
if (getScoreMode(gameId) === ScoreMode.FINAL) {
points += tileIdxs.length;
}
else if (getScoreMode(gameId) === SCORE_MODE_ANY) {
else if (getScoreMode(gameId) === ScoreMode.ANY) {
points += 1;
}
else ;
@ -1075,7 +1068,7 @@ function handleInput$1(gameId, playerId, input, ts) {
break;
}
}
if (snapped && getScoreMode(gameId) === SCORE_MODE_ANY) {
if (snapped && getScoreMode(gameId) === ScoreMode.ANY) {
const points = getPlayerPoints(gameId, playerId) + 1;
changePlayer(gameId, playerId, { d, ts, points });
_playerChange();
@ -1150,8 +1143,6 @@ var GameCommon = {
getStartTs,
getFinishTs,
handleInput: handleInput$1,
SCORE_MODE_FINAL,
SCORE_MODE_ANY,
};
const __filename = fileURLToPath(import.meta.url);
@ -1343,7 +1334,7 @@ async function createPuzzle(rng, targetTiles, image, ts) {
}
// then shuffle the positions
positions = rng.shuffle(positions);
tiles = tiles.map(tile => {
const pieces = tiles.map(tile => {
return Util.encodeTile({
idx: tile.idx,
group: 0,
@ -1362,7 +1353,7 @@ async function createPuzzle(rng, targetTiles, image, ts) {
// Complete puzzle object
return {
// tiles array
tiles,
tiles: pieces,
// game data for puzzle, data changes during the game
data: {
// TODO: maybe calculate this each time?
@ -1500,7 +1491,7 @@ function loadGame(gameId) {
puzzle: game.puzzle,
players: game.players,
evtInfos: {},
scoreMode: game.scoreMode || GameCommon.SCORE_MODE_FINAL,
scoreMode: game.scoreMode || ScoreMode.FINAL,
};
GameCommon.setGame(gameObject.id, gameObject);
}
@ -1746,7 +1737,7 @@ wss.on('message', async ({ socket, data }) => {
throw `[gamelog ${gameId} does not exist... ]`;
}
const log = GameLog.get(gameId);
const game = await Game.createGameObject(gameId, log[0][2], log[0][3], log[0][4], log[0][5] || GameCommon.SCORE_MODE_FINAL);
const game = await Game.createGameObject(gameId, log[0][2], log[0][3], log[0][4], log[0][5] || ScoreMode.FINAL);
notify([Protocol.EV_SERVER_INIT_REPLAY, Util.encodeGame(game), log], [socket]);
}
break;

View file

@ -1,16 +1,12 @@
import Geometry from './Geometry'
import Geometry, { Point, Rect } from './Geometry'
import Protocol from './Protocol'
import { Rng } from './Rng'
import Time from './Time'
import Util from './Util'
interface EncodedPlayer extends Array<any> {}
interface EncodedPiece extends Array<any> {}
interface Point {
x: number
y: number
}
export type EncodedPlayer = Array<any>
export type EncodedPiece = Array<any>
export type EncodedPieceShape = number
interface GameRng {
obj: Rng
@ -22,7 +18,7 @@ interface Game {
players: Array<EncodedPlayer>
puzzle: Puzzle
evtInfos: Record<string, EvtInfo>
scoreMode?: number
scoreMode?: ScoreMode
rng: GameRng
}
@ -44,15 +40,24 @@ interface PuzzleTable {
height: number
}
enum PieceEdge {
Flat = 0,
Out = 1,
In = -1,
}
export interface PieceShape {
top: 0|1|-1
bottom: 0|1|-1
left: 0|1|-1
right: 0|1|-1
top: PieceEdge
bottom: PieceEdge
left: PieceEdge
right: PieceEdge
}
export interface Piece {
owner: string|number
idx: number
pos: Point
z: number
group: number
}
export interface PuzzleInfo {
@ -72,8 +77,7 @@ export interface PuzzleInfo {
tilesX: number
tilesY: number
// TODO: ts type Array<PieceShape>
shapes: Array<any>
shapes: Array<EncodedPieceShape>
}
export interface Player {
@ -93,8 +97,10 @@ interface EvtInfo {
_last_mouse_down: Point|null
}
const SCORE_MODE_FINAL = 0
const SCORE_MODE_ANY = 1
export enum ScoreMode {
FINAL = 0,
ANY = 1,
}
const IDLE_TIMEOUT_SEC = 30
@ -134,20 +140,20 @@ function getPlayerIndexById(gameId: string, playerId: string): number {
return -1
}
function getPlayerIdByIndex(gameId: string, playerIndex: number) {
function getPlayerIdByIndex(gameId: string, playerIndex: number): string|null {
if (GAMES[gameId].players.length > playerIndex) {
return Util.decodePlayer(GAMES[gameId].players[playerIndex]).id
}
return null
}
function getPlayer(gameId: string, playerId: string) {
let idx = getPlayerIndexById(gameId, playerId)
function getPlayer(gameId: string, playerId: string): Player {
const idx = getPlayerIndexById(gameId, playerId)
return Util.decodePlayer(GAMES[gameId].players[idx])
}
function setPlayer(gameId: string, playerId: string, player: Player) {
let idx = getPlayerIndexById(gameId, playerId)
const idx = getPlayerIndexById(gameId, playerId)
if (idx === -1) {
GAMES[gameId].players.push(Util.encodePlayer(player))
} else {
@ -168,17 +174,17 @@ function playerExists(gameId: string, playerId: string) {
return idx !== -1
}
function getActivePlayers(gameId: string, ts: number) {
function getActivePlayers(gameId: string, ts: number): Array<Player> {
const minTs = ts - IDLE_TIMEOUT_SEC * Time.SEC
return getAllPlayers(gameId).filter((p: Player) => p.ts >= minTs)
}
function getIdlePlayers(gameId: string, ts: number) {
function getIdlePlayers(gameId: string, ts: number): Array<Player> {
const minTs = ts - IDLE_TIMEOUT_SEC * Time.SEC
return getAllPlayers(gameId).filter((p: Player) => p.ts < minTs && p.points > 0)
}
function addPlayer(gameId: string, playerId: string, ts: number) {
function addPlayer(gameId: string, playerId: string, ts: number): void {
if (!playerExists(gameId, playerId)) {
setPlayer(gameId, playerId, __createPlayerObject(playerId, ts))
} else {
@ -186,7 +192,7 @@ function addPlayer(gameId: string, playerId: string, ts: number) {
}
}
function getEvtInfo(gameId: string, playerId: string) {
function getEvtInfo(gameId: string, playerId: string): EvtInfo {
if (playerId in GAMES[gameId].evtInfos) {
return GAMES[gameId].evtInfos[playerId]
}
@ -211,7 +217,7 @@ function getAllGames(): Array<Game> {
})
}
function getAllPlayers(gameId: string) {
function getAllPlayers(gameId: string): Array<Player> {
return GAMES[gameId]
? GAMES[gameId].players.map(Util.decodePlayer)
: []
@ -221,11 +227,11 @@ function get(gameId: string) {
return GAMES[gameId]
}
function getTileCount(gameId: string) {
function getTileCount(gameId: string): number {
return GAMES[gameId].puzzle.tiles.length
}
function getImageUrl(gameId: string) {
function getImageUrl(gameId: string): string {
return GAMES[gameId].puzzle.info.imageUrl
}
@ -233,8 +239,8 @@ function setImageUrl(gameId: string, imageUrl: string) {
GAMES[gameId].puzzle.info.imageUrl = imageUrl
}
function getScoreMode(gameId: string) {
return GAMES[gameId].scoreMode || SCORE_MODE_FINAL
function getScoreMode(gameId: string): ScoreMode {
return GAMES[gameId].scoreMode || ScoreMode.FINAL
}
function isFinished(gameId: string) {
@ -259,6 +265,7 @@ function getTilesSortedByZIndex(gameId: string) {
function changePlayer(gameId: string, playerId: string, change: any) {
const player = getPlayer(gameId, playerId)
for (let k of Object.keys(change)) {
// @ts-ignore
player[k] = change[k]
}
setPlayer(gameId, playerId, player)
@ -274,12 +281,13 @@ function changeData(gameId: string, change: any) {
function changeTile(gameId: string, tileIdx: number, change: any) {
for (let k of Object.keys(change)) {
const tile = Util.decodeTile(GAMES[gameId].puzzle.tiles[tileIdx])
// @ts-ignore
tile[k] = change[k]
GAMES[gameId].puzzle.tiles[tileIdx] = Util.encodeTile(tile)
}
}
const getTile = (gameId: string, tileIdx: number) => {
const getTile = (gameId: string, tileIdx: number): Piece => {
return Util.decodeTile(GAMES[gameId].puzzle.tiles[tileIdx])
}
@ -500,7 +508,7 @@ const freeTileIdxByPos = (gameId: string, pos: Point) => {
continue
}
const collisionRect = {
const collisionRect: Rect = {
x: tile.pos.x,
y: tile.pos.y,
w: info.tileSize,
@ -531,9 +539,9 @@ const getPlayerName = (gameId: string, playerId: string) => {
return p ? p.name : null
}
const getPlayerPoints = (gameId: string, playerId: string) => {
const getPlayerPoints = (gameId: string, playerId: string): number => {
const p = getPlayer(gameId, playerId)
return p ? p.points : null
return p ? p.points : 0
}
// determine if two tiles are grouped together
@ -746,13 +754,13 @@ function handleInput(gameId: string, playerId: string, input: any, ts: number) {
_tileChanges(tileIdxs)
let points = getPlayerPoints(gameId, playerId)
if (getScoreMode(gameId) === SCORE_MODE_FINAL) {
if (getScoreMode(gameId) === ScoreMode.FINAL) {
points += tileIdxs.length
} else if (getScoreMode(gameId) === SCORE_MODE_ANY) {
} else if (getScoreMode(gameId) === ScoreMode.ANY) {
points += 1
} else {
// no score mode... should never occur, because there is a
// fallback to SCORE_MODE_FINAL in getScoreMode function
// fallback to ScoreMode.FINAL in getScoreMode function
}
changePlayer(gameId, playerId, { d, ts, points })
_playerChange()
@ -809,7 +817,7 @@ function handleInput(gameId: string, playerId: string, input: any, ts: number) {
break
}
}
if (snapped && getScoreMode(gameId) === SCORE_MODE_ANY) {
if (snapped && getScoreMode(gameId) === ScoreMode.ANY) {
const points = getPlayerPoints(gameId, playerId) + 1
changePlayer(gameId, playerId, { d, ts, points })
_playerChange()
@ -881,6 +889,4 @@ export default {
getStartTs,
getFinishTs,
handleInput,
SCORE_MODE_FINAL,
SCORE_MODE_ANY,
}

View file

@ -1,14 +1,18 @@
interface Point {
export interface Point {
x: number
y: number
}
interface Rect {
export interface Rect {
x: number
y: number
w: number
h: number
}
export interface Dim {
w: number
h: number
}
function pointSub(a: Point, b: Point): Point {
return { x: a.x - b.x, y: a.y - b.y }

View file

@ -4,7 +4,7 @@ const MIN = SEC * 60
const HOUR = MIN * 60
const DAY = HOUR * 24
export const timestamp = () => {
export const timestamp = (): number => {
const d = new Date();
return Date.UTC(
d.getUTCFullYear(),
@ -17,7 +17,7 @@ export const timestamp = () => {
)
}
export const durationStr = (duration: number) => {
export const durationStr = (duration: number): string => {
const d = Math.floor(duration / DAY)
duration = duration % DAY

View file

@ -1,3 +1,5 @@
import { EncodedPiece, EncodedPieceShape, EncodedPlayer, Piece, PieceShape, Player } from './GameCommon'
import { Point } from './Geometry'
import { Rng } from './Rng'
@ -27,10 +29,7 @@ export const logger = (...pre: Array<any>) => {
// get a unique id
export const uniqId = () => Date.now().toString(36) + Math.random().toString(36).substring(2)
function encodeShape(data: any): number {
if (typeof data === 'number') {
return data
}
function encodeShape(data: PieceShape): EncodedPieceShape {
/* encoded in 1 byte:
00000000
^^ top
@ -44,10 +43,7 @@ function encodeShape(data: any): number {
| ((data.left + 1) << 6)
}
function decodeShape(data: any) {
if (typeof data !== 'number') {
return data
}
function decodeShape(data: EncodedPieceShape): PieceShape {
return {
top: (data >> 0 & 0b11) - 1,
right: (data >> 2 & 0b11) - 1,
@ -56,17 +52,11 @@ function decodeShape(data: any) {
}
}
function encodeTile(data: any): Array<any> {
if (Array.isArray(data)) {
return data
}
function encodeTile(data: Piece): EncodedPiece {
return [data.idx, data.pos.x, data.pos.y, data.z, data.owner, data.group]
}
function decodeTile(data: any) {
if (!Array.isArray(data)) {
return data
}
function decodeTile(data: EncodedPiece): Piece {
return {
idx: data[0],
pos: {
@ -79,10 +69,7 @@ function decodeTile(data: any) {
}
}
function encodePlayer(data: any): Array<any> {
if (Array.isArray(data)) {
return data
}
function encodePlayer(data: Player): EncodedPlayer {
return [
data.id,
data.x,
@ -96,10 +83,7 @@ function encodePlayer(data: any): Array<any> {
]
}
function decodePlayer(data: any) {
if (!Array.isArray(data)) {
return data
}
function decodePlayer(data: EncodedPlayer): Player {
return {
id: data[0],
x: data[1],
@ -145,7 +129,7 @@ function decodeGame(data: any) {
}
}
function coordByTileIdx(info: any, tileIdx: number) {
function coordByTileIdx(info: any, tileIdx: number): Point {
const wTiles = info.width / info.tileSize
return {
x: tileIdx % wTiles,

View file

@ -1,16 +1,10 @@
import { Dim, Point } from "../common/Geometry"
const MIN_ZOOM = .1
const MAX_ZOOM = 6
const ZOOM_STEP = .05
type ZOOM_DIR = 'in'|'out'
interface Point {
x: number
y: number
}
interface Dim {
w: number
h: number
}
export default function Camera () {
let x = 0

View file

@ -17,15 +17,23 @@ async function loadImageToBitmap(imagePath: string): Promise<ImageBitmap> {
})
}
async function resizeBitmap (bitmap: ImageBitmap, width: number, height: number): Promise<ImageBitmap> {
async function resizeBitmap (
bitmap: ImageBitmap,
width: number,
height: number
): Promise<ImageBitmap> {
const c = createCanvas(width, height)
const ctx = c.getContext('2d') as CanvasRenderingContext2D
ctx.drawImage(bitmap, 0, 0, bitmap.width, bitmap.height, 0, 0, width, height)
return await createImageBitmap(c)
}
async function colorize(image: ImageBitmap, mask: ImageBitmap, color: string): Promise<ImageBitmap> {
const c = createCanvas(image.width, image.height)
async function colorize(
bitmap: ImageBitmap,
mask: ImageBitmap,
color: string
): Promise<ImageBitmap> {
const c = createCanvas(bitmap.width, bitmap.height)
const ctx = c.getContext('2d') as CanvasRenderingContext2D
ctx.save()
ctx.drawImage(mask, 0, 0)
@ -35,7 +43,7 @@ async function colorize(image: ImageBitmap, mask: ImageBitmap, color: string): P
ctx.restore()
ctx.save()
ctx.globalCompositeOperation = "destination-over"
ctx.drawImage(image, 0, 0)
ctx.drawImage(bitmap, 0, 0)
ctx.restore()
return await createImageBitmap(c)
}

View file

@ -1,13 +1,17 @@
"use strict"
import Geometry from '../common/Geometry'
import Geometry, { Rect } from '../common/Geometry'
import Graphics from './Graphics'
import Util, { logger } from './../common/Util'
import { Puzzle, PuzzleInfo, PieceShape } from './../common/GameCommon'
const log = logger('PuzzleGraphics.js')
async function createPuzzleTileBitmaps(img: ImageBitmap, tiles: Array<any>, info: PuzzleInfo) {
async function createPuzzleTileBitmaps(
img: ImageBitmap,
tiles: Array<any>,
info: PuzzleInfo
): Promise<Array<ImageBitmap>> {
log.log('start createPuzzleTileBitmaps')
var tileSize = info.tileSize
var tileMarginWidth = info.tileMarginWidth
@ -23,7 +27,7 @@ async function createPuzzleTileBitmaps(img: ImageBitmap, tiles: Array<any>, info
63, 5, 65, 15, 100, 0
];
const bitmaps = new Array(tiles.length)
const bitmaps: Array<ImageBitmap> = new Array(tiles.length)
const paths: Record<string, Path2D> = {}
function pathForShape(shape: PieceShape) {
@ -89,7 +93,7 @@ async function createPuzzleTileBitmaps(img: ImageBitmap, tiles: Array<any>, info
const c2 = Graphics.createCanvas(tileDrawSize, tileDrawSize)
const ctx2 = c2.getContext('2d') as CanvasRenderingContext2D
for (let t of tiles) {
for (const t of tiles) {
const tile = Util.decodeTile(t)
const srcRect = srcRectByIdx(info, tile.idx)
const path = pathForShape(Util.decodeShape(info.shapes[tile.idx]))
@ -198,7 +202,7 @@ async function createPuzzleTileBitmaps(img: ImageBitmap, tiles: Array<any>, info
return bitmaps
}
function srcRectByIdx(puzzleInfo: PuzzleInfo, idx: number) {
function srcRectByIdx(puzzleInfo: PuzzleInfo, idx: number): Rect {
const c = Util.coordByTileIdx(puzzleInfo, idx)
return {
x: c.x * puzzleInfo.tileSize,
@ -208,7 +212,7 @@ function srcRectByIdx(puzzleInfo: PuzzleInfo, idx: number) {
}
}
async function loadPuzzleBitmaps(puzzle: Puzzle) {
async function loadPuzzleBitmaps(puzzle: Puzzle): Promise<Array<ImageBitmap>> {
// load bitmap, to determine the original size of the image
const bmp = await Graphics.loadImageToBitmap(puzzle.info.imageUrl)

View file

@ -44,7 +44,7 @@
<script lang="ts">
import { defineComponent } from 'vue'
import GameCommon from './../../common/GameCommon'
import { ScoreMode } from './../../common/GameCommon'
import Upload from './../components/Upload.vue'
import ImageTeaser from './../components/ImageTeaser.vue'
@ -64,7 +64,7 @@ export default defineComponent({
return {
tiles: 1000,
image: '',
scoreMode: GameCommon.SCORE_MODE_ANY,
scoreMode: ScoreMode.ANY,
}
},
methods: {

View file

@ -11,6 +11,7 @@ import Game, { Player, Piece } from './../common/GameCommon'
import fireworksController from './Fireworks'
import Protocol from '../common/Protocol'
import Time from '../common/Time'
import { Dim, Point } from '../common/Geometry'
declare global {
interface Window {
@ -34,10 +35,6 @@ export const MODE_REPLAY = 'replay'
let PIECE_VIEW_FIXED = true
let PIECE_VIEW_LOOSE = true
interface Point {
x: number
y: number
}
interface Hud {
setActivePlayers: (v: Array<any>) => void
setIdlePlayers: (v: Array<any>) => void
@ -474,10 +471,16 @@ export async function main(
RERENDER = true
} else if (entryWithTs[0] === Protocol.LOG_UPDATE_PLAYER) {
const playerId = Game.getPlayerIdByIndex(gameId, entryWithTs[1])
if (!playerId) {
throw '[ 2021-05-17 player not found (update player) ]'
}
Game.addPlayer(gameId, playerId, nextTs)
RERENDER = true
} else if (entryWithTs[0] === Protocol.LOG_HANDLE_INPUT) {
const playerId = Game.getPlayerIdByIndex(gameId, entryWithTs[1])
if (!playerId) {
throw '[ 2021-05-17 player not found (handle input) ]'
}
const input = entryWithTs[2]
Game.handleInput(gameId, playerId, input, nextTs)
RERENDER = true
@ -598,9 +601,9 @@ export async function main(
const ts = TIME()
let pos
let dim
let bmp
let pos: Point
let dim: Dim
let bmp: ImageBitmap
if (window.DEBUG) Debug.checkpoint_start(0)

View file

@ -29,7 +29,7 @@
</div>
</template>
<script lang="ts">
import { defineComponent, PropType } from 'vue'
import { defineComponent } from 'vue'
import Scores from './../components/Scores.vue'
import PuzzleStatus from './../components/PuzzleStatus.vue'
@ -39,6 +39,7 @@ import ConnectionOverlay from './../components/ConnectionOverlay.vue'
import HelpOverlay from './../components/HelpOverlay.vue'
import { main, MODE_PLAY } from './../game'
import { Player } from '../../common/GameCommon'
export default defineComponent({
name: 'game',
@ -52,9 +53,8 @@ export default defineComponent({
},
data() {
return {
// TODO: ts Array<Player> type
activePlayers: [] as PropType<Array<any>>,
idlePlayers: [] as PropType<Array<any>>,
activePlayers: [] as Array<Player>,
idlePlayers: [] as Array<Player>,
finished: false,
duration: 0,
@ -103,8 +103,8 @@ export default defineComponent({
MODE_PLAY,
this.$el,
{
setActivePlayers: (v: Array<any>) => { this.activePlayers = v },
setIdlePlayers: (v: Array<any>) => { this.idlePlayers = v },
setActivePlayers: (v: Array<Player>) => { this.activePlayers = v },
setIdlePlayers: (v: Array<Player>) => { this.idlePlayers = v },
setFinished: (v: boolean) => { this.finished = v },
setDuration: (v: number) => { this.duration = v },
setPiecesDone: (v: number) => { this.piecesDone = v },

View file

@ -1,4 +1,4 @@
import GameCommon from './../common/GameCommon'
import GameCommon, { ScoreMode } from './../common/GameCommon'
import Util from './../common/Util'
import { Rng } from './../common/Rng'
import GameLog from './GameLog'
@ -6,7 +6,13 @@ import { createPuzzle } from './Puzzle'
import Protocol from './../common/Protocol'
import GameStorage from './GameStorage'
async function createGameObject(gameId: string, targetTiles: number, image: { file: string, url: string }, ts: number, scoreMode: number) {
async function createGameObject(
gameId: string,
targetTiles: number,
image: { file: string, url: string },
ts: number,
scoreMode: ScoreMode
) {
const seed = Util.hash(gameId + ' ' + ts)
const rng = new Rng(seed)
return {
@ -19,7 +25,13 @@ async function createGameObject(gameId: string, targetTiles: number, image: { fi
}
}
async function createGame(gameId: string, targetTiles: number, image: { file: string, url: string }, ts: number, scoreMode: number) {
async function createGame(
gameId: string,
targetTiles: number,
image: { file: string, url: string },
ts: number,
scoreMode: ScoreMode
) {
const gameObject = await createGameObject(gameId, targetTiles, image, ts, scoreMode)
GameLog.create(gameId)

View file

@ -1,5 +1,5 @@
import fs from 'fs'
import GameCommon from './../common/GameCommon'
import GameCommon, { ScoreMode } from './../common/GameCommon'
import Util, { logger } from './../common/Util'
import { Rng } from './../common/Rng'
import { DATA_DIR } from './Dirs'
@ -55,7 +55,7 @@ function loadGame(gameId: string): void {
puzzle: game.puzzle,
players: game.players,
evtInfos: {},
scoreMode: game.scoreMode || GameCommon.SCORE_MODE_FINAL,
scoreMode: game.scoreMode || ScoreMode.FINAL,
}
GameCommon.setGame(gameObject.id, gameObject)
}

View file

@ -1,6 +1,7 @@
import Util from './../common/Util'
import { Rng } from './../common/Rng'
import Images from './Images'
import { EncodedPiece, EncodedPieceShape, PieceShape } from '../common/GameCommon'
interface PuzzleInfo {
width: number
@ -31,7 +32,7 @@ async function createPuzzle(
if (!dim || !dim.width || !dim.height) {
throw `[ 2021-05-16 invalid dimension for path ${imagePath} ]`
}
const info = determinePuzzleInfo(dim.width, dim.height, targetTiles)
const info: PuzzleInfo = determinePuzzleInfo(dim.width, dim.height, targetTiles)
let tiles = new Array(info.tiles)
for (let i = 0; i < tiles.length; i++) {
@ -91,7 +92,7 @@ async function createPuzzle(
// then shuffle the positions
positions = rng.shuffle(positions)
tiles = tiles.map(tile => {
const pieces: Array<EncodedPiece> = tiles.map(tile => {
return Util.encodeTile({
idx: tile.idx, // index of tile in the array
group: 0, // if grouped with other tiles
@ -113,7 +114,7 @@ async function createPuzzle(
// Complete puzzle object
return {
// tiles array
tiles,
tiles: pieces,
// game data for puzzle, data changes during the game
data: {
// TODO: maybe calculate this each time?
@ -159,10 +160,10 @@ async function createPuzzle(
function determinePuzzleTileShapes(
rng: Rng,
info: PuzzleInfo
) {
): Array<EncodedPieceShape> {
const tabs = [-1, 1]
const shapes = new Array(info.tiles)
const shapes: Array<PieceShape> = new Array(info.tiles)
for (let i = 0; i < info.tiles; i++) {
let coord = Util.coordByTileIdx(info, i)
shapes[i] = {
@ -191,7 +192,11 @@ const determineTilesXY = (w: number, h: number, targetTiles: number) => {
}
}
const determinePuzzleInfo = (w: number, h: number, targetTiles: number) => {
const determinePuzzleInfo = (
w: number,
h: number,
targetTiles: number
): PuzzleInfo => {
const {tilesX, tilesY} = determineTilesXY(w, h, targetTiles)
const tiles = tilesX * tilesY
const tileSize = TILE_SIZE

View file

@ -13,7 +13,7 @@ import GameSockets from './GameSockets'
import Time from './../common/Time'
import Images from './Images'
import { UPLOAD_DIR, UPLOAD_URL, PUBLIC_DIR } from './Dirs'
import GameCommon from '../common/GameCommon'
import GameCommon, { ScoreMode } from '../common/GameCommon'
import GameStorage from './GameStorage'
let configFile = ''
@ -158,7 +158,7 @@ wss.on('message', async ({socket, data} : { socket: WebSocket, data: any }) => {
log[0][2],
log[0][3],
log[0][4],
log[0][5] || GameCommon.SCORE_MODE_FINAL
log[0][5] || ScoreMode.FINAL
)
notify(
[Protocol.EV_SERVER_INIT_REPLAY, Util.encodeGame(game), log],