add shape modes any and flat
This commit is contained in:
parent
b88321bb1b
commit
2d83fd441f
9 changed files with 98 additions and 30 deletions
1
build/public/assets/index.3208e2e9.js
Normal file
1
build/public/assets/index.3208e2e9.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -4,7 +4,7 @@
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
|
|
||||||
<title>🧩 jigsaw.hyottoko.club</title>
|
<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="modulepreload" href="/assets/vendor.18cd2d7e.js">
|
||||||
<link rel="stylesheet" href="/assets/index.f7304069.css">
|
<link rel="stylesheet" href="/assets/index.f7304069.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,12 @@ var ScoreMode;
|
||||||
ScoreMode[ScoreMode["FINAL"] = 0] = "FINAL";
|
ScoreMode[ScoreMode["FINAL"] = 0] = "FINAL";
|
||||||
ScoreMode[ScoreMode["ANY"] = 1] = "ANY";
|
ScoreMode[ScoreMode["ANY"] = 1] = "ANY";
|
||||||
})(ScoreMode || (ScoreMode = {}));
|
})(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 {
|
class Rng {
|
||||||
constructor(seed) {
|
constructor(seed) {
|
||||||
|
|
@ -1433,7 +1439,7 @@ var Images = {
|
||||||
// cut size of each puzzle tile in the
|
// cut size of each puzzle tile in the
|
||||||
// final resized version of the puzzle image
|
// final resized version of the puzzle image
|
||||||
const TILE_SIZE = 64;
|
const TILE_SIZE = 64;
|
||||||
async function createPuzzle(rng, targetTiles, image, ts) {
|
async function createPuzzle(rng, targetTiles, image, ts, shapeMode) {
|
||||||
const imagePath = image.file;
|
const imagePath = image.file;
|
||||||
const imageUrl = image.url;
|
const imageUrl = image.url;
|
||||||
// determine puzzle information from the image dimensions
|
// 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++) {
|
for (let i = 0; i < rawPieces.length; i++) {
|
||||||
rawPieces[i] = { idx: i };
|
rawPieces[i] = { idx: i };
|
||||||
}
|
}
|
||||||
const shapes = determinePuzzleTileShapes(rng, info);
|
const shapes = determinePuzzleTileShapes(rng, info, shapeMode);
|
||||||
let positions = new Array(info.tiles);
|
let positions = new Array(info.tiles);
|
||||||
for (const piece of rawPieces) {
|
for (const piece of rawPieces) {
|
||||||
const coord = Util.coordByPieceIdx(info, piece.idx);
|
const coord = Util.coordByPieceIdx(info, piece.idx);
|
||||||
|
|
@ -1555,8 +1561,19 @@ async function createPuzzle(rng, targetTiles, image, ts) {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
function determinePuzzleTileShapes(rng, info) {
|
function determineTabs(shapeMode) {
|
||||||
const tabs = [-1, 1];
|
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);
|
const shapes = new Array(info.tiles);
|
||||||
for (let i = 0; i < info.tiles; i++) {
|
for (let i = 0; i < info.tiles; i++) {
|
||||||
const coord = Util.coordByPieceIdx(info, i);
|
const coord = Util.coordByPieceIdx(info, i);
|
||||||
|
|
@ -1692,22 +1709,23 @@ var GameStorage = {
|
||||||
setDirty,
|
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 seed = Util.hash(gameId + ' ' + ts);
|
||||||
const rng = new Rng(seed);
|
const rng = new Rng(seed);
|
||||||
return {
|
return {
|
||||||
id: gameId,
|
id: gameId,
|
||||||
rng: { type: 'Rng', obj: rng },
|
rng: { type: 'Rng', obj: rng },
|
||||||
puzzle: await createPuzzle(rng, targetTiles, image, ts),
|
puzzle: await createPuzzle(rng, targetTiles, image, ts, shapeMode),
|
||||||
players: [],
|
players: [],
|
||||||
evtInfos: {},
|
evtInfos: {},
|
||||||
scoreMode,
|
scoreMode,
|
||||||
|
shapeMode,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
async function createGame(gameId, targetTiles, image, ts, scoreMode) {
|
async function createGame(gameId, targetTiles, image, ts, scoreMode, shapeMode) {
|
||||||
const gameObject = await createGameObject(gameId, targetTiles, image, ts, scoreMode);
|
const gameObject = await createGameObject(gameId, targetTiles, image, ts, scoreMode, shapeMode);
|
||||||
GameLog.create(gameId);
|
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);
|
GameCommon.setGame(gameObject.id, gameObject);
|
||||||
GameStorage.setDirty(gameId);
|
GameStorage.setDirty(gameId);
|
||||||
}
|
}
|
||||||
|
|
@ -1981,7 +1999,7 @@ app.get('/api/replay-data', async (req, res) => {
|
||||||
let game = null;
|
let game = null;
|
||||||
if (offset === 0) {
|
if (offset === 0) {
|
||||||
// also need the game
|
// 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 });
|
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();
|
const gameId = Util.uniqId();
|
||||||
if (!GameCommon.exists(gameId)) {
|
if (!GameCommon.exists(gameId)) {
|
||||||
const ts = Time.timestamp();
|
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 });
|
res.send({ id: gameId });
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -73,6 +73,7 @@ export interface Game {
|
||||||
puzzle: Puzzle
|
puzzle: Puzzle
|
||||||
evtInfos: Record<string, EvtInfo>
|
evtInfos: Record<string, EvtInfo>
|
||||||
scoreMode?: ScoreMode
|
scoreMode?: ScoreMode
|
||||||
|
shapeMode?: ShapeMode
|
||||||
rng: GameRng
|
rng: GameRng
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,6 +91,7 @@ export interface GameSettings {
|
||||||
tiles: number
|
tiles: number
|
||||||
image: Image
|
image: Image
|
||||||
scoreMode: ScoreMode
|
scoreMode: ScoreMode
|
||||||
|
shapeMode: ShapeMode
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Puzzle {
|
export interface Puzzle {
|
||||||
|
|
@ -198,3 +200,9 @@ export enum ScoreMode {
|
||||||
FINAL = 0,
|
FINAL = 0,
|
||||||
ANY = 1,
|
ANY = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum ShapeMode {
|
||||||
|
NORMAL = 0,
|
||||||
|
ANY = 1,
|
||||||
|
FLAT = 2,
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,16 @@
|
||||||
<label><input type="radio" v-model="scoreMode" value="0" /> Final (Score when pieces are put to their final location)</label>
|
<label><input type="radio" v-model="scoreMode" value="0" /> Final (Score when pieces are put to their final location)</label>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</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>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -36,7 +46,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue'
|
import { defineComponent } from 'vue'
|
||||||
|
|
||||||
import { GameSettings, ScoreMode } from './../../common/Types'
|
import { GameSettings, ScoreMode, ShapeMode } from './../../common/Types'
|
||||||
import ResponsiveImage from './ResponsiveImage.vue'
|
import ResponsiveImage from './ResponsiveImage.vue'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
|
@ -58,6 +68,7 @@ export default defineComponent({
|
||||||
return {
|
return {
|
||||||
tiles: 1000,
|
tiles: 1000,
|
||||||
scoreMode: ScoreMode.ANY,
|
scoreMode: ScoreMode.ANY,
|
||||||
|
shapeMode: ShapeMode.NORMAL,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
@ -66,6 +77,7 @@ export default defineComponent({
|
||||||
tiles: this.tilesInt,
|
tiles: this.tilesInt,
|
||||||
image: this.image,
|
image: this.image,
|
||||||
scoreMode: this.scoreModeInt,
|
scoreMode: this.scoreModeInt,
|
||||||
|
shapeMode: this.shapeModeInt,
|
||||||
} as GameSettings)
|
} as GameSettings)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -84,6 +96,9 @@ export default defineComponent({
|
||||||
scoreModeInt (): number {
|
scoreModeInt (): number {
|
||||||
return parseInt(`${this.scoreMode}`, 10)
|
return parseInt(`${this.scoreMode}`, 10)
|
||||||
},
|
},
|
||||||
|
shapeModeInt (): number {
|
||||||
|
return parseInt(`${this.shapeMode}`, 10)
|
||||||
|
},
|
||||||
tilesInt (): number {
|
tilesInt (): number {
|
||||||
return parseInt(`${this.tiles}`, 10)
|
return parseInt(`${this.tiles}`, 10)
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import GameCommon from './../common/GameCommon'
|
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 Util, { logger } from './../common/Util'
|
||||||
import { Rng } from './../common/Rng'
|
import { Rng } from './../common/Rng'
|
||||||
import GameLog from './GameLog'
|
import GameLog from './GameLog'
|
||||||
|
|
@ -14,17 +14,19 @@ async function createGameObject(
|
||||||
targetTiles: number,
|
targetTiles: number,
|
||||||
image: PuzzleCreationImageInfo,
|
image: PuzzleCreationImageInfo,
|
||||||
ts: Timestamp,
|
ts: Timestamp,
|
||||||
scoreMode: ScoreMode
|
scoreMode: ScoreMode,
|
||||||
|
shapeMode: ShapeMode
|
||||||
): Promise<Game> {
|
): Promise<Game> {
|
||||||
const seed = Util.hash(gameId + ' ' + ts)
|
const seed = Util.hash(gameId + ' ' + ts)
|
||||||
const rng = new Rng(seed)
|
const rng = new Rng(seed)
|
||||||
return {
|
return {
|
||||||
id: gameId,
|
id: gameId,
|
||||||
rng: { type: 'Rng', obj: rng },
|
rng: { type: 'Rng', obj: rng },
|
||||||
puzzle: await createPuzzle(rng, targetTiles, image, ts),
|
puzzle: await createPuzzle(rng, targetTiles, image, ts, shapeMode),
|
||||||
players: [],
|
players: [],
|
||||||
evtInfos: {},
|
evtInfos: {},
|
||||||
scoreMode,
|
scoreMode,
|
||||||
|
shapeMode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -33,18 +35,29 @@ async function createGame(
|
||||||
targetTiles: number,
|
targetTiles: number,
|
||||||
image: PuzzleCreationImageInfo,
|
image: PuzzleCreationImageInfo,
|
||||||
ts: Timestamp,
|
ts: Timestamp,
|
||||||
scoreMode: ScoreMode
|
scoreMode: ScoreMode,
|
||||||
|
shapeMode: ShapeMode
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const gameObject = await createGameObject(
|
const gameObject = await createGameObject(
|
||||||
gameId,
|
gameId,
|
||||||
targetTiles,
|
targetTiles,
|
||||||
image,
|
image,
|
||||||
ts,
|
ts,
|
||||||
scoreMode
|
scoreMode,
|
||||||
|
shapeMode
|
||||||
)
|
)
|
||||||
|
|
||||||
GameLog.create(gameId)
|
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)
|
GameCommon.setGame(gameObject.id, gameObject)
|
||||||
GameStorage.setDirty(gameId)
|
GameStorage.setDirty(gameId)
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import Util from './../common/Util'
|
import Util from './../common/Util'
|
||||||
import { Rng } from './../common/Rng'
|
import { Rng } from './../common/Rng'
|
||||||
import Images from './Images'
|
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'
|
import { Dim, Point } from '../common/Geometry'
|
||||||
|
|
||||||
export interface PuzzleCreationImageInfo {
|
export interface PuzzleCreationImageInfo {
|
||||||
|
|
@ -28,7 +28,8 @@ async function createPuzzle(
|
||||||
rng: Rng,
|
rng: Rng,
|
||||||
targetTiles: number,
|
targetTiles: number,
|
||||||
image: PuzzleCreationImageInfo,
|
image: PuzzleCreationImageInfo,
|
||||||
ts: number
|
ts: number,
|
||||||
|
shapeMode: ShapeMode
|
||||||
): Promise<Puzzle> {
|
): Promise<Puzzle> {
|
||||||
const imagePath = image.file
|
const imagePath = image.file
|
||||||
const imageUrl = image.url
|
const imageUrl = image.url
|
||||||
|
|
@ -44,7 +45,7 @@ async function createPuzzle(
|
||||||
for (let i = 0; i < rawPieces.length; i++) {
|
for (let i = 0; i < rawPieces.length; i++) {
|
||||||
rawPieces[i] = { idx: i }
|
rawPieces[i] = { idx: i }
|
||||||
}
|
}
|
||||||
const shapes = determinePuzzleTileShapes(rng, info)
|
const shapes = determinePuzzleTileShapes(rng, info, shapeMode)
|
||||||
|
|
||||||
let positions: Point[] = new Array(info.tiles)
|
let positions: Point[] = new Array(info.tiles)
|
||||||
for (const piece of rawPieces) {
|
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(
|
function determinePuzzleTileShapes(
|
||||||
rng: Rng,
|
rng: Rng,
|
||||||
info: PuzzleCreationInfo
|
info: PuzzleCreationInfo,
|
||||||
|
shapeMode: ShapeMode
|
||||||
): Array<EncodedPieceShape> {
|
): Array<EncodedPieceShape> {
|
||||||
const tabs = [-1, 1]
|
const tabs: number[] = determineTabs(shapeMode)
|
||||||
|
|
||||||
const shapes: Array<PieceShape> = new Array(info.tiles)
|
const shapes: Array<PieceShape> = new Array(info.tiles)
|
||||||
for (let i = 0; i < info.tiles; i++) {
|
for (let i = 0; i < info.tiles; i++) {
|
||||||
const coord = Util.coordByPieceIdx(info, i)
|
const coord = Util.coordByPieceIdx(info, i)
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import {
|
||||||
UPLOAD_DIR,
|
UPLOAD_DIR,
|
||||||
} from './Dirs'
|
} from './Dirs'
|
||||||
import GameCommon from '../common/GameCommon'
|
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 GameStorage from './GameStorage'
|
||||||
import Db from './Db'
|
import Db from './Db'
|
||||||
|
|
||||||
|
|
@ -89,7 +89,8 @@ app.get('/api/replay-data', async (req, res): Promise<void> => {
|
||||||
log[0][2],
|
log[0][2],
|
||||||
log[0][3],
|
log[0][3],
|
||||||
log[0][4],
|
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 })
|
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.tiles,
|
||||||
gameSettings.image,
|
gameSettings.image,
|
||||||
ts,
|
ts,
|
||||||
gameSettings.scoreMode
|
gameSettings.scoreMode,
|
||||||
|
gameSettings.shapeMode
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
res.send({ id: gameId })
|
res.send({ id: gameId })
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue