add other snap mode

This commit is contained in:
Zutatensuppe 2021-06-04 09:26:37 +02:00
parent 42aaf10679
commit 2a12900614
11 changed files with 164 additions and 27 deletions

View file

@ -16,6 +16,7 @@ import {
PuzzleData,
PuzzleDataChange,
ScoreMode,
SnapMode,
Timestamp
} from './Types'
import Util from './Util'
@ -172,6 +173,10 @@ function getScoreMode(gameId: string): ScoreMode {
return GAMES[gameId].scoreMode || ScoreMode.FINAL
}
function getSnapMode(gameId: string): SnapMode {
return GAMES[gameId].snapMode || SnapMode.NORMAL
}
function isFinished(gameId: string): boolean {
return getFinishedPiecesCount(gameId) === getPieceCount(gameId)
}
@ -237,6 +242,16 @@ const getPieceGroup = (gameId: string, tileIdx: number): number => {
return tile.group
}
const isCornerPiece = (gameId: string, tileIdx: number): boolean => {
const info = GAMES[gameId].puzzle.info
return (
tileIdx === 0 // top left corner
|| tileIdx === (info.tilesX - 1) // top right corner
|| tileIdx === (info.tiles - info.tilesX) // bottom left corner
|| tileIdx === (info.tiles - 1) // bottom right corner
)
}
const getFinalPiecePos = (gameId: string, tileIdx: number): Point => {
const info = GAMES[gameId].puzzle.info
const boardPos = {
@ -406,6 +421,14 @@ const movePiecesDiff = (
}
}
const isFinishedPiece = (gameId: string, pieceIdx: number): boolean => {
return getPieceOwner(gameId, pieceIdx) === -1
}
const getPieceOwner = (gameId: string, pieceIdx: number): string|number => {
return getPiece(gameId, pieceIdx).owner
}
const finishPieces = (gameId: string, pieceIdxs: Array<number>): void => {
for (const pieceIdx of pieceIdxs) {
changePiece(gameId, pieceIdx, { owner: -1, z: 1 })
@ -721,7 +744,26 @@ function handleInput(
// Check if the tile was dropped near the final location
const tilePos = getPiecePos(gameId, pieceIdx)
const finalPos = getFinalPiecePos(gameId, pieceIdx)
if (Geometry.pointDistance(finalPos, tilePos) < puzzle.info.snapDistance) {
let canSnapToFinal = false
console.log(getSnapMode(gameId))
if (getSnapMode(gameId) === SnapMode.REAL) {
// only can snap to final if any of the grouped pieces are
// corner pieces
for (const pieceIdxTmp of pieceIdxs) {
if (isCornerPiece(gameId, pieceIdxTmp)) {
canSnapToFinal = true
break
}
}
} else {
canSnapToFinal = true
}
if (
canSnapToFinal
&& Geometry.pointDistance(finalPos, tilePos) < puzzle.info.snapDistance
) {
const diff = Geometry.pointSub(finalPos, tilePos)
// Snap the tile to the final destination
movePiecesDiff(gameId, pieceIdxs, diff)
@ -774,8 +816,12 @@ function handleInput(
movePiecesDiff(gameId, pieceIdxs, diff)
groupTiles(gameId, tileIdx, otherTileIdx)
pieceIdxs = getGroupedPieceIdxs(gameId, tileIdx)
const zIndex = getMaxZIndexByPieceIdxs(gameId, pieceIdxs)
setPiecesZIndex(gameId, pieceIdxs, zIndex)
if (isFinishedPiece(gameId, otherTileIdx)) {
finishPieces(gameId, pieceIdxs)
} else {
const zIndex = getMaxZIndexByPieceIdxs(gameId, pieceIdxs)
setPiecesZIndex(gameId, pieceIdxs, zIndex)
}
_pieceChanges(pieceIdxs)
return true
}

View file

@ -49,6 +49,8 @@ export type EncodedGame = FixedLengthArray<[
Array<EncodedPlayer>,
Record<string, EvtInfo>,
ScoreMode,
ShapeMode,
SnapMode,
]>
export interface ReplayData {
@ -75,6 +77,7 @@ export interface Game {
evtInfos: Record<string, EvtInfo>
scoreMode?: ScoreMode
shapeMode?: ShapeMode
snapMode?: SnapMode
rng: GameRng
}
@ -93,6 +96,7 @@ export interface GameSettings {
image: Image
scoreMode: ScoreMode
shapeMode: ShapeMode
snapMode: SnapMode
}
export interface Puzzle {
@ -207,3 +211,8 @@ export enum ShapeMode {
ANY = 1,
FLAT = 2,
}
export enum SnapMode {
NORMAL = 0,
REAL = 1,
}

View file

@ -9,7 +9,9 @@ import {
PieceShape,
Player,
PuzzleInfo,
ScoreMode
ScoreMode,
ShapeMode,
SnapMode
} from './Types'
import { Point } from './Geometry'
import { Rng } from './Rng'
@ -129,6 +131,8 @@ function encodeGame(data: Game): EncodedGame {
data.players,
data.evtInfos,
data.scoreMode || ScoreMode.FINAL,
data.shapeMode || ShapeMode.ANY,
data.snapMode || SnapMode.NORMAL,
]
}
@ -143,6 +147,8 @@ function decodeGame(data: EncodedGame): Game {
players: data[4],
evtInfos: data[5],
scoreMode: data[6],
shapeMode: data[7],
snapMode: data[8],
}
}

View file

@ -32,6 +32,14 @@
<label><input type="radio" v-model="shapeMode" value="2" /> Flat (all pieces flat on all sides)</label>
</td>
</tr>
<tr>
<td><label>Snapping: </label></td>
<td>
<label><input type="radio" v-model="snapMode" value="0" /> Normal (pieces snap to final destination and to each other)</label>
<br />
<label><input type="radio" v-model="snapMode" value="1" /> Real (pieces snap only to corners, already snapped pieces and to each other)</label>
</td>
</tr>
</table>
</div>
@ -46,7 +54,7 @@
<script lang="ts">
import { defineComponent } from 'vue'
import { GameSettings, ScoreMode, ShapeMode } from './../../common/Types'
import { GameSettings, ScoreMode, ShapeMode, SnapMode } from './../../common/Types'
import ResponsiveImage from './ResponsiveImage.vue'
export default defineComponent({
@ -69,6 +77,7 @@ export default defineComponent({
tiles: 1000,
scoreMode: ScoreMode.ANY,
shapeMode: ShapeMode.NORMAL,
snapMode: SnapMode.NORMAL,
}
},
methods: {
@ -78,6 +87,7 @@ export default defineComponent({
image: this.image,
scoreMode: this.scoreModeInt,
shapeMode: this.shapeModeInt,
snapMode: this.snapModeInt,
} as GameSettings)
},
},
@ -99,6 +109,9 @@ export default defineComponent({
shapeModeInt (): number {
return parseInt(`${this.shapeMode}`, 10)
},
snapModeInt (): number {
return parseInt(`${this.snapMode}`, 10)
},
tilesInt (): number {
return parseInt(`${this.tiles}`, 10)
},

View file

@ -1,5 +1,5 @@
import GameCommon from './../common/GameCommon'
import { Change, Game, Input, ScoreMode, ShapeMode, Timestamp } from './../common/Types'
import { Change, Game, Input, ScoreMode, ShapeMode, SnapMode, Timestamp } from './../common/Types'
import Util, { logger } from './../common/Util'
import { Rng } from './../common/Rng'
import GameLog from './GameLog'
@ -15,7 +15,8 @@ async function createGameObject(
image: PuzzleCreationImageInfo,
ts: Timestamp,
scoreMode: ScoreMode,
shapeMode: ShapeMode
shapeMode: ShapeMode,
snapMode: SnapMode
): Promise<Game> {
const seed = Util.hash(gameId + ' ' + ts)
const rng = new Rng(seed)
@ -27,6 +28,7 @@ async function createGameObject(
evtInfos: {},
scoreMode,
shapeMode,
snapMode,
}
}
@ -36,7 +38,8 @@ async function createGame(
image: PuzzleCreationImageInfo,
ts: Timestamp,
scoreMode: ScoreMode,
shapeMode: ShapeMode
shapeMode: ShapeMode,
snapMode: SnapMode
): Promise<void> {
const gameObject = await createGameObject(
gameId,
@ -44,7 +47,8 @@ async function createGame(
image,
ts,
scoreMode,
shapeMode
shapeMode,
snapMode
)
GameLog.create(gameId)
@ -56,7 +60,8 @@ async function createGame(
image,
ts,
scoreMode,
shapeMode
shapeMode,
snapMode
)
GameCommon.setGame(gameObject.id, gameObject)

View file

@ -1,6 +1,6 @@
import fs from 'fs'
import GameCommon from './../common/GameCommon'
import { Piece, ScoreMode } from './../common/Types'
import { Game, Piece, ScoreMode, ShapeMode, SnapMode } from './../common/Types'
import Util, { logger } from './../common/Util'
import { Rng } from './../common/Rng'
import { DATA_DIR } from './Dirs'
@ -49,7 +49,7 @@ function loadGame(gameId: string): void {
if (!Array.isArray(game.players)) {
game.players = Object.values(game.players)
}
const gameObject = {
const gameObject: Game = {
id: game.id,
rng: {
type: game.rng ? game.rng.type : '_fake_',
@ -59,6 +59,8 @@ function loadGame(gameId: string): void {
players: game.players,
evtInfos: {},
scoreMode: game.scoreMode || ScoreMode.FINAL,
shapeMode: game.shapeMode || ShapeMode.ANY,
snapMode: game.snapMode || SnapMode.NORMAL,
}
GameCommon.setGame(gameObject.id, gameObject)
}
@ -88,6 +90,8 @@ function persistGame(gameId: string): void {
puzzle: game.puzzle,
players: game.players,
scoreMode: game.scoreMode,
shapeMode: game.shapeMode,
snapMode: game.snapMode,
}))
log.info(`[INFO] persisted game ${game.id}`)
}

View file

@ -19,7 +19,7 @@ import {
UPLOAD_DIR,
} from './Dirs'
import GameCommon from '../common/GameCommon'
import { ServerEvent, Game as GameType, GameSettings, ScoreMode, ShapeMode } from '../common/Types'
import { ServerEvent, Game as GameType, GameSettings, ScoreMode, ShapeMode, SnapMode } from '../common/Types'
import GameStorage from './GameStorage'
import Db from './Db'
@ -90,7 +90,8 @@ app.get('/api/replay-data', async (req, res): Promise<void> => {
log[0][3],
log[0][4],
log[0][5] || ScoreMode.FINAL,
log[0][6] || ShapeMode.NORMAL
log[0][6] || ShapeMode.NORMAL,
log[0][7] || SnapMode.NORMAL,
)
}
res.send({ log, game: game ? Util.encodeGame(game) : null })
@ -203,7 +204,8 @@ app.post('/api/newgame', express.json(), async (req, res): Promise<void> => {
gameSettings.image,
ts,
gameSettings.scoreMode,
gameSettings.shapeMode
gameSettings.shapeMode,
gameSettings.snapMode,
)
}
res.send({ id: gameId })