wip
This commit is contained in:
parent
084e9449dc
commit
bb042b46ac
5 changed files with 44 additions and 13 deletions
|
@ -657,8 +657,7 @@ export class MahjongService implements OnApplicationShutdown, OnModuleInit {
|
|||
|
||||
if (mj.riichis[house]) {
|
||||
// リーチ時はアガリ牌でない限りツモ切り
|
||||
const horaSets = Mmj.getHoraSets(mj.handTileTypes[house]);
|
||||
if (horaSets.length === 0) {
|
||||
if (!Mmj.canHora(mj.handTileTypes[house])) {
|
||||
setTimeout(() => {
|
||||
this.dahai(room, mj, house, mj.handTiles[house].at(-1));
|
||||
}, 500);
|
||||
|
|
|
@ -292,7 +292,7 @@ const isMyTurn = computed(() => {
|
|||
});
|
||||
|
||||
const canHora = computed(() => {
|
||||
return Mmj.getHoraSets(mj.value.myHandTileTypes).length > 0;
|
||||
return Mmj.canHora(mj.value.myHandTileTypes).length;
|
||||
});
|
||||
|
||||
const selectableTiles = ref<Mmj.TileType[] | null>(null);
|
||||
|
|
|
@ -237,6 +237,8 @@ export const PREV_TILE_FOR_SHUNTSU: Record<TileType, TileType | null> = {
|
|||
chun: null,
|
||||
};
|
||||
|
||||
const KOKUSHI_TILES: TileType[] = ['m1', 'm9', 'p1', 'p9', 's1', 's9', 'e', 's', 'w', 'n', 'haku', 'hatsu', 'chun'];
|
||||
|
||||
type EnvForCalcYaku = {
|
||||
house: House;
|
||||
|
||||
|
@ -471,7 +473,7 @@ export const YAKU_DEFINITIONS = [{
|
|||
|
||||
// TODO: 両面待ちかどうか
|
||||
|
||||
const horaSets = getHoraSets(state.handTiles.concat(state.tsumoTile ?? state.ronTile));
|
||||
const horaSets = analyze1head3mentsuSets(state.handTiles.concat(state.tsumoTile ?? state.ronTile));
|
||||
return horaSets.some(horaSet => {
|
||||
// 風牌判定(役牌でなければOK)
|
||||
if (horaSet.head === state.seatWind) return false;
|
||||
|
@ -489,7 +491,7 @@ export const YAKU_DEFINITIONS = [{
|
|||
// 面前じゃないとダメ
|
||||
if (state.huros.some(huro => CALL_HURO_TYPES.includes(huro.type))) return false;
|
||||
|
||||
const horaSets = getHoraSets(state.handTiles.concat(state.tsumoTile ?? state.ronTile));
|
||||
const horaSets = analyze1head3mentsuSets(state.handTiles.concat(state.tsumoTile ?? state.ronTile));
|
||||
return horaSets.some(horaSet => {
|
||||
// 同じ順子が2つあるか?
|
||||
return horaSet.mentsus.some((mentsu) =>
|
||||
|
@ -505,12 +507,26 @@ export const YAKU_DEFINITIONS = [{
|
|||
if (state.huros.length > 0) {
|
||||
if (state.huros.some(huro => huro.type === 'cii')) return false;
|
||||
}
|
||||
const horaSets = getHoraSets(state.handTiles.concat(state.tsumoTile ?? state.ronTile));
|
||||
const horaSets = analyze1head3mentsuSets(state.handTiles.concat(state.tsumoTile ?? state.ronTile));
|
||||
return horaSets.some(horaSet => {
|
||||
// 全て刻子か?
|
||||
if (!horaSet.mentsus.every((mentsu) => mentsu[0] === mentsu[1])) return false;
|
||||
});
|
||||
},
|
||||
}, {
|
||||
name: 'chitoitsu',
|
||||
fan: 2,
|
||||
isYakuman: false,
|
||||
calc: (state: EnvForCalcYaku) => {
|
||||
return isChitoitsu(state.handTiles.concat(state.tsumoTile ?? state.ronTile));
|
||||
},
|
||||
}, {
|
||||
name: 'kokushi',
|
||||
fan: 13,
|
||||
isYakuman: true,
|
||||
calc: (state: EnvForCalcYaku) => {
|
||||
return isKokushi(state.handTiles.concat(state.tsumoTile ?? state.ronTile));
|
||||
},
|
||||
}];
|
||||
|
||||
export function fanToPoint(fan: number, isParent: boolean): number {
|
||||
|
@ -709,7 +725,7 @@ function extractShuntsus(tiles: TileType[]): [TileType, TileType, TileType][] {
|
|||
* @param handTiles ポン、チー、カンした牌を含まない手牌
|
||||
* @returns
|
||||
*/
|
||||
export function getHoraSets(handTiles: TileType[]): HoraSet[] {
|
||||
function analyze1head3mentsuSets(handTiles: TileType[]): HoraSet[] {
|
||||
const horaSets: HoraSet[] = [];
|
||||
|
||||
const headSet: TileType[] = [];
|
||||
|
@ -808,6 +824,14 @@ export function getHoraSets(handTiles: TileType[]): HoraSet[] {
|
|||
return horaSets;
|
||||
}
|
||||
|
||||
export function canHora(handTiles: TileType[]): boolean {
|
||||
if (isKokushi(handTiles)) return true;
|
||||
if (isChitoitsu(handTiles)) return true;
|
||||
|
||||
const horaSets = analyze1head3mentsuSets(handTiles);
|
||||
return horaSets.length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* アガリ牌リストを取得
|
||||
* @param handTiles ポン、チー、カンした牌を含まない手牌
|
||||
|
@ -815,14 +839,23 @@ export function getHoraSets(handTiles: TileType[]): HoraSet[] {
|
|||
export function getHoraTiles(handTiles: TileType[]): TileType[] {
|
||||
return TILE_TYPES.filter(tile => {
|
||||
const tempHandTiles = [...handTiles, tile];
|
||||
const horaSets = getHoraSets(tempHandTiles);
|
||||
const horaSets = analyze1head3mentsuSets(tempHandTiles);
|
||||
return horaSets.length > 0;
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: 国士無双判定関数
|
||||
function isKokushi(handTiles: TileType[]): boolean {
|
||||
return KOKUSHI_TILES.every(t => handTiles.includes(t));
|
||||
}
|
||||
|
||||
// TODO: 七対子判定関数
|
||||
function isChitoitsu(handTiles: TileType[]): boolean {
|
||||
const countMap = new Map<TileType, number>();
|
||||
for (const tile of handTiles) {
|
||||
const count = (countMap.get(tile) ?? 0) + 1;
|
||||
countMap.set(tile, count);
|
||||
}
|
||||
return Array.from(countMap.values()).every(c => c === 2);
|
||||
}
|
||||
|
||||
export function getTilesForRiichi(handTiles: TileType[]): TileType[] {
|
||||
return handTiles.filter(tile => {
|
||||
|
|
|
@ -108,8 +108,7 @@ class StateManager {
|
|||
// TODO: ポンされるなどして自分の河にない場合の考慮
|
||||
if (this.hoTileTypes[house].includes($type(tid))) return false;
|
||||
|
||||
const horaSets = Common.getHoraSets(this.handTileTypes[house].concat($type(tid)));
|
||||
if (horaSets.length === 0) return false; // 完成形じゃない
|
||||
if (!Common.canHora(this.handTileTypes[house].concat($type(tid)))) return false; // 完成形じゃない
|
||||
|
||||
// TODO
|
||||
//const yakus = YAKU_DEFINITIONS.filter(yaku => yaku.calc(this.state, { tsumoTile: null, ronTile: tile }));
|
||||
|
|
|
@ -218,7 +218,7 @@ export class PlayerGameEngine {
|
|||
|
||||
if (house === this.myHouse) {
|
||||
} else {
|
||||
const canRon = Common.getHoraSets(this.myHandTiles.concat(tid).map(id => $type(id))).length > 0;
|
||||
const canRon = Common.canHora(this.myHandTiles.concat(tid).map(id => $type(id)));
|
||||
const canPon = !this.isMeRiichi && this.myHandTileTypes.filter(t => t === $type(tid)).length === 2;
|
||||
const canKan = !this.isMeRiichi && this.myHandTileTypes.filter(t => t === $type(tid)).length === 3;
|
||||
const canCii = !this.isMeRiichi && house === Common.prevHouse(this.myHouse) &&
|
||||
|
|
Loading…
Reference in a new issue