增加题目发送,和积分更新机制
This commit is contained in:
parent
9f795bf415
commit
6d0f821f04
@ -8,30 +8,23 @@ import {
|
|||||||
import { ZError } from '../../common/ZError'
|
import { ZError } from '../../common/ZError'
|
||||||
import { BaseConst } from '../../constants/BaseConst'
|
import { BaseConst } from '../../constants/BaseConst'
|
||||||
import { mission_vo } from '../../config/parsers/mission_vo'
|
import { mission_vo } from '../../config/parsers/mission_vo'
|
||||||
import { beginGame, createRoom } from '../../services/WsSvr'
|
import {
|
||||||
|
beginGame,
|
||||||
|
broadcast,
|
||||||
|
createRoom,
|
||||||
|
sendQuestion, updateScore
|
||||||
|
} from '../../services/WsSvr'
|
||||||
import { RoomState } from '../../services/RoomState'
|
import { RoomState } from '../../services/RoomState'
|
||||||
import { retry } from '../../utils/promise.util'
|
import { retry } from '../../utils/promise.util'
|
||||||
import { RoomLockErr } from '../../common/RoomLockErr'
|
import { RoomLockErr } from '../../common/RoomLockErr'
|
||||||
import { Schedule } from '../../clock/Schedule'
|
import { Schedule } from '../../clock/Schedule'
|
||||||
import { createDeflateRaw } from 'zlib'
|
import {
|
||||||
|
checkSubFinish, sendOneQuestion,
|
||||||
|
startGame,
|
||||||
|
transformRecord
|
||||||
|
} from '../../services/GameLogic'
|
||||||
|
|
||||||
|
|
||||||
const transformRecord = function (records: any[]) {
|
|
||||||
return records.map(o => {
|
|
||||||
let answers = []
|
|
||||||
for (let i = 1; i <= 4; i++) {
|
|
||||||
if (o[`a${ i }`]) {
|
|
||||||
answers.push(o[`a${ i }`])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
answers.randomSort()
|
|
||||||
return {
|
|
||||||
id: o._id,
|
|
||||||
title: o.question,
|
|
||||||
answers,
|
|
||||||
type: 1
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
class PuzzleController extends BaseController {
|
class PuzzleController extends BaseController {
|
||||||
@role('anon')
|
@role('anon')
|
||||||
@ -59,7 +52,8 @@ class PuzzleController extends BaseController {
|
|||||||
@role('anon')
|
@role('anon')
|
||||||
@router('post /api/:accountid/puzzle/answer')
|
@router('post /api/:accountid/puzzle/answer')
|
||||||
async report(req, res) {
|
async report(req, res) {
|
||||||
let { id, answer, type, session, accountid } = req.params
|
let { id, answer, type, session, accountid, mode } = req.params
|
||||||
|
mode = mode || 0
|
||||||
if (!id || !session) {
|
if (!id || !session) {
|
||||||
throw new ZError(11, 'param mismatch')
|
throw new ZError(11, 'param mismatch')
|
||||||
}
|
}
|
||||||
@ -79,7 +73,7 @@ class PuzzleController extends BaseController {
|
|||||||
throw new ZError(16, 'current question not in current match')
|
throw new ZError(16, 'current question not in current match')
|
||||||
}
|
}
|
||||||
let statMap = history.members.get(accountid)
|
let statMap = history.members.get(accountid)
|
||||||
if (statMap.questions.find(o => o == id)) {
|
if (statMap.answer.has(id)) {
|
||||||
throw new ZError(15, 'current question already answered')
|
throw new ZError(15, 'current question already answered')
|
||||||
}
|
}
|
||||||
let record = await Puzzle.findById(id)
|
let record = await Puzzle.findById(id)
|
||||||
@ -90,8 +84,7 @@ class PuzzleController extends BaseController {
|
|||||||
if (type == 1) {
|
if (type == 1) {
|
||||||
result = 0
|
result = 0
|
||||||
}
|
}
|
||||||
statMap.answer.push(result)
|
statMap.answer.set(id, result)
|
||||||
statMap.questions.push(id)
|
|
||||||
if (result == 1) {
|
if (result == 1) {
|
||||||
statMap.rightCount++
|
statMap.rightCount++
|
||||||
statMap.comboCount++
|
statMap.comboCount++
|
||||||
@ -103,6 +96,13 @@ class PuzzleController extends BaseController {
|
|||||||
history.status = 1
|
history.status = 1
|
||||||
history.markModified('members')
|
history.markModified('members')
|
||||||
await history.save()
|
await history.save()
|
||||||
|
if (mode == 1) {
|
||||||
|
let score = result ? 3 : -1
|
||||||
|
await updateScore(history.room, [{accountid, score }])
|
||||||
|
if (checkSubFinish(history, id)) {
|
||||||
|
await sendOneQuestion(history)
|
||||||
|
}
|
||||||
|
}
|
||||||
return { result, answer: record.a1, stats: history.members }
|
return { result, answer: record.a1, stats: history.members }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,6 +132,8 @@ class PuzzleController extends BaseController {
|
|||||||
if (history && !history.hasExpired()) {
|
if (history && !history.hasExpired()) {
|
||||||
new RoomState().unlock(shop)
|
new RoomState().unlock(shop)
|
||||||
beginTime = history.begin
|
beginTime = history.begin
|
||||||
|
history.members.set(accountid, new PuzzleStatusClass())
|
||||||
|
await history.save()
|
||||||
return roomId = history.room
|
return roomId = history.room
|
||||||
} else {
|
} else {
|
||||||
let rsp = await createRoom(data)
|
let rsp = await createRoom(data)
|
||||||
@ -145,15 +147,14 @@ class PuzzleController extends BaseController {
|
|||||||
history.room = roomId
|
history.room = roomId
|
||||||
//TODO: 根据配置赋值
|
//TODO: 根据配置赋值
|
||||||
const beginSecond = 20 * 1000
|
const beginSecond = 20 * 1000
|
||||||
|
history.total = 10
|
||||||
history.begin = Date.now() + beginSecond
|
history.begin = Date.now() + beginSecond
|
||||||
beginTime = history.begin
|
beginTime = history.begin
|
||||||
history.expire = history.begin + (100 || 90) * 1000
|
history.expire = history.begin + (100 || 90) * 1000
|
||||||
history.type = 1
|
history.type = 1
|
||||||
await history.save()
|
await history.save()
|
||||||
new Schedule().beginSchedule(beginSecond, async function () {
|
new Schedule().beginSchedule(beginSecond, async function () {
|
||||||
await beginGame(roomId, {})
|
await startGame(roomId, history)
|
||||||
history.status = 1
|
|
||||||
await history.save()
|
|
||||||
}, shop)
|
}, shop)
|
||||||
new RoomState().unlock(shop)
|
new RoomState().unlock(shop)
|
||||||
return roomId
|
return roomId
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import BaseController from '../../common/base.controller'
|
import BaseController from '../../common/base.controller'
|
||||||
|
import { role, router } from '../../decorators/router'
|
||||||
|
|
||||||
class ServerController extends BaseController {
|
class ServerController extends BaseController {
|
||||||
|
|
||||||
|
@ -2,4 +2,6 @@ export class BaseConst{
|
|||||||
public static readonly COMPOUND = 'compound'
|
public static readonly COMPOUND = 'compound'
|
||||||
public static readonly MISSION = 'mission'
|
public static readonly MISSION = 'mission'
|
||||||
public static readonly RANK_SCORE = 'rank_score'
|
public static readonly RANK_SCORE = 'rank_score'
|
||||||
|
// 多人答题时间
|
||||||
|
public static readonly MATCH_ANSWER_TIME = 10000
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,9 @@ import { Base, TimeStamps } from '@typegoose/typegoose/lib/defaultClasses'
|
|||||||
})
|
})
|
||||||
export class PuzzleStatusClass {
|
export class PuzzleStatusClass {
|
||||||
|
|
||||||
@prop({default: []})
|
@prop({ type: Number, default: new Map() })
|
||||||
answer: number[]
|
answer: Map<string, number>
|
||||||
|
|
||||||
@prop({ type: () => [String], default: [] })
|
|
||||||
questions: string[]
|
|
||||||
/**
|
/**
|
||||||
* 打对数量
|
* 打对数量
|
||||||
* @type {number}
|
* @type {number}
|
||||||
@ -71,6 +69,19 @@ export class PuzzleSessionClass extends BaseModule {
|
|||||||
@prop({default: 0})
|
@prop({default: 0})
|
||||||
public type: number
|
public type: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前的问题
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
@prop({default: 0})
|
||||||
|
public current: number
|
||||||
|
/**
|
||||||
|
* 一共多少问题
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
@prop()
|
||||||
|
public total: number
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 比赛状态
|
* 比赛状态
|
||||||
* 0: 未开始答题
|
* 0: 未开始答题
|
||||||
@ -93,6 +104,10 @@ export class PuzzleSessionClass extends BaseModule {
|
|||||||
public hasExpired(): boolean {
|
public hasExpired(): boolean {
|
||||||
return this.expire < Date.now()
|
return this.expire < Date.now()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get scheduleKey() {
|
||||||
|
return this.room + this._id
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PuzzleSession = getModelForClass(PuzzleSessionClass, { existingConnection: PuzzleSessionClass.db })
|
export const PuzzleSession = getModelForClass(PuzzleSessionClass, { existingConnection: PuzzleSessionClass.db })
|
||||||
|
74
src/services/GameLogic.ts
Normal file
74
src/services/GameLogic.ts
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import { beginGame, endGame, sendQuestion, updateScore } from './WsSvr'
|
||||||
|
import { Puzzle } from '../models/content/Puzzle'
|
||||||
|
import { Schedule } from '../clock/Schedule'
|
||||||
|
import { BaseConst } from '../constants/BaseConst'
|
||||||
|
|
||||||
|
|
||||||
|
export function transformRecord(records: any[]) {
|
||||||
|
return records.map(o => {
|
||||||
|
let answers = []
|
||||||
|
for (let i = 1; i <= 4; i++) {
|
||||||
|
if (o[`a${ i }`]) {
|
||||||
|
answers.push(o[`a${ i }`])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
answers.randomSort()
|
||||||
|
return {
|
||||||
|
id: o._id,
|
||||||
|
title: o.question,
|
||||||
|
answers,
|
||||||
|
type: 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function checkSubFinish(history: any, qid: string) {
|
||||||
|
let count = 0
|
||||||
|
for (let [key, val] of history.members) {
|
||||||
|
if (val.has(qid)) {
|
||||||
|
count ++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count >= history.questions.length;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 开始游戏
|
||||||
|
* @param {string} roomId
|
||||||
|
* @param history
|
||||||
|
* @return {Promise<void>}
|
||||||
|
*/
|
||||||
|
export async function startGame(roomId: string, history: any) {
|
||||||
|
await beginGame(roomId, {})
|
||||||
|
let records = await Puzzle.randomQuestions({}, history.total)
|
||||||
|
history.questions = records.map(o => o._id)
|
||||||
|
await history.save()
|
||||||
|
await sendOneQuestion(history)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function sendOneQuestion(history: any) {
|
||||||
|
const roomId = history.room
|
||||||
|
new Schedule().stopSchedule(history.scheduleKey)
|
||||||
|
if (history.current >= history.questions.length) {
|
||||||
|
console.log('match over')
|
||||||
|
await endGame(roomId, {})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let qid = history.questions[history.current]
|
||||||
|
let record = await Puzzle.findById(qid)
|
||||||
|
let qdata: any = transformRecord([record])[0]
|
||||||
|
qdata.no = history.current
|
||||||
|
await sendQuestion(roomId, qdata)
|
||||||
|
history.current ++
|
||||||
|
await history.save()
|
||||||
|
new Schedule().beginSchedule(BaseConst.MATCH_ANSWER_TIME, async function (){
|
||||||
|
let datas = []
|
||||||
|
for (let [accountid, data] of history.members) {
|
||||||
|
if (!data.answer.has(qid)) {
|
||||||
|
datas.push({accountid, score: -1})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await updateScore(history.room, datas)
|
||||||
|
await sendOneQuestion(history)
|
||||||
|
}, history.scheduleKey)
|
||||||
|
}
|
@ -85,8 +85,53 @@ export async function beginGame(roomId, params) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function endGame(roomId, params) {
|
||||||
|
console.log(`end game: ${roomId}, ${params}`)
|
||||||
|
const url = `${apiBase}/room/call`
|
||||||
|
const args = [params]
|
||||||
|
const data = {
|
||||||
|
roomId,
|
||||||
|
method: 'endGame',
|
||||||
|
args: JSON.stringify(args)
|
||||||
|
}
|
||||||
|
return axios.post(url, data)
|
||||||
|
.then(res => {
|
||||||
|
return res.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建房间
|
||||||
|
* @param data
|
||||||
|
* @return {Promise<AxiosResponse<any>>}
|
||||||
|
*/
|
||||||
export async function createRoom(data) {
|
export async function createRoom(data) {
|
||||||
const url = `${apiBase}/matchmake/joinOrCreate/puzzle_room`
|
const url = `${apiBase}/matchmake/joinOrCreate/puzzle_room`
|
||||||
return axios.post(url, data)
|
return axios.post(url, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送一条问题
|
||||||
|
* @param {string} roomId
|
||||||
|
* @param data
|
||||||
|
* @return {Promise<AxiosResponse<any>>}
|
||||||
|
*/
|
||||||
|
export async function sendQuestion(roomId: string, data: any) {
|
||||||
|
console.log(`sendOneQuestion to ${roomId}, ${JSON.stringify(data)}`)
|
||||||
|
return broadcast(roomId, 'question', data)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function updateScore(roomId: string, data: any) {
|
||||||
|
console.log(`updateScore: ${roomId}, ${JSON.stringify(data)}`)
|
||||||
|
const url = `${apiBase}/room/call`
|
||||||
|
const args = [data]
|
||||||
|
const params = {
|
||||||
|
roomId,
|
||||||
|
method: 'updateScore',
|
||||||
|
args: JSON.stringify(args)
|
||||||
|
}
|
||||||
|
return axios.post(url, params)
|
||||||
|
.then(res => {
|
||||||
|
return res.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user