enhance(reversi): tweak reversi
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import * as Redis from 'ioredis';
|
||||
import * as Reversi from 'misskey-reversi';
|
||||
import type { MiChannel } from '@/models/Channel.js';
|
||||
import type { MiUser } from '@/models/User.js';
|
||||
import type { MiUserProfile } from '@/models/UserProfile.js';
|
||||
@@ -179,12 +180,7 @@ export interface ReversiGameEventTypes {
|
||||
key: string;
|
||||
value: any;
|
||||
};
|
||||
putStone: {
|
||||
at: number;
|
||||
color: boolean;
|
||||
pos: number;
|
||||
next: boolean;
|
||||
};
|
||||
log: Reversi.Serializer.Log & { id: string | null };
|
||||
syncState: {
|
||||
crc32: string;
|
||||
};
|
||||
|
@@ -235,11 +235,14 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
|
||||
|
||||
const map = freshGame.map != null ? freshGame.map : getRandomMap();
|
||||
|
||||
const crc32 = CRC32.str(JSON.stringify(freshGame.logs)).toString();
|
||||
|
||||
await this.reversiGamesRepository.update(game.id, {
|
||||
startedAt: new Date(),
|
||||
isStarted: true,
|
||||
black: bw,
|
||||
map: map,
|
||||
crc32,
|
||||
});
|
||||
|
||||
//#region 盤面に最初から石がないなどして始まった瞬間に勝敗が決定する場合があるのでその処理
|
||||
@@ -309,7 +312,7 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public async putStoneToGame(game: MiReversiGame, user: MiUser, pos: number) {
|
||||
public async putStoneToGame(game: MiReversiGame, user: MiUser, pos: number, id?: string | null) {
|
||||
if (!game.isStarted) return;
|
||||
if (game.isEnded) return;
|
||||
if ((game.user1Id !== user.id) && (game.user2Id !== user.id)) return;
|
||||
@@ -319,56 +322,58 @@ export class ReversiService implements OnApplicationShutdown, OnModuleInit {
|
||||
? true
|
||||
: false;
|
||||
|
||||
const o = new Reversi.Game(game.map, {
|
||||
const engine = Reversi.Serializer.restoreGame({
|
||||
map: game.map,
|
||||
isLlotheo: game.isLlotheo,
|
||||
canPutEverywhere: game.canPutEverywhere,
|
||||
loopedBoard: game.loopedBoard,
|
||||
logs: game.logs,
|
||||
});
|
||||
|
||||
// 盤面の状態を再生
|
||||
for (const log of game.logs) {
|
||||
o.put(log.color, log.pos);
|
||||
}
|
||||
if (engine.turn !== myColor) return;
|
||||
if (!engine.canPut(myColor, pos)) return;
|
||||
|
||||
if (o.turn !== myColor) return;
|
||||
|
||||
if (!o.canPut(myColor, pos)) return;
|
||||
o.put(myColor, pos);
|
||||
engine.putStone(pos);
|
||||
|
||||
let winner;
|
||||
if (o.isEnded) {
|
||||
if (o.winner === true) {
|
||||
if (engine.isEnded) {
|
||||
if (engine.winner === true) {
|
||||
winner = game.black === 1 ? game.user1Id : game.user2Id;
|
||||
} else if (o.winner === false) {
|
||||
} else if (engine.winner === false) {
|
||||
winner = game.black === 1 ? game.user2Id : game.user1Id;
|
||||
} else {
|
||||
winner = null;
|
||||
}
|
||||
}
|
||||
|
||||
const logs = Reversi.Serializer.deserializeLogs(game.logs);
|
||||
|
||||
const log = {
|
||||
at: Date.now(),
|
||||
color: myColor,
|
||||
time: Date.now(),
|
||||
player: myColor,
|
||||
operation: 'put',
|
||||
pos,
|
||||
};
|
||||
} as const;
|
||||
|
||||
const crc32 = CRC32.str(game.logs.map(x => x.pos.toString()).join('') + pos.toString()).toString();
|
||||
logs.push(log);
|
||||
|
||||
game.logs.push(log);
|
||||
const serializeLogs = Reversi.Serializer.serializeLogs(logs);
|
||||
|
||||
const crc32 = CRC32.str(JSON.stringify(serializeLogs)).toString();
|
||||
|
||||
await this.reversiGamesRepository.update(game.id, {
|
||||
crc32,
|
||||
isEnded: o.isEnded,
|
||||
isEnded: engine.isEnded,
|
||||
winnerId: winner,
|
||||
logs: game.logs,
|
||||
logs: serializeLogs,
|
||||
});
|
||||
|
||||
this.globalEventService.publishReversiGameStream(game.id, 'putStone', {
|
||||
this.globalEventService.publishReversiGameStream(game.id, 'log', {
|
||||
...log,
|
||||
next: o.turn,
|
||||
id: id ?? null,
|
||||
});
|
||||
|
||||
if (o.isEnded) {
|
||||
if (engine.isEnded) {
|
||||
this.globalEventService.publishReversiGameStream(game.id, 'ended', {
|
||||
winnerId: winner ?? null,
|
||||
game: await this.reversiGameEntityService.packDetail(game.id, user),
|
||||
|
@@ -55,11 +55,7 @@ export class ReversiGameEntityService {
|
||||
isLlotheo: game.isLlotheo,
|
||||
canPutEverywhere: game.canPutEverywhere,
|
||||
loopedBoard: game.loopedBoard,
|
||||
logs: game.logs.map(log => ({
|
||||
at: log.at,
|
||||
color: log.color,
|
||||
pos: log.pos,
|
||||
})),
|
||||
logs: game.logs,
|
||||
map: game.map,
|
||||
});
|
||||
}
|
||||
|
@@ -76,11 +76,7 @@ export class MiReversiGame {
|
||||
@Column('jsonb', {
|
||||
default: [],
|
||||
})
|
||||
public logs: {
|
||||
at: number;
|
||||
color: boolean;
|
||||
pos: number;
|
||||
}[];
|
||||
public logs: number[][];
|
||||
|
||||
@Column('varchar', {
|
||||
array: true, length: 64,
|
||||
@@ -117,9 +113,6 @@ export class MiReversiGame {
|
||||
})
|
||||
public form2: any | null;
|
||||
|
||||
/**
|
||||
* ログのposを文字列としてすべて連結したもののCRC32値
|
||||
*/
|
||||
@Column('varchar', {
|
||||
length: 32, nullable: true,
|
||||
})
|
||||
|
@@ -204,22 +204,8 @@ export const packedReversiGameDetailedSchema = {
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
items: {
|
||||
type: 'object',
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
properties: {
|
||||
at: {
|
||||
type: 'number',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
color: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
pos: {
|
||||
type: 'number',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
map: {
|
||||
|
@@ -45,7 +45,7 @@ class ReversiGameChannel extends Channel {
|
||||
switch (type) {
|
||||
case 'ready': this.ready(body); break;
|
||||
case 'updateSettings': this.updateSettings(body.key, body.value); break;
|
||||
case 'putStone': this.putStone(body.pos); break;
|
||||
case 'putStone': this.putStone(body.pos, body.id); break;
|
||||
case 'syncState': this.syncState(body.crc32); break;
|
||||
}
|
||||
}
|
||||
@@ -72,14 +72,14 @@ class ReversiGameChannel extends Channel {
|
||||
}
|
||||
|
||||
@bindThis
|
||||
private async putStone(pos: number) {
|
||||
private async putStone(pos: number, id: string) {
|
||||
if (this.user == null) return;
|
||||
|
||||
// TODO: キャッシュしたい
|
||||
const game = await this.reversiGamesRepository.findOneBy({ id: this.gameId! });
|
||||
if (game == null) throw new Error('game not found');
|
||||
|
||||
this.reversiService.putStoneToGame(game, this.user, pos);
|
||||
this.reversiService.putStoneToGame(game, this.user, pos, id);
|
||||
}
|
||||
|
||||
@bindThis
|
||||
|
Reference in New Issue
Block a user