add shape modes any and flat

This commit is contained in:
Zutatensuppe 2021-06-03 09:07:57 +02:00
parent b88321bb1b
commit 2d83fd441f
9 changed files with 98 additions and 30 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

@ -4,7 +4,7 @@
<meta charset="UTF-8">
<title>🧩 jigsaw.hyottoko.club</title>
<script type="module" crossorigin src="/assets/index.3ca85e0f.js"></script>
<script type="module" crossorigin src="/assets/index.3208e2e9.js"></script>
<link rel="modulepreload" href="/assets/vendor.18cd2d7e.js">
<link rel="stylesheet" href="/assets/index.f7304069.css">
</head>

View file

@ -24,6 +24,12 @@ var ScoreMode;
ScoreMode[ScoreMode["FINAL"] = 0] = "FINAL";
ScoreMode[ScoreMode["ANY"] = 1] = "ANY";
})(ScoreMode || (ScoreMode = {}));
var ShapeMode;
(function (ShapeMode) {
ShapeMode[ShapeMode["NORMAL"] = 0] = "NORMAL";
ShapeMode[ShapeMode["ANY"] = 1] = "ANY";
ShapeMode[ShapeMode["FLAT"] = 2] = "FLAT";
})(ShapeMode || (ShapeMode = {}));
class Rng {
constructor(seed) {
@ -1433,7 +1439,7 @@ var Images = {
// cut size of each puzzle tile in the
// final resized version of the puzzle image
const TILE_SIZE = 64;
async function createPuzzle(rng, targetTiles, image, ts) {
async function createPuzzle(rng, targetTiles, image, ts, shapeMode) {
const imagePath = image.file;
const imageUrl = image.url;
// determine puzzle information from the image dimensions
@ -1446,7 +1452,7 @@ async function createPuzzle(rng, targetTiles, image, ts) {
for (let i = 0; i < rawPieces.length; i++) {
rawPieces[i] = { idx: i };
}
const shapes = determinePuzzleTileShapes(rng, info);
const shapes = determinePuzzleTileShapes(rng, info, shapeMode);
let positions = new Array(info.tiles);
for (const piece of rawPieces) {
const coord = Util.coordByPieceIdx(info, piece.idx);
@ -1555,8 +1561,19 @@ async function createPuzzle(rng, targetTiles, image, ts) {
},
};
}
function determinePuzzleTileShapes(rng, info) {
const tabs = [-1, 1];
function determineTabs(shapeMode) {
switch (shapeMode) {
case ShapeMode.ANY:
return [-1, 0, 1];
case ShapeMode.FLAT:
return [0];
case ShapeMode.NORMAL:
default:
return [-1, 1];
}
}
function determinePuzzleTileShapes(rng, info, shapeMode) {
const tabs = determineTabs(shapeMode);
const shapes = new Array(info.tiles);
for (let i = 0; i < info.tiles; i++) {
const coord = Util.coordByPieceIdx(info, i);
@ -1692,22 +1709,23 @@ var GameStorage = {
setDirty,
};
async function createGameObject(gameId, targetTiles, image, ts, scoreMode) {
async function createGameObject(gameId, targetTiles, image, ts, scoreMode, shapeMode) {
const seed = Util.hash(gameId + ' ' + ts);
const rng = new Rng(seed);
return {
id: gameId,
rng: { type: 'Rng', obj: rng },
puzzle: await createPuzzle(rng, targetTiles, image, ts),
puzzle: await createPuzzle(rng, targetTiles, image, ts, shapeMode),
players: [],
evtInfos: {},
scoreMode,
shapeMode,
};
}
async function createGame(gameId, targetTiles, image, ts, scoreMode) {
const gameObject = await createGameObject(gameId, targetTiles, image, ts, scoreMode);
async function createGame(gameId, targetTiles, image, ts, scoreMode, shapeMode) {
const gameObject = await createGameObject(gameId, targetTiles, image, ts, scoreMode, shapeMode);
GameLog.create(gameId);
GameLog.log(gameId, Protocol.LOG_HEADER, 1, targetTiles, image, ts, scoreMode);
GameLog.log(gameId, Protocol.LOG_HEADER, 1, targetTiles, image, ts, scoreMode, shapeMode);
GameCommon.setGame(gameObject.id, gameObject);
GameStorage.setDirty(gameId);
}
@ -1981,7 +1999,7 @@ app.get('/api/replay-data', async (req, res) => {
let game = null;
if (offset === 0) {
// also need the game
game = await Game.createGameObject(gameId, log[0][2], log[0][3], log[0][4], log[0][5] || ScoreMode.FINAL);
game = await Game.createGameObject(gameId, log[0][2], log[0][3], log[0][4], log[0][5] || ScoreMode.FINAL, log[0][6] || ShapeMode.NORMAL);
}
res.send({ log, game: game ? Util.encodeGame(game) : null });
});
@ -2069,7 +2087,7 @@ app.post('/api/newgame', express.json(), async (req, res) => {
const gameId = Util.uniqId();
if (!GameCommon.exists(gameId)) {
const ts = Time.timestamp();
await Game.createGame(gameId, gameSettings.tiles, gameSettings.image, ts, gameSettings.scoreMode);
await Game.createGame(gameId, gameSettings.tiles, gameSettings.image, ts, gameSettings.scoreMode, gameSettings.shapeMode);
}
res.send({ id: gameId });
});

View file

@ -73,6 +73,7 @@ export interface Game {
puzzle: Puzzle
evtInfos: Record<string, EvtInfo>
scoreMode?: ScoreMode
shapeMode?: ShapeMode
rng: GameRng
}
@ -90,6 +91,7 @@ export interface GameSettings {
tiles: number
image: Image
scoreMode: ScoreMode
shapeMode: ShapeMode
}
export interface Puzzle {
@ -198,3 +200,9 @@ export enum ScoreMode {
FINAL = 0,
ANY = 1,
}
export enum ShapeMode {
NORMAL = 0,
ANY = 1,
FLAT = 2,
}

View file

@ -22,6 +22,16 @@
<label><input type="radio" v-model="scoreMode" value="0" /> Final (Score when pieces are put to their final location)</label>
</td>
</tr>
<tr>
<td><label>shapes: </label></td>
<td>
<label><input type="radio" v-model="shapeMode" value="0" /> Normal</label>
<br />
<label><input type="radio" v-model="shapeMode" value="1" /> Any (flat pieces can occur anywhere)</label>
<br />
<label><input type="radio" v-model="shapeMode" value="2" /> Flat (all pieces flat on all sides)</label>
</td>
</tr>
</table>
</div>
@ -36,7 +46,7 @@
<script lang="ts">
import { defineComponent } from 'vue'
import { GameSettings, ScoreMode } from './../../common/Types'
import { GameSettings, ScoreMode, ShapeMode } from './../../common/Types'
import ResponsiveImage from './ResponsiveImage.vue'
export default defineComponent({
@ -58,6 +68,7 @@ export default defineComponent({
return {
tiles: 1000,
scoreMode: ScoreMode.ANY,
shapeMode: ShapeMode.NORMAL,
}
},
methods: {
@ -66,6 +77,7 @@ export default defineComponent({
tiles: this.tilesInt,
image: this.image,
scoreMode: this.scoreModeInt,
shapeMode: this.shapeModeInt,
} as GameSettings)
},
},
@ -84,6 +96,9 @@ export default defineComponent({
scoreModeInt (): number {
return parseInt(`${this.scoreMode}`, 10)
},
shapeModeInt (): number {
return parseInt(`${this.shapeMode}`, 10)
},
tilesInt (): number {
return parseInt(`${this.tiles}`, 10)
},

View file

@ -1,5 +1,5 @@
import GameCommon from './../common/GameCommon'
import { Change, Game, Input, ScoreMode, Timestamp } from './../common/Types'
import { Change, Game, Input, ScoreMode, ShapeMode, Timestamp } from './../common/Types'
import Util, { logger } from './../common/Util'
import { Rng } from './../common/Rng'
import GameLog from './GameLog'
@ -14,17 +14,19 @@ async function createGameObject(
targetTiles: number,
image: PuzzleCreationImageInfo,
ts: Timestamp,
scoreMode: ScoreMode
scoreMode: ScoreMode,
shapeMode: ShapeMode
): Promise<Game> {
const seed = Util.hash(gameId + ' ' + ts)
const rng = new Rng(seed)
return {
id: gameId,
rng: { type: 'Rng', obj: rng },
puzzle: await createPuzzle(rng, targetTiles, image, ts),
puzzle: await createPuzzle(rng, targetTiles, image, ts, shapeMode),
players: [],
evtInfos: {},
scoreMode,
shapeMode,
}
}
@ -33,18 +35,29 @@ async function createGame(
targetTiles: number,
image: PuzzleCreationImageInfo,
ts: Timestamp,
scoreMode: ScoreMode
scoreMode: ScoreMode,
shapeMode: ShapeMode
): Promise<void> {
const gameObject = await createGameObject(
gameId,
targetTiles,
image,
ts,
scoreMode
scoreMode,
shapeMode
)
GameLog.create(gameId)
GameLog.log(gameId, Protocol.LOG_HEADER, 1, targetTiles, image, ts, scoreMode)
GameLog.log(
gameId,
Protocol.LOG_HEADER,
1,
targetTiles,
image,
ts,
scoreMode,
shapeMode
)
GameCommon.setGame(gameObject.id, gameObject)
GameStorage.setDirty(gameId)

View file

@ -1,7 +1,7 @@
import Util from './../common/Util'
import { Rng } from './../common/Rng'
import Images from './Images'
import { EncodedPiece, EncodedPieceShape, PieceShape, Puzzle } from '../common/Types'
import { EncodedPiece, EncodedPieceShape, PieceShape, Puzzle, ShapeMode } from '../common/Types'
import { Dim, Point } from '../common/Geometry'
export interface PuzzleCreationImageInfo {
@ -28,7 +28,8 @@ async function createPuzzle(
rng: Rng,
targetTiles: number,
image: PuzzleCreationImageInfo,
ts: number
ts: number,
shapeMode: ShapeMode
): Promise<Puzzle> {
const imagePath = image.file
const imageUrl = image.url
@ -44,7 +45,7 @@ async function createPuzzle(
for (let i = 0; i < rawPieces.length; i++) {
rawPieces[i] = { idx: i }
}
const shapes = determinePuzzleTileShapes(rng, info)
const shapes = determinePuzzleTileShapes(rng, info, shapeMode)
let positions: Point[] = new Array(info.tiles)
for (const piece of rawPieces) {
@ -162,13 +163,24 @@ async function createPuzzle(
},
}
}
function determineTabs (shapeMode: ShapeMode): number[] {
switch(shapeMode) {
case ShapeMode.ANY:
return [-1, 0, 1]
case ShapeMode.FLAT:
return [0]
case ShapeMode.NORMAL:
default:
return [-1, 1]
}
}
function determinePuzzleTileShapes(
rng: Rng,
info: PuzzleCreationInfo
info: PuzzleCreationInfo,
shapeMode: ShapeMode
): Array<EncodedPieceShape> {
const tabs = [-1, 1]
const tabs: number[] = determineTabs(shapeMode)
const shapes: Array<PieceShape> = new Array(info.tiles)
for (let i = 0; i < info.tiles; i++) {
const coord = Util.coordByPieceIdx(info, i)

View file

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