增加题目发送,和积分更新机制

This commit is contained in:
zhl 2021-04-29 20:49:35 +08:00
parent 9f795bf415
commit 6d0f821f04
6 changed files with 168 additions and 30 deletions

View File

@ -8,30 +8,23 @@ import {
import { ZError } from '../../common/ZError'
import { BaseConst } from '../../constants/BaseConst'
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 { retry } from '../../utils/promise.util'
import { RoomLockErr } from '../../common/RoomLockErr'
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 {
@role('anon')
@ -59,7 +52,8 @@ class PuzzleController extends BaseController {
@role('anon')
@router('post /api/:accountid/puzzle/answer')
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) {
throw new ZError(11, 'param mismatch')
}
@ -79,7 +73,7 @@ class PuzzleController extends BaseController {
throw new ZError(16, 'current question not in current match')
}
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')
}
let record = await Puzzle.findById(id)
@ -90,8 +84,7 @@ class PuzzleController extends BaseController {
if (type == 1) {
result = 0
}
statMap.answer.push(result)
statMap.questions.push(id)
statMap.answer.set(id, result)
if (result == 1) {
statMap.rightCount++
statMap.comboCount++
@ -103,6 +96,13 @@ class PuzzleController extends BaseController {
history.status = 1
history.markModified('members')
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 }
}
@ -132,6 +132,8 @@ class PuzzleController extends BaseController {
if (history && !history.hasExpired()) {
new RoomState().unlock(shop)
beginTime = history.begin
history.members.set(accountid, new PuzzleStatusClass())
await history.save()
return roomId = history.room
} else {
let rsp = await createRoom(data)
@ -145,15 +147,14 @@ class PuzzleController extends BaseController {
history.room = roomId
//TODO: 根据配置赋值
const beginSecond = 20 * 1000
history.total = 10
history.begin = Date.now() + beginSecond
beginTime = history.begin
history.expire = history.begin + (100 || 90) * 1000
history.type = 1
await history.save()
new Schedule().beginSchedule(beginSecond, async function () {
await beginGame(roomId, {})
history.status = 1
await history.save()
await startGame(roomId, history)
}, shop)
new RoomState().unlock(shop)
return roomId

View File

@ -1,4 +1,5 @@
import BaseController from '../../common/base.controller'
import { role, router } from '../../decorators/router'
class ServerController extends BaseController {

View File

@ -2,4 +2,6 @@ export class BaseConst{
public static readonly COMPOUND = 'compound'
public static readonly MISSION = 'mission'
public static readonly RANK_SCORE = 'rank_score'
// 多人答题时间
public static readonly MATCH_ANSWER_TIME = 10000
}

View File

@ -10,11 +10,9 @@ import { Base, TimeStamps } from '@typegoose/typegoose/lib/defaultClasses'
})
export class PuzzleStatusClass {
@prop({default: []})
answer: number[]
@prop({ type: Number, default: new Map() })
answer: Map<string, number>
@prop({ type: () => [String], default: [] })
questions: string[]
/**
*
* @type {number}
@ -71,6 +69,19 @@ export class PuzzleSessionClass extends BaseModule {
@prop({default: 0})
public type: number
/**
*
* @type {number}
*/
@prop({default: 0})
public current: number
/**
*
* @type {number}
*/
@prop()
public total: number
/**
*
* 0: 未开始答题
@ -93,6 +104,10 @@ export class PuzzleSessionClass extends BaseModule {
public hasExpired(): boolean {
return this.expire < Date.now()
}
public get scheduleKey() {
return this.room + this._id
}
}
export const PuzzleSession = getModelForClass(PuzzleSessionClass, { existingConnection: PuzzleSessionClass.db })

74
src/services/GameLogic.ts Normal file
View 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)
}

View File

@ -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) {
const url = `${apiBase}/matchmake/joinOrCreate/puzzle_room`
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
})
}