活动投骰子

代码git地址:https://gitee.com/wyqgg/iblog.git

描述

首先获得骰子

​ 每天(首次登录、签到)之后都可以获得一个骰子

掷骰子逻辑

获取前进步数(每次使用全部的骰子,每个骰子可以前进1-6步),每个步数都有奖励(前进一步可以获得10积分,每到达特定步数可以获得指定金币奖励)

实现:

首先设置redis缓存

key

类型过期时间描述
date(‘Y-m-d’, time()) . “__” . $uid ."_Login_dice"string86400登陆锁,来指定首次登陆
date(‘Y-m-d’, time()) . “__” . $uid ."_signIn_dice"string86400签到锁,来指定首次登陆
$uid . ‘_diceNum’string30*86400用户骰子的总数
$uid . ‘_diceStep’string30*86400用户掷骰子走的步数
$uid._‘rollDiceLock’string3redis防止并发点击锁
stepRankzset30*86400用户步数排行榜

数据表

骰子活动记录表

CREATE TABLE `activity_score` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `uid` int(11) DEFAULT NULL COMMENT '用户id',
  `step` int(5) DEFAULT NULL COMMENT '前进的步数',
  `after_step` int(5) DEFAULT NULL COMMENT '使用之后的步数',
  `score` int(11) DEFAULT NULL COMMENT '获取的积分',
  `coin` int(11) DEFAULT '0' COMMENT '额外金币奖励,未获得则为零',
  `use_num` int(5) DEFAULT NULL COMMENT '使用的骰子数量',
  `init_time` int(11) DEFAULT NULL,
  `last_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `uid_index` (`uid`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=gbk COMMENT='骰子活动记录表';

逻辑

​ 每次登陆、和签到获得骰子放在指定的键中,每天首次登陆和签到自增骰子($uid . ‘_diceNum’)的数量。

​ 每次登陆签到设置锁,用来判断用户是否可以获得骰子

​ 掷骰子的时候获取用户的骰子总数减去骰子记录表中的该用户指定时间小号的骰子数量就可以获得剩余的骰子数量,然后计算出用户可以前进的步数,增加到用户步数中($uid . ‘_diceStep’),然后将用户和步数放到用户步数排行(stepRank)中,将本次骰子的记录放到骰子记录表中,将获得的奖励存到用户账户中,即可。

使用ci框架在iblog项目中实现具体代码为:

控制器代码:

(将逻辑处理全部放到service层代码,这里只做参数获取)

class Activity extends Base_Controller
{
    public function __construct()
    {
        parent::__construct();
        $this->load->service('Activity_service');
        $this->load->model('Activity_model');
    }

    //掷骰子操作
    public function rollDice()
    {
        $data = $this->input->post();
        $uid = empty($data['uid']) ? 0 : $data['uid'];
        $this->Activity_service->rollDice($uid);
    }

    //获取用户步数排行榜
    public function stepRank()
    {
        $data = $this->input->post();
        $uid = empty($data['uid']) ? 0 : $data['uid'];
        $this->Activity_service->stepRank($uid);
    }

    //掷骰子活动首页
    public function diceIndex()
    {
        $data = $this->input->post();
        $uid = empty($data['uid']) ? 0 : $data['uid'];
        $this->Activity_service->diceIndex($uid);
    }
}

登录和签到中添加增加骰子方法

/*
 * 用户签到 User控制器
 */
public function signIn()
{
    $data = $this->input->post();
    $rules = [
        [
            'field' => 'user_id',
            'label' => '用户id',
            'rules' => 'required',
            'errors' => [
                'require' => '用户id不能为空',
            ]
        ],
    ];
    $res = $this->validate($data, $rules);
    if (!$res) {
        fail(400, '参数错误!');
    }
    $data['init_date'] = date('Y-m-d', time());
    $isSignIn = $this->users_model->isSignIn($data);
    if ($isSignIn) {
        fail(400, '已签到,不可重复签到!');
    }
    //获取当前用户昨天签到的keep_time+1,若没有则为1;
    $time = date('Y-m-d', strtotime('-1 days'));
    $data['keep_time'] = $this->users_model->getSignInKeep($data['user_id'], $time);
    //签到操作
    $data1 = $this->users_model->signIn($data);
    if (!$data1) {
        fail(400, '签到失败!');
    }
    //签到成功增加一个骰子
    $this->Activity_service->addDice($data['user_id'],'signIn');
    success($data, '签到成功!');
}

//登录 Login控制器
public function login()
{
    //获取数据
    $post = $this->input->post();
    //查询是否有该用户名
    $data = $this->users_model->findByUsername($post['username']);
    if ($data) {
        if (encrypt($post['password']) == $data['password']) {
            //记录登录日志
            $sqlData = [
                'ip' => $_SERVER['SERVER_ADDR'],
                'init_time' => time(),
                'user_name' => $post['username'],
                'uid' => $data['id']
            ];
            $data['init_time'] = time();
            //登录日志
            $this->logger_model->userLoginLog($sqlData);
            //用户首次登录成功送一个骰子
            $this->Activity_service->addDice($data['id'],'Login');
            $data['image'] = "http://cakephp.com/" . $data['image'];
            success($data, '登陆成功!');
        } else {
            fail(501, '密码错误!');
        }
    } else {
        fail(500, '没有该用户!');
    }
}
service代码:
<?php

class Activity_service extends MY_Service
{
    //redis连接
    private $conn;

    public function __construct()
    {
        parent::__construct();
        $this->load->model('Activity_model');
        $this->conn = getRedis();
        //活动的数据放在三库
        $this->conn->selectDb(3);
    }

    //掷骰子操作
    public function rollDice($uid)
    {
        if ($uid == 0) {
            fail(400, '参数错误');
        }
        $lock = $uid . '_rollDiceLock'; //redis防止并发点击锁
        if (!$this->conn->setNxExpire($lock, 1, 3)) {
            fail(400, '点击太快了,稍后再试');
        }
        $num = $this->getDiceNum($uid);
        if (!$num) {
            $this->conn->del($lock); //移除锁
            fail(400, '骰子数量不足');
        }
        //执行掷骰子操作(有多少骰子,全部掷出)
        $step = 0;
        for ($i = 1; $i <= $num; $i++) {
            $step += rand(1, 6);
        }
        if ($step <= 0) {
            $this->conn->del($lock); //移除锁
            fail(400, '前进步数计算错误');
        }
        //更新用户已经走的步数
        $step_key = $uid . '_diceStep';
        $this->conn->incrBy($step_key, $step);
        //更新步数排行榜 (向有序set中指定id加指定的步长)
        $step_rank_key = 'stepRank';
        $after_step = $this->conn->zIncrBy($step_rank_key, $step, $uid);

        //获取到的积分奖励(每一步获取10积分)
        $score = $step * 10;
        //额外金币奖励
        $coin = $this->getAward($step, $after_step);
        //将获得的全部奖励记录到本次骰子活动的记录表中
        $this->Activity_model->addScore($uid, $step, $score, $coin, $after_step, $num);
        //将积分奖励增加到用户账户上
        $this->Activity_model->updateScore($uid, $score, $coin);

        $res = [
            'step' => $step,
            'score' => $score,
            'use_num' => $num,
            'coin' => $coin,
        ];
        $this->conn->del($lock);//移除锁
        success($res);
    }

    /*
     * 获得骰子(首次登录、每日签到)
     */
    public function addDice($uid, $action)
    {
        //将当天日期上锁
        $lock_key = date('Y-m-d', time()) . '_' . $uid . "_{$action}_" . '_dice';
        $status = $this->conn->setNx($lock_key, 1);
        $this->conn->expire($lock_key, 86400);
        //只有首次进来才加骰子
        if ($status) {
            $dice_key = $uid . '_diceNum';
            $this->conn->expire($dice_key, 86400 * 7);
            $this->conn->incr($dice_key);
        }
    }

    /*
     * 掷骰子的额外奖励
     */
    public function getAwardList()
    {
        return [
            [
                'step' => 10,
                'coin' => 100
            ],
            [
                'step' => 20,
                'coin' => 200,
            ],
            [
                'step' => 50,
                'coin' => 500,
            ],
            [
                'step' => 100,
                'coin' => 1000,
            ],
            [
                'step' => 200,
                'coin' => 2000,
            ],
            [
                'step' => 500,
                'coin' => 10000,
            ],
        ];
    }

    /*
     * 获取用户可以使用的骰子数量
     */
    public function getDiceNum($uid)
    {
        //获取用户的骰子数
        $key = $uid . '_diceNum';
        //从redis中获取用户全部的骰子数量
        $allNum = $this->conn->get($key);
        //获取用户已经消耗的骰子数量
        $useNum = $this->Activity_model->getUseNum($uid);
        //返回剩下的骰子数量,不够的话返回false
        return ($allNum - $useNum >= 0) ? $allNum - $useNum : false;
    }

    /*
     * 获取用户可以获得的额外金币奖励
     */
    public function getAward($step, $after_step)
    {
        //获取用户本次掷骰子获取的额外奖励
        $list = $this->getAwardList();
        $list = array_column($list, null, 'step');
        $award = 0;
        //获取用户可以获得的额外奖励
        foreach ($list as $k => $v) {
            if ($after_step >= $v['step'] && $after_step - $step < $v['step']) {
                $award += $v['coin'];
            }
        }
        return $award;
    }

    //活动首页
    public function diceIndex($uid)
    {
        if (!$uid) {
            fail(400, '参数错误!');
        }
        //全部榜单
        $list = $this->userStepRank();
        //用户距离榜单的数据
        $userInfo = $this->stepDistance($list, $uid);
        //用户剩下的骰子数量
        $num = $this->getDiceNum($uid);
        $userInfo['num'] = $num;
        //用户走过的全部步数
        $key = $uid . "_diceStep";
        $userStep = $this->conn->get($key);
        $award = $this->getAwardList();
        foreach ($award as $k => $v) {
            if ($userStep >= $v['step']) {
                unset($award[$k]);
            }
        }
        $data = [
            'userInfo' => $userInfo,
            'award' => $award,
        ];
        success($data);
    }

    //榜单页面
    public function stepRank($uid)
    {
        //获取全部榜单
        $list = $this->userStepRank();
        //取榜单前三
        $userRank3 = array_slice($list, 0, 3);
        //取前三名用户的详细信息
        $userInfo3 = $this->Activity_model->stepRank($userRank3);
        foreach ($userInfo3 as $k => $v) {
            foreach ($userRank3 as $kk => $vv) {
                if ($v['id'] == $vv['uid']) {
                    $userRank3[$kk]['nickname'] = $v['nickname'] ? $v['nickname'] : '';
                    $userRank3[$kk]['image'] = $v['image'] ? $v['image'] : '';
                }
                $userRank3[$kk]['award'] = $this->rankAward()[$vv['rank']];
            }
        }
        //获取用户的步数信息
        $userRank = $this->stepDistance($list, $uid);
        $userInfo = $this->Activity_model->commonQuery('nickname,image', ['id' => $uid], 'users');
        $userRank['nickname'] = $userInfo[0]['nickname'];
        $userRank['image'] = $userInfo[0]['image'];
        $data = [
            'rankList' => $userRank3,
            'userInfo' => $userRank
        ];
        success($data);
    }

    //获取完成的用户排行榜单
    public function userStepRank()
    {
        //获取榜单的前3名数据
        $step_rank_key = 'stepRank';
        //获取全部的榜单
        $rank = $this->conn->zRevRange($step_rank_key, 0, -1, true);
        $rank1 = 1;
        foreach ($rank as $k => $v) {
            $res[] = [
                'uid' => $k,
                'step' => $v,
                'rank' => $rank1
            ];
            $rank1++;
        }
        return $res;
    }

    //获取用户在榜单的位置以及距离上一名需要的步数
    public function stepDistance($list, $uid)
    {
        $uidKeysArray = array_column($list, null, 'uid');
        //前三名
        $uidKeysArray3 = array_slice($uidKeysArray, 0, 3, true);
        //用户在榜单中
        if (array_key_exists($uid, $uidKeysArray3)) {
            foreach ($list as $k => $v) {
                if ($v['uid'] == $uid) {
                    if ($v['rank'] == 1) {
                        $distance = 0;
                    } else {
                        $distance = $list[$k - 1]['step'] - $v['step'];

                    }
                    $res = [
                        'uid' => $uid,
                        'rank' => $v['rank'],
                        'step' => $v['step'],
                        'distance' => $distance
                    ];
                }
            }
        } else {
            //用户不在榜单中,则距离榜单最后一名需要的步数
            $end = end($uidKeysArray3);
            $res = [
                'uid' => $uid,
                'rank' => $uidKeysArray[$uid]['rank'],
                'step' => $uidKeysArray[$uid]['step'],
                'distance' => $end['step'] - $uidKeysArray[$uid]['step']
            ];
        }
        return $res;
    }

    //榜单前三名活动结束之后可以获得的奖励列表
    public function rankAward()
    {
        return [
            1 => '100000金币',
            2 => '50000金币',
            3 => '10000金币',
        ];
    }
}

model层代码:

这里我定义了一个Base_model里面定义了几个比较基础的通用增删改查方法

<?php
/**
 * Created by PhpStorm.
 * User: wyq
 * Date: 2021/10/29
 * Time: 13:35
 */

class Activity_model extends Base_Model
{
    public function __construct()
    {
        parent::__construct();
    }

    public function addScore($uid, $step, $score, $coin, $after_step, $num)
    {
        $data = [
            'uid' => $uid,
            'step' => $step,
            'score' => $score,
            'coin' => $coin,
            'after_step' => $after_step,
            'use_num' => $num,
            'init_time' => time()
        ];
        return $this->commonInsert('activity_score', $data);
    }

    public function getUseNum($uid)
    {
        $res = $this->commonQuery('sum(use_num) num','uid='.$uid,'activity_score');
        return $res[0]['num'];
    }

    public function updateScore($uid, $score,$coin)
    {
        $before = $this->commonQuery('score,coin', ['id' => $uid], 'users');
        $score += $before[0]['score'];
        $coin += $before[0]['coin'];
        return $this->commonUpdate('users', ['score' => $score,'coin' => $coin], ['id' => $uid]);
    }

    public function stepRank($rank)
    {
        $uid = array_column($rank, 'uid');
        $res = $this->db->select('id,nickname,image')
            ->where_in('id', $uid)
            ->get('users');
        return $res->num_rows() ? $res->result_array() : false;
    }
}
Base_model代码
<?php

class Base_Model extends CI_Model
{
    public function __construct()
    {
        parent::__construct();
        $this->load->database();
    }

    /*
     * 通用的简单检索
     */
    public function commonQuery($fields, $where, $table)
    {
        $query = $this->db->select($fields)->where($where)->get($table);
        return $query->num_rows() ? $query->result_array() : [];
    }

    /*
     * 通用的简单删除
     */
    public function commonDelete($table, $where)
    {
        $this->db->delete($table, $where);
        return $this->db->affected_rows() ? true : false;
    }

    /*
     * 通用的新增
     */
    public function commonInsert($table, $value)
    {
        $this->db->insert($table, $value);
        return $this->db->affected_rows() ? true : false;
    }

    /*
     * 通用的修改
     */
    public function commonUpdate($table, $value, $where)
    {
        $this->db->update($table, $value, $where);
        return $this->db->affected_rows() ? true : false;
    }
}

这里我使用的接口编程(只能本地访问)

接口返回
掷骰子操作

请求地址:(ci.com/activity/rollDice)

请求类型: POST

请求参数: uid(用户id)

成功返回示例:

{
    "code": 200,
    "msg": "success",
    "data": {
        "step": 299,
        "score": 2990,
        "use_num": 92,
        "coin": 3500
    }
}

失败示例:

{
    "code": 400,
    "msg": "骰子数量不足",
    "data": []
}

返回参数

参数类型描述
stepint本次前进的步数
scoreint获得的积分
use_numint本次使用的骰子数量
coinint本次获得的额外金币奖励
获取榜单

请求地址:(ci.com/activity/stepRank)

请求类型: POST

请求参数: uid(用户id)

返回示例:

{
    "code": 200,
    "msg": "success",
    "data": {
        "rankList": [
            {
                "uid": 2,
                "step": 337,
                "rank": 1,
                "nickname": "王永清1",
                "image": "static/img/2021-11-01/16357612048552.png",
                "award": "100000金币"
            },
            {
                "uid": 3,
                "step": 11,
                "rank": 2,
                "award": "50000金币",
                "nickname": "石赵玉",
                "image": "static/img/2021-11-01/16357612074427.png"
            },
            {
                "uid": 4,
                "step": 6,
                "rank": 3,
                "award": "10000金币",
                "nickname": "住我心,免房租1",
                "image": "static/img/2021-11-01/16357612109097.png"
            }
        ],
        "userInfo": {
            "uid": "2",
            "rank": 1,
            "step": 337,
            "distance": 0,
            "nickname": "王永清1",
            "image": "static/img/2021-11-01/16357612048552.png"
        }
    }
}

返回参数列表

参数类型描述
rankListjson榜单信息 这里只取前三名
rankList.nicknamestring榜单用户昵称
rankList.stepint榜单用户前进的步数
rankList.rankint榜单用户排名
rankList.awardstring该排名可以获得的奖励
rankList.imagestring榜单用户头像
userInfojson当前登录用户信息
userInfo.distanceint距上一名的步数差,若为没上榜则距离上榜的步数差
活动首页

请求地址:(ci.com/activity/diceIndex)

请求类型: POST

请求参数: uid(用户id)

返回示例:

{
    "code": 200,
    "msg": "success",
    "data": {
        "userInfo": {
            "uid": "3",
            "rank": 2,
            "step": 11,
            "distance": 326,
            "num": 0
        },
        "award": {
            "1": {
                "step": 20,
                "coin": 200
            },
            "2": {
                "step": 50,
                "coin": 500
            },
            "3": {
                "step": 100,
                "coin": 1000
            },
            "4": {
                "step": 200,
                "coin": 2000
            },
            "5": {
                "step": 500,
                "coin": 10000
            }
        }
    }
}

返回参数列表

参数类型描述
awardjson用户未获得的额外奖励列表
award.stepstring额外奖励获得需要的步数
award.coinint额外奖励的金币数量
userInfoint当前登录用户信息
userInfo.stepstring用户的步数
userInfo.imagestring榜单用户头像
userInfo.rankjson用户排名
userInfo.distanceint距上一名的步数差,若为没上榜则距离上榜的步数差
userInfo.numint当前用户可以使用的骰子数

这里因为本系统中没有额外的道具,所以奖励只能有用户的积分,和金币。若其他系统额外的奖励可以是其他的道具,基本功能可以实现,但是功能还不是很完善。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值