修改题目获取方式
This commit is contained in:
parent
96ec66d881
commit
a0f5746af8
10
doc/api.md
10
doc/api.md
@ -29,8 +29,9 @@
|
|||||||
|
|
||||||
| 字段 | 说明 |
|
| 字段 | 说明 |
|
||||||
| -------- | -------------------------------------- |
|
| -------- | -------------------------------------- |
|
||||||
| shop | 店铺id |
|
| shop | 店铺id, 比如 607ff59d4a4e16687a3b7079 |
|
||||||
| level | 关卡id |
|
| level | 关卡id |
|
||||||
|
| type | 是否降低难度 0: 普通, 1: 降低难度 |
|
||||||
|
|
||||||
3. Response: JSON
|
3. Response: JSON
|
||||||
|
|
||||||
@ -47,7 +48,8 @@
|
|||||||
"刘永福"
|
"刘永福"
|
||||||
],
|
],
|
||||||
"category": "体育-体育", // 类型
|
"category": "体育-体育", // 类型
|
||||||
"type": 1 // 题目类型 1: 普通的文字选择题, 2: 图形
|
"type": 1, // 题目类型 1: 普通的文字选择题, 2: 图形
|
||||||
|
"quality": 1 // 题目难度
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,6 +139,7 @@
|
|||||||
| -------- | -------------------------------------- |
|
| -------- | -------------------------------------- |
|
||||||
| count | 需要获取的数量 |
|
| count | 需要获取的数量 |
|
||||||
| session | 当局的id, 从关卡题目列表中获取 |
|
| session | 当局的id, 从关卡题目列表中获取 |
|
||||||
|
| quality | 难度 |
|
||||||
|
|
||||||
3. Response: JSON
|
3. Response: JSON
|
||||||
|
|
||||||
@ -151,7 +154,8 @@
|
|||||||
"刘永福"
|
"刘永福"
|
||||||
],
|
],
|
||||||
"category": "体育-体育", // 类型
|
"category": "体育-体育", // 类型
|
||||||
"type": 1 // 题目类型 1: 普通的文字选择题, 2: 图形
|
"type": 1, // 题目类型 1: 普通的文字选择题, 2: 图形
|
||||||
|
"quality": 1 // 题目难度
|
||||||
}]
|
}]
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,25 +18,44 @@ 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 { calcScore, startGame, transformRecord } from '../../services/GameLogic'
|
import {
|
||||||
|
calcScore, calcSingleScore,
|
||||||
|
checkSingleFinish, fetchLevelCfg, fetchSinglePuzzleType,
|
||||||
|
startGame,
|
||||||
|
transformRecord, updateSingleRank
|
||||||
|
} from '../../services/GameLogic'
|
||||||
import { ObjectId } from 'bson'
|
import { ObjectId } from 'bson'
|
||||||
|
import { Shop } from '../../models/shop/Shop'
|
||||||
|
import { isObjectId } from '../../utils/string.util'
|
||||||
|
|
||||||
|
|
||||||
class PuzzleController extends BaseController {
|
class PuzzleController extends BaseController {
|
||||||
|
//TODO:: 增加字段, 表明该次是普通开局还是降低难度开局
|
||||||
@role('anon')
|
@role('anon')
|
||||||
@router('post /api/:accountid/puzzle/list')
|
@router('post /api/:accountid/puzzle/list')
|
||||||
async list(req, res) {
|
async list(req, res) {
|
||||||
let { shop, level, accountid } = req.params
|
let { shop, level, accountid, type } = req.params
|
||||||
level = +level || 1
|
level = +level || 1
|
||||||
const cfgs: mission_vo[] = Array.from(global.$cfg.get(BaseConst.MISSION).values())
|
if (!shop || isObjectId(shop)) {
|
||||||
const cfg = cfgs.find(o => o.number == level) || cfgs[cfgs.length - 1]
|
throw new ZError(10, '没有店铺id或者店铺id格式不正确, 测试使用: 607ff59d4a4e16687a3b7079')
|
||||||
let count = cfg.beforehand_enemy || 10
|
}
|
||||||
let records = await Puzzle.randomQuestions({}, count)
|
const cfg = fetchLevelCfg(level)
|
||||||
|
let params = {}
|
||||||
|
let typeArr = await fetchSinglePuzzleType({shopId: shop, levelCfg: cfg})
|
||||||
|
if (typeArr?.length > 0) {
|
||||||
|
params = {$or: [{tag: {$in: typeArr}}, {sub_tag: {$in: typeArr}}]}
|
||||||
|
}
|
||||||
|
let record1 = await Puzzle.randomQuestions(Object.assign(params, {quality: 1}), 5)
|
||||||
|
let record2 = await Puzzle.randomQuestions(Object.assign(params, {quality: 2}), 5)
|
||||||
|
let record3 = await Puzzle.randomQuestions(Object.assign(params, {quality: 3}), 5)
|
||||||
|
const records = (record1.concat(record2)).concat(record3)
|
||||||
let history = new PuzzleSession({ shop, level })
|
let history = new PuzzleSession({ shop, level })
|
||||||
history.members.set(accountid, new PuzzleStatusClass())
|
history.members.set(accountid, new PuzzleStatusClass())
|
||||||
history.questions = records.map(o => o._id)
|
history.questions = records.map(o => o._id)
|
||||||
history.expire = Date.now() + (cfg.time || 90) * 1000
|
history.expire = Date.now() + (cfg.time || 90) * 1000
|
||||||
history.type = 0
|
history.type = 0
|
||||||
|
history.difficultyMode = type || 0
|
||||||
|
history.qtypes = typeArr
|
||||||
await history.save()
|
await history.save()
|
||||||
const results = transformRecord(records)
|
const results = transformRecord(records)
|
||||||
return {
|
return {
|
||||||
@ -100,6 +119,23 @@ class PuzzleController extends BaseController {
|
|||||||
// if (checkSubFinish(history, id)) {
|
// if (checkSubFinish(history, id)) {
|
||||||
// await sendOneQuestion(history)
|
// await sendOneQuestion(history)
|
||||||
// }
|
// }
|
||||||
|
} else if (mode == 0) {
|
||||||
|
let result = checkSingleFinish(history)
|
||||||
|
if (result) {
|
||||||
|
history.status = 9
|
||||||
|
//TODO:: 计算积分, 并更新排行榜
|
||||||
|
let score = calcSingleScore()
|
||||||
|
let rankObj = {
|
||||||
|
shop: history.shop,
|
||||||
|
level: history.level,
|
||||||
|
accountId: accountid,
|
||||||
|
score,
|
||||||
|
mode: 0,
|
||||||
|
session: history.id
|
||||||
|
}
|
||||||
|
await updateSingleRank(rankObj)
|
||||||
|
await history.save()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return { result, answer: record.a1, stats: history.members }
|
return { result, answer: record.a1, stats: history.members }
|
||||||
}
|
}
|
||||||
@ -107,7 +143,7 @@ class PuzzleController extends BaseController {
|
|||||||
@role('anon')
|
@role('anon')
|
||||||
@router('post /api/:accountid/puzzle/more')
|
@router('post /api/:accountid/puzzle/more')
|
||||||
async moreLevelQuestions(req, res) {
|
async moreLevelQuestions(req, res) {
|
||||||
let {session,accountid, count} = req.params
|
let {session,accountid, count, quality} = req.params
|
||||||
count = count ? +count : 10
|
count = count ? +count : 10
|
||||||
if (!session) {
|
if (!session) {
|
||||||
throw new ZError(11, 'param mismatch')
|
throw new ZError(11, 'param mismatch')
|
||||||
@ -125,7 +161,13 @@ class PuzzleController extends BaseController {
|
|||||||
throw new ZError(14, 'not in current match')
|
throw new ZError(14, 'not in current match')
|
||||||
}
|
}
|
||||||
let ids = history.questions.map(o => new ObjectId(o))
|
let ids = history.questions.map(o => new ObjectId(o))
|
||||||
let options = {'_id': {$nin: ids}}
|
let options: any = {'_id': {$nin: ids}}
|
||||||
|
if (quality) {
|
||||||
|
options.quality = quality
|
||||||
|
}
|
||||||
|
if (history.qtypes.length > 0) {
|
||||||
|
Object.assign(options, {$or: [{tag: {$in: history.qtypes}}, {sub_tag: {$in: history.qtypes}}]})
|
||||||
|
}
|
||||||
let records = await Puzzle.randomQuestions(options, count)
|
let records = await Puzzle.randomQuestions(options, count)
|
||||||
const results = transformRecord(records)
|
const results = transformRecord(records)
|
||||||
history.questions = history.questions.concat(records.map(o => o._id))
|
history.questions = history.questions.concat(records.map(o => o._id))
|
||||||
|
@ -7,7 +7,7 @@ export class mission_vo implements Cfg{
|
|||||||
public number: number;
|
public number: number;
|
||||||
public commonlyadd: number;
|
public commonlyadd: number;
|
||||||
public hardadd: number;
|
public hardadd: number;
|
||||||
public hp: number;
|
public lastdif: number;
|
||||||
public hp: number;
|
public hp: number;
|
||||||
public hpstar: number;
|
public hpstar: number;
|
||||||
public time: number;
|
public time: number;
|
||||||
@ -22,7 +22,7 @@ export class mission_vo implements Cfg{
|
|||||||
this.number = data.number;
|
this.number = data.number;
|
||||||
this.commonlyadd = data.commonlyadd;
|
this.commonlyadd = data.commonlyadd;
|
||||||
this.hardadd = data.hardadd;
|
this.hardadd = data.hardadd;
|
||||||
this.hp = data.hp;
|
this.lastdif = data.lastdif;
|
||||||
this.hp = data.hp;
|
this.hp = data.hp;
|
||||||
this.hpstar = data.hpstar;
|
this.hpstar = data.hpstar;
|
||||||
this.time = data.time;
|
this.time = data.time;
|
||||||
|
@ -99,7 +99,7 @@ class PuzzleClass extends BaseModule {
|
|||||||
}
|
}
|
||||||
public static async randomQuestions(this: ReturnModelType<typeof PuzzleClass>, options: any, count: number) {
|
public static async randomQuestions(this: ReturnModelType<typeof PuzzleClass>, options: any, count: number) {
|
||||||
let filters = {status: 1, is_hide: 0, deleted: 0, dp: 1}
|
let filters = {status: 1, is_hide: 0, deleted: 0, dp: 1}
|
||||||
Object.assign(options)
|
Object.assign(filters, options)
|
||||||
return Puzzle.aggregate([
|
return Puzzle.aggregate([
|
||||||
{ $match: filters },
|
{ $match: filters },
|
||||||
{ $sample: { size: count } }
|
{ $sample: { size: count } }
|
||||||
|
39
src/models/match/PuzzleRank.ts
Normal file
39
src/models/match/PuzzleRank.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { BaseModule } from '../Base'
|
||||||
|
import { dbconn } from '../../decorators/dbconn'
|
||||||
|
import {
|
||||||
|
getModelForClass,
|
||||||
|
index,
|
||||||
|
modelOptions,
|
||||||
|
prop
|
||||||
|
} from '@typegoose/typegoose'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排名数据
|
||||||
|
*/
|
||||||
|
@dbconn()
|
||||||
|
@index({ shop: 1, level: 1, accountId: 1, mode: 1}, { unique: true })
|
||||||
|
@modelOptions({ schemaOptions: { collection: 'puzzle_rank', timestamps: true } })
|
||||||
|
export class PuzzleRankClass extends BaseModule {
|
||||||
|
@prop()
|
||||||
|
public shop: string
|
||||||
|
|
||||||
|
@prop()
|
||||||
|
public level: number
|
||||||
|
|
||||||
|
@prop()
|
||||||
|
public accountId: string
|
||||||
|
|
||||||
|
@prop()
|
||||||
|
public score: number
|
||||||
|
|
||||||
|
@prop()
|
||||||
|
public session: string
|
||||||
|
|
||||||
|
@prop()
|
||||||
|
public mode: number
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PuzzleRank = getModelForClass(PuzzleRankClass, { existingConnection: PuzzleRankClass.db })
|
@ -73,6 +73,15 @@ export class PuzzleSessionClass extends BaseModule {
|
|||||||
@prop({default: 0})
|
@prop({default: 0})
|
||||||
public type: number
|
public type: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 模式
|
||||||
|
* 0: 普通
|
||||||
|
* 1: 减低难度
|
||||||
|
* @type {number}
|
||||||
|
*/
|
||||||
|
@prop({default: 0})
|
||||||
|
public difficultyMode: number
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当前的问题
|
* 当前的问题
|
||||||
* @type {number}
|
* @type {number}
|
||||||
@ -95,6 +104,13 @@ export class PuzzleSessionClass extends BaseModule {
|
|||||||
*/
|
*/
|
||||||
@prop({default: 0})
|
@prop({default: 0})
|
||||||
public status: number
|
public status: number
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 已选择的题库分类
|
||||||
|
* @type {string[]}
|
||||||
|
*/
|
||||||
|
@prop()
|
||||||
|
public qtypes: string[]
|
||||||
/**
|
/**
|
||||||
* 开始时间
|
* 开始时间
|
||||||
* 对于多人比赛来说, 需要一个自动开始时间
|
* 对于多人比赛来说, 需要一个自动开始时间
|
||||||
|
@ -11,6 +11,10 @@ import { BaseConst } from '../constants/BaseConst'
|
|||||||
import { QCategoryCache } from './QCategoryCache'
|
import { QCategoryCache } from './QCategoryCache'
|
||||||
import { PuzzleSession } from '../models/match/PuzzleSession'
|
import { PuzzleSession } from '../models/match/PuzzleSession'
|
||||||
import { GameEnv } from '../config/GameEnv'
|
import { GameEnv } from '../config/GameEnv'
|
||||||
|
import { PuzzleRank } from '../models/match/PuzzleRank'
|
||||||
|
import { Shop } from '../models/shop/Shop'
|
||||||
|
import { mission_vo } from '../config/parsers/mission_vo'
|
||||||
|
import { ShopActivity } from '../models/shop/ShopActivity'
|
||||||
|
|
||||||
|
|
||||||
export function transformRecord(records: any[]) {
|
export function transformRecord(records: any[]) {
|
||||||
@ -112,3 +116,100 @@ export function calcScore(timeKey: string, combo: number) {
|
|||||||
const cfg = new GameEnv()
|
const cfg = new GameEnv()
|
||||||
return cfg.pvpBaseScore + time / 100 * cfg.pvpTimeRate + combo * cfg.pvpComboRate
|
return cfg.pvpBaseScore + time / 100 * cfg.pvpTimeRate + combo * cfg.pvpComboRate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新排行榜
|
||||||
|
* @param {string} shop 店铺id
|
||||||
|
* @param {number} level 关卡id
|
||||||
|
* @param {string} accountId 帐号id
|
||||||
|
* @param {number} score 分数
|
||||||
|
* @param {string} session
|
||||||
|
* @param {number} mode 模式: 0: 单人 1: pvp
|
||||||
|
* @return {Promise<void>}
|
||||||
|
*/
|
||||||
|
export async function updateSingleRank({shop, level, accountId, score, session, mode }
|
||||||
|
: {shop: string,
|
||||||
|
level: number,
|
||||||
|
accountId: string,
|
||||||
|
score: number,
|
||||||
|
mode: number
|
||||||
|
session: string}) {
|
||||||
|
|
||||||
|
let record = (await PuzzleRank.findOrCreate({shop, level, accountId, mode})).doc
|
||||||
|
if (record.score < score) {
|
||||||
|
record.score = score
|
||||||
|
record.session = session
|
||||||
|
await record.save()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO::
|
||||||
|
* 单人模式检查游戏是否结束
|
||||||
|
*/
|
||||||
|
export function checkSingleFinish(history: any) {
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO::
|
||||||
|
* 计算单人模式的得分
|
||||||
|
* @return {number}
|
||||||
|
*/
|
||||||
|
export function calcSingleScore() {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确定pvp模式题目类型
|
||||||
|
* @param {string} shopId
|
||||||
|
* @param {string} aid 活动配置
|
||||||
|
* @return {Promise<void>}
|
||||||
|
*/
|
||||||
|
export async function fetchPvpPuzzleType({shopId, aid} : {shopId: string, aid?: string}) {
|
||||||
|
|
||||||
|
//{$or:[{tag: {$in: ['a', 'SS']}}, {sub_tag: {$in: ['a', 'SS']}}]}
|
||||||
|
let typeArr: string[] = []
|
||||||
|
if (aid) {
|
||||||
|
let actData = await ShopActivity.findById(aid)
|
||||||
|
if (actData?.qtypes?.length > 0) {
|
||||||
|
typeArr = actData.qtypes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (typeArr.length === 0 ) {
|
||||||
|
let shop = await Shop.findById(shopId)
|
||||||
|
if (shop?.qtypes?.length > 0) {
|
||||||
|
typeArr = shop.qtypes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// let params = {$or: [{tag: {$in: typeArr}}, {sub_tag: {$in: typeArr}}]}
|
||||||
|
return typeArr
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取单人模式题目类型
|
||||||
|
* @param {string} shopId
|
||||||
|
* @param {mission_vo} levelCfg
|
||||||
|
* @return {Promise<void>}
|
||||||
|
*/
|
||||||
|
export async function fetchSinglePuzzleType({shopId, levelCfg} : {shopId: string, levelCfg?: mission_vo}) {
|
||||||
|
let typeArr: string[] = []
|
||||||
|
let shop = await Shop.findById(shopId)
|
||||||
|
if (shop?.qtypes?.length > 0) {
|
||||||
|
typeArr = shop.qtypes
|
||||||
|
}
|
||||||
|
if (typeArr.length === 0 && levelCfg?.keyID) {
|
||||||
|
typeArr = levelCfg.keyID.split(':')
|
||||||
|
}
|
||||||
|
return typeArr
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取关卡配置信息
|
||||||
|
* @param {number} level
|
||||||
|
*/
|
||||||
|
export function fetchLevelCfg(level: number) {
|
||||||
|
const cfgs: mission_vo[] = Array.from(global.$cfg.get(BaseConst.MISSION).values())
|
||||||
|
return cfgs.find(o => o.number == level) || cfgs[cfgs.length - 1]
|
||||||
|
}
|
||||||
|
@ -48,3 +48,13 @@ export function isTrue(obj) {
|
|||||||
return obj === 'true' || obj === 'TRUE' || obj === 'True' || obj === 'on' || obj ==='ON' || obj === true || obj === 1
|
return obj === 'true' || obj === 'TRUE' || obj === 'True' || obj === 'on' || obj ==='ON' || obj === true || obj === 1
|
||||||
|| obj === '1' || obj === 'YES' || obj === 'yes';
|
|| obj === '1' || obj === 'YES' || obj === 'yes';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 验证ObjectId格式是否正确
|
||||||
|
* @param {string} id
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
export function isObjectId(id: string): boolean {
|
||||||
|
//mongoose.Types.ObjectId.isValid(id)
|
||||||
|
return /^[a-fA-F0-9]{24}$/.test(id)
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user