You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Nodejs和MongoDB的Tambola(Bingo)游戏中奖匹配逻辑实现咨询

Tambola宾果游戏中奖判定实现方案

因为你的数据量最多只有500条,优先推荐逻辑更简单、更适合新手调试的Node业务层处理方案,完全可以满足性能需求。


前置准备

先在服务端维护一个已开出号码的Set集合,用于快速判断号码是否被开出,每次生成新的不重复随机数后存入该集合:

// 存储所有已开出的号码,查询时间复杂度O(1)
const drawnNumbers = new Set()

方案1:Node业务层判定(新手推荐)

直接从MongoDB拉取全量票数据,逐个判断奖项条件即可:

const { MongoClient } = require('mongodb')
const mongoUri = '替换为你的MongoDB连接地址'
const client = new MongoClient(mongoUri)

async function getCurrentWinners() {
  try {
    await client.connect()
    const ticketCol = client.db('ticketdb').collection('tickets')
    // 拉取所有票数据,最多500条无性能压力
    const allTickets = await ticketCol.find({}).toArray()
    const winnerResult = {
      顶线奖: [],
      中线奖: [],
      底线奖: [],
      FullHouse: []
    }

    for (const ticket of allTickets) {
      const tktMatrix = ticket.tkt
      // 判定顶线奖:第一行所有非空值都已开出
      const topLineWin = tktMatrix[0].every(num => num === '' || drawnNumbers.has(num))
      if (topLineWin) winnerResult.顶线奖.push({
        id: ticket._id,
        name: ticket.name,
        phone: ticket.phone_no
      })
      // 判定中线奖:第二行所有非空值都已开出
      const midLineWin = tktMatrix[1].every(num => num === '' || drawnNumbers.has(num))
      if (midLineWin) winnerResult.中线奖.push({
        id: ticket._id,
        name: ticket.name,
        phone: ticket.phone_no
      })
      // 判定底线奖:第三行所有非空值都已开出
      const bottomLineWin = tktMatrix[2].every(num => num === '' || drawnNumbers.has(num))
      if (bottomLineWin) winnerResult.底线奖.push({
        id: ticket._id,
        name: ticket.name,
        phone: ticket.phone_no
      })
      // 判定FullHouse:所有15个号码都已开出
      const allTicketNums = tktMatrix.flat().filter(num => num !== '')
      const fullHouseWin = allTicketNums.every(num => drawnNumbers.has(num))
      if (fullHouseWin) winnerResult.FullHouse.push({
        id: ticket._id,
        name: ticket.name,
        phone: ticket.phone_no
      })
    }
    return winnerResult
  } finally {
    await client.close()
  }
}

开号主逻辑

// 每5秒开号+判定中奖
setInterval(async () => {
  // 生成1-99不重复随机数
  let newNum
  do {
    newNum = Math.floor(Math.random() * 99) + 1
  } while(drawnNumbers.has(newNum) && drawnNumbers.size < 99)
  // 所有号码开完终止流程
  if (drawnNumbers.size >= 99) {
    console.log('本轮游戏所有号码已开完')
    process.exit(0)
  }
  drawnNumbers.add(newNum)
  console.log('本次开出号码:', newNum)
  // 获取当前中奖名单
  const winners = await getCurrentWinners()
  console.log('当前中奖名单:', winners)
}, 5000)

方案优化:减少查询数据量

如果需要进一步降低性能消耗,每次开号后只查询包含该新号码的票,只处理这些票即可:

// 替换之前的全量查询语句
const relatedTickets = await ticketCol.find({
  $or: [
    {'tkt.0': newNum},
    {'tkt.1': newNum},
    {'tkt.2': newNum}
  ]
}).toArray()

方案2:MongoDB聚合判定(进阶可选)

如果需要在数据库层直接完成判定,可以使用以下聚合语句,调用时把已开出的Set转成数组传入即可:

async function getWinnersByAgg(drawnNumArr) {
  const ticketCol = client.db('ticketdb').collection('tickets')
  return await ticketCol.aggregate([
    {
      $addFields: {
        topLineWin: {
          $allElementsTrue: {
            $map: {
              input: '$tkt.0',
              in: {$or: [{$eq: ['$$this', '']}, {$in: ['$$this', drawnNumArr]}]}
            }
          }
        },
        midLineWin: {
          $allElementsTrue: {
            $map: {
              input: '$tkt.1',
              in: {$or: [{$eq: ['$$this', '']}, {$in: ['$$this', drawnNumArr]}]}
            }
          }
        },
        bottomLineWin: {
          $allElementsTrue: {
            $map: {
              input: '$tkt.2',
              in: {$or: [{$eq: ['$$this', '']}, {$in: ['$$this', drawnNumArr]}]}
            }
          }
        },
        fullHouseWin: {
          $setIsSubset: [
            {$filter: {input: {$concatArrays: ['$tkt.0', '$tkt.1', '$tkt.2']}, cond: {$ne: ['$$this', '']}}},
            drawnNumArr
          ]
        }
      }
    },
    {
      $match: {
        $or: [
          {topLineWin: true},
          {midLineWin: true},
          {bottomLineWin: true},
          {fullHouseWin: true}
        ]
      }
    }
  ]).toArray()
}

额外注意事项

如果需要避免同一个票重复领取同一个奖项,可以给tickets集合新增won_awards数组字段,中奖后将对应奖项名称写入该字段,下次判定时过滤掉已经领取过的奖项即可。

内容的提问来源于stack exchange,提问作者aemisom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 08:24:10