记录:随机数抽奖
要求:每次生成3个 1 - 10 之间可重复(或不可重复)的随机数,10次为一轮,每轮要求数字5出现6次、数字4出现3次、…。
提炼需求:
1,可设置最小数、最大数、每次抽奖生成随机数的个数、是否允许重复
2,可设置每轮指定数字的出现次数
3,可设置每轮的抽奖次数
注意:设置项发生变化,则重置游戏
效果图示例:
Choujianglog 模型
<?php
namespace app\admin\model\choujiang;
use think\Model;
class Choujianglog extends Model
{
// 表名
protected $name = 'choujiang_log';
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'integer';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = false;
protected $deleteTime = false;
// 追加属性
protected $append = [
];
// 获取抽奖当前轮次
public function getLunci($choujiang_id, $yilunchoujiagcishu) {
$lunci = $this->where(['choujiang_id'=>$choujiang_id])->max('lunci');
if(!$lunci){
$lunci = 1;
}
return $lunci;
}
// 获取抽奖接下来的轮次
public function getnextLunci($choujiang_id, $yilunchoujiagcishu) {
$lunci = $this->where(['choujiang_id'=>$choujiang_id])->max('lunci');
if(!$lunci){
$lunci = 1;
}
$choujiangcishu = $this->where(['choujiang_id'=>$choujiang_id, 'lunci'=>$lunci])->group('sign')->count();
if($choujiangcishu >= $yilunchoujiagcishu){
$lunci += 1;
}
return $lunci;
}
// 生成sign
public function createSign() {
$str = '123567890123567890123567890';//34个字符
$str = str_shuffle($str); //随机地打乱字符串中的所有字符
$sign = date('YmdHis').substr($str,0,4); //截取字符串
if($this->where(['sign'=>$sign])->value('sign')){
$this->createSign();
}else{
return $sign;
}
}
}
Choujiang模型
<?php
namespace app\admin\model\choujiang;
use think\Model;
class Choujiang extends Model
{
// 表名
protected $name = 'choujiang';
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'integer';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = 'updatetime';
protected $deleteTime = false;
// 追加属性
protected $append = [
'state_text'
];
public function getStateList()
{
return ['1' => __('State 1'), '2' => __('State 2')];
}
public function getStateTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['state']) ? $data['state'] : '');
$list = $this->getStateList();
return isset($list[$value]) ? $list[$value] : '';
}
}
Choujiangset模型
<?php
namespace app\admin\model\choujiang;
use think\Model;
class Choujiangset extends Model
{
// 表名
protected $name = 'choujiang_set';
// 自动写入时间戳字段
protected $autoWriteTimestamp = false;
// 定义时间戳字段名
protected $createTime = false;
protected $updateTime = false;
protected $deleteTime = false;
// 追加属性
protected $append = [
'state_text'
];
public function getStateList()
{
return ['1' => __('State 1'), '2' => __('State 2')];
}
public function getStateTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['state']) ? $data['state'] : '');
$list = $this->getStateList();
return isset($list[$value]) ? $list[$value] : '';
}
}
代码:
<?php
namespace app\api\controller;
use app\common\controller\Api;
use think\Exception;
use think\Validate;
use app\admin\model\choujiang\Choujiang as ChoujiangModel;
use app\admin\model\choujiang\Choujianglog as ChoujianglogModel;
use app\admin\model\choujiang\Choujiangset as ChoujiangsetModel;
/**
* 随机数接口
*/
class Choujiang extends Api
{
protected $noNeedLogin = ['*'];
protected $noNeedRight = ['*'];
protected $yilunchoujiagcishu = 10; //一轮抽奖次数
protected $default_min_val = 1; //(默认)最小数
protected $default_max_val = 10; //(默认)最大数
protected $default_geshu = 3; //(默认)个数
protected $default_state = 1; //(默认)允许重复:1=是,2=否
public function _initialize()
{
parent::_initialize();
if(!((new ChoujiangsetModel())->where(['id'=>['>', 0]])->value('id'))){
(new ChoujiangsetModel())->save([
'min_val'=>$this->default_min_val,
'max_val'=>$this->default_max_val,
'geshu'=>$this->default_geshu,
'state'=>$this->default_state,
]);
}
if(!((new ChoujiangModel())->where(['id'=>['>', 0]])->value('id'))){
$info = (new ChoujiangsetModel())->where(['id'=>['>', 0]])->field('min_val,max_val,geshu,state')->find();
(new ChoujiangModel())->save([
'min_val'=>$info['min_val'],
'max_val'=>$info['max_val'],
'geshu'=>$info['geshu'],
'state'=>$info['state'],
]);
}
}
/**
* 生成随机数页面,获取设置
*
* @ApiMethod (GET)
* @ApiHeaders (name=token, type=string, required=false, description="请求的Token")
*/
public function getSet()
{
try {
$info = (new ChoujiangsetModel())->where(['id'=>['>', 0]])->field('min_val,max_val,geshu,state')->find();
$this->success("OK", [
'info' => $info,
]);
} catch (Exception $e) {
$this->error($e->getMessage());
}
}
/**
* 生成随机数页面,修改设置
*
* @ApiMethod (POST)
* @ApiHeaders (name=token, type=string, required=false, description="请求的Token")
// * @param string $min_val 最小数
// * @param string $max_val 最大数
* @param string $geshu 个数
// * @param string $state 允许重复:1=是,2=否
*/
public function editSet()
{
try {
$min_val = $this->request->post('min_val/d',1);
$max_val = $this->request->post('max_val/d',10);
$geshu = $this->request->post('geshu/d',3);
$state = $this->request->post('state',1);
if(!in_array($geshu, [1,2,3])){
$this->error('个数只能设置为1,2,3');
}
if($min_val >= $max_val){
$this->error('最小数应小于最大数');
}
if($min_val <= 0 || $max_val <= 0){
$this->error('最小数和最大数应>0');
}
if(!in_array($state, [1,2])){
$this->error('允许重复只能设置为1,2');
}
$info = (new ChoujiangsetModel())->where(['id'=>['>', 0]])->field('min_val,max_val,geshu,state')->find();
$data = [
'min_val' => $min_val,
'max_val' => $max_val,
'geshu' => $geshu,
'state' => $state,
];
$info->save($data);
$choujianginfo = (new ChoujiangModel())->where(['id'=>['>', 0]])->field('min_val,max_val,geshu,state')->order('id desc')->find();
// 若配置修改则重置游戏
if($choujianginfo['min_val'] != $data['min_val'] || $choujianginfo['max_val'] != $data['max_val'] || $choujianginfo['geshu'] != $data['geshu'] || $choujianginfo['state'] != $data['state']){
(new ChoujiangModel())->save([
'min_val'=>$data['min_val'],
'max_val'=>$data['max_val'],
'geshu'=>$data['geshu'],
'state'=>$data['state'],
]);
}
$this->success("保存成功", [
'info' => $data,
]);
} catch (Exception $e) {
$this->error($e->getMessage());
}
}
/**
* 生成随机数页面,生成随机数
*
* @ApiMethod (POST)
* @ApiHeaders (name=token, type=string, required=false, description="请求的Token")
*/
public function choujiang()
{
try {
$newchoujianginfo = (new ChoujiangModel())->where(['id'=>['>', 0]])->field('id,min_val,max_val,geshu,state,neidingcishu,content')->order('id desc')->find();
$nextlunci = (new ChoujianglogModel)->getnextLunci($newchoujianginfo['id'], $this->yilunchoujiagcishu); //获取抽奖接下来的轮次
$min = $newchoujianginfo['min_val'];
$max = $newchoujianginfo['max_val'];
$geshu = $newchoujianginfo['geshu'];
$state = $newchoujianginfo['state'];
$neidingcishu = $newchoujianginfo['neidingcishu'];
// 当前轮次抽奖次数
$choujiangcishu = (new ChoujianglogModel)->where(['choujiang_id'=>$newchoujianginfo['id'], 'lunci'=>$nextlunci])->group('sign')->count();
if($choujiangcishu == 0){ //开始新一轮
$numbers = []; // 生成的数字
$keyArr = []; //内定数字
// 优先将内定数字放入数组
if($neidingcishu){
foreach(json_decode($neidingcishu, true) as $key=>$value){
// 生成数字$key,并确保满足条件($value次)
for ($i = 0; $i < $value; $i++) {
$numbers[] = $key;
}
$keyArr[] = $key;
}
}
// 除去内定数字之外的数字集
$shuziArr = array_values(array_diff(range($min, $max), $keyArr));
// 填补,确保没有超出条件限制
shuffle($shuziArr); // 打乱数组顺序
$shuziArrwhile = $shuziArr;
while (count($numbers) < $geshu*$this->yilunchoujiagcishu) {
if(count($shuziArrwhile) <= 0){
$shuziArrwhile = $shuziArr;
}
$shuzi = array_shift($shuziArrwhile);
$numbers[] = $shuzi;
}
// 打乱数组顺序,确保随机性
shuffle($numbers);
// 允许重复:1=是,2=否
if($state == 1){
// 分割数组
$newNumbers = array_chunk($numbers, $geshu);
}else{
$newNumbers = [];
for ($i = 0; $i < count($numbers); $i += $geshu) {
$randomarr = array_values(array_unique(array_slice($numbers, $i, $geshu)));
if(count($randomarr) != $geshu){
$this->error('抱歉,参数配置错误');
}
$newNumbers[] = $randomarr;
}
}
$firstArr = array_shift($newNumbers);
}else{
$newNumbers = json_decode($newchoujianginfo['content'], true);
$firstArr = array_shift($newNumbers);
}
// 保存抽奖记录
$choujianglogModel = new ChoujianglogModel();
$sign = $choujianglogModel->createSign();
$logData = [];
foreach($firstArr as $k=>$v){
$logData[] = [
'choujiang_id'=>$newchoujianginfo['id'],
'lunci'=>$nextlunci,
'number'=>$v,
'sign'=>$sign,
];
}
$choujianglogModel->allowField(true)->saveAll($logData);
// 保存剩余待抽奖项
$newchoujianginfo->save(['content'=>json_encode($newNumbers)]);
$this->success("OK", [
'data' => $firstArr,
]);
} catch (Exception $e) {
$this->error($e->getMessage());
}
}
/**
* 内定数字页面,获取数据
*
* @ApiMethod (GET)
* @ApiHeaders (name=token, type=string, required=false, description="请求的Token")
*/
public function getChoujiangSet()
{
try {
$newchoujianginfo = $this->choujiangset();
$this->success("OK", [
'info' => $newchoujianginfo,
]);
} catch (Exception $e) {
$this->error($e->getMessage());
}
}
private function choujiangset() {
$newchoujianginfo = (new ChoujiangModel())->where(['id'=>['>', 0]])->field('id,min_val,max_val,geshu,state,neidingcishu')->order('id desc')->find();
$lunci = (new ChoujianglogModel)->getLunci($newchoujianginfo['id'], $this->yilunchoujiagcishu); //获取抽奖当前轮次
$neidingcishu_arr = [];
if($newchoujianginfo['neidingcishu']){
foreach(json_decode($newchoujianginfo['neidingcishu'], true) as $k=>$v){
$neidingcishu_arr[] = [
'shuzi'=>$k,
'cishu'=>$v,
'chouzhongcishu'=>(new ChoujianglogModel)->where(['choujiang_id'=>$newchoujianginfo['id'], 'lunci'=>$lunci, 'number'=>$k])->count(),
];
}
}
$newchoujianginfo['neidingcishu_arr'] = $neidingcishu_arr;
unset($newchoujianginfo['neidingcishu']);
$newchoujianginfo['choujiangcishu'] = (new ChoujianglogModel)->where(['choujiang_id'=>$newchoujianginfo['id'], 'lunci'=>$lunci])->group('sign')->count();
return $newchoujianginfo;
}
/**
* 内定数字页面,设置出现次数
*
* @ApiMethod (POST)
* @ApiHeaders (name=token, type=string, required=false, description="请求的Token")
* @param json $neidingcishu json字符串,例如{"1":"5","2":"3"}
*/
public function editChoujiangSet()
{
try {
$neidingcishu = htmlspecialchars_decode($this->request->post('neidingcishu/s', ''));
$neidingcishu = json_decode($neidingcishu, true);
// $neidingcishu = $this->request->post()['neidingcishu'];
$choujianginfo = (new ChoujiangModel())->where(['id'=>['>', 0]])->order('id desc')->find();
if($neidingcishu){
$arr = [];
$max_cishu = $this->yilunchoujiagcishu * $choujianginfo['geshu'];
$cishu = 0;
foreach($neidingcishu as $key=>$value){
if($key < $choujianginfo['min_val'] || $key > $choujianginfo['max_val']){
$this->error('数字应在最小数与最大数之间');
}
if($choujianginfo['state']==1 && $value > $max_cishu){
$this->error('单个数字出现总次数应<='.$max_cishu);
}
if($choujianginfo['state']==2 && $value > $this->yilunchoujiagcishu){
$this->error('单个数字出现总次数应<='.$this->yilunchoujiagcishu);
}
$cishu += $value;
if($cishu > $max_cishu){
$this->error('数字出现总次数应<='.$max_cishu);
}
$arr[$key] = $value;
}
if($choujianginfo['min_val']+1 == $choujianginfo['max_val'] && count($arr)==2 && $cishu != $max_cishu){
$this->error('数字出现总次数应=='.$max_cishu);
}
$neidingcishu_str = json_encode($arr);
}else{
$neidingcishu_str = '';
}
if($choujianginfo['neidingcishu'] != $neidingcishu_str){
$info = (new ChoujiangsetModel())->where(['id'=>['>', 0]])->field('min_val,max_val,geshu,state')->find();
(new ChoujiangModel())->save([
'min_val'=>$info['min_val'],
'max_val'=>$info['max_val'],
'geshu'=>$info['geshu'],
'state'=>$info['state'],
'neidingcishu'=>$neidingcishu_str,
]);
}
$newchoujianginfo = $this->choujiangset();
$this->success("保存成功", [
'info' => $newchoujianginfo,
]);
} catch (Exception $e) {
$this->error($e->getMessage());
}
}
}
sql
CREATE TABLE `fa_choujiang_set` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`min_val` int(10) DEFAULT '0' COMMENT '最小数',
`max_val` int(10) DEFAULT '0' COMMENT '最大数',
`geshu` int(10) DEFAULT '0' COMMENT '个数',
`state` enum('1','2') DEFAULT '1' COMMENT '允许重复:1=是,2=否',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COMMENT='抽奖设置表';
CREATE TABLE `fa_choujiang` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`min_val` int(10) DEFAULT '0' COMMENT '最小数',
`max_val` int(10) DEFAULT '0' COMMENT '最大数',
`geshu` int(10) DEFAULT '0' COMMENT '个数',
`state` enum('1','2') DEFAULT '1' COMMENT '允许重复:1=是,2=否',
`neidingcishu` text COMMENT '内定次数',
`content` text COMMENT '内容',
`createtime` bigint(16) DEFAULT NULL COMMENT '创建时间',
`updatetime` bigint(16) DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8mb4 COMMENT='抽奖表';
CREATE TABLE `fa_choujiang_log` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`choujiang_id` int(10) DEFAULT '0' COMMENT '抽奖ID',
`number` int(10) DEFAULT '0' COMMENT '数字',
`sign` varchar(100) DEFAULT NULL COMMENT '标识',
`lunci` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '轮次(第几轮)',
`createtime` bigint(16) DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`),
KEY `choujiang_id` (`choujiang_id`)
) ENGINE=InnoDB AUTO_INCREMENT=65 DEFAULT CHARSET=utf8mb4 COMMENT='抽奖记录表';