掼蛋程序怎么研发

1. 使用对象封装游戏数据:可定义Player、Card、Record等类,更好地组织数据及业务逻辑。

2. 存储游戏数据:使用Redis或其他数据库存储玩家、牌组、出牌记录等数据,实现服务端数据持久化。

3. 完善各游戏规则:发牌、出牌判断、升级、进贡、炸弹、胜负、计分等规则都需要细致全面地实现。

4. 服务端维护玩家状态:判断玩家是否在线、出牌顺序、已出牌信息等,实时更新并与前端同步状态。 

5. 实现更丰富的消息类型:除了出牌、登录和聊天外,还需要上线、离线、获取排行、使用道具、完成任务等类型的消息交互。

6. 聊天功能完善:可加入私聊、表情、禁言等功能,同时需要判断和过滤敏感词汇,确保聊天体验。

7. 使用Daemons管理定时器:使用daemon管理多个定时器,执行不同的游戏逻辑,更高效稳定。

8. 日志与异常处理:需要进行完善的日志记录与异常处理,保证程序健壮性。

9. 加密机制:如对用户密码进行加密存储与验证,保证用户数据安全。

10. 部署与性能优化:使用Supervisord部署,根据QPS优化Worker进程数量,提高服务器性能。

服务端代码

用workman 写一个掼蛋规则,包含了 发牌、出牌判断、升级、进贡、炸弹、胜负、计分等规则
require_once __DIR__ . '/vendor/autoload.php';

use Workerman\Worker; 
use Workerman\Lib\Timer;

// worker进程,监听4000端口  
$worker = new Worker("websocket://0.0.0.0:4000");

// 全局变量  
$pai = get_pai();        // 牌组  
$player = [];            // 玩家列表
$chu_pai = [];           // 出牌记录
$dipai = [];             // 底牌
$level = 1;              // 当前级别 

// 定时器,每秒执行  
Timer::add(1, function() { 
    // 发牌
    fa_pai(); 
    
    // 检测是否升级
    sheng_ji();  
    
    // 检测是否需要进贡 
    jin_gong();
    
    // 检测是否有炸弹
    zha_dan();  
    
    // 检测是否有胜者
    sheng_fu();   
});

// 收到消息,判断消息类型执行对应逻辑  
$worker->onMessage = function($connection, $msg) {
    $data = json_decode($msg, true);
    switch ($data['type']) {
        case 'login':       // 登录  
            login($connection, $data);   
            break;
        case 'chu_pai':     // 出牌  
            chu_pai($data['pai']);  
            send_chu_pai(); // 发送最新出牌记录到前端  
            break;
        case 'chat':        // 聊天
            chat($msg);  
            break;
    }
};  

// 出牌判断  
function chu_pai($pai) {
    ...
}

// 其他规则实现  
function fa_pai() { ... }
function sheng_ji() { ... } 
function jin_gong() { ... }
function zha_dan() { ... }
function sheng_fu() { ... }

// 运行worker  
Worker::runAll();

以上是标准掼蛋棋牌中52张牌的映射数组,分为:1. 方块(1-13):数字2到10和J、Q、K、A
2. 红桃(21-34):数字2到10和J、Q、K、A
3. 梅花(41-54):数字2到10和J、Q、K、A
4. 黑桃(61-74):数字2到10和J、Q、K、A

$pai = [
    1  => 'A', 2  => '2', 3  => '3', 4  => '4', 5  => '5', 
    6  => '6', 7  => '7', 8  => '8', 9  => '9', 10 => 'X', 
    11 => 'J', 12 => 'Q', 13 => 'K', 14 => 'A', 
    // 红桃
    21 => 'A', 22 => '2', 23 => '3', 24 => '4', 25 => '5', 
    26 => '6', 27 => '7', 28 => '8', 29 => '9', 30 => 'X', 
    31 => 'J', 32 => 'Q', 33 => 'K', 34 => 'A',
    // 梅花 
    41 => 'A', 42 => '2', 43 => '3', 44 => '4', 45 => '5',
    46 => '6', 47 => '7', 48 => '8', 49 => '9', 50 => 'X',
    51 => 'J', 52 => 'Q', 53 => 'K', 54 => 'A', 
    // 黑桃
    61 => 'A', 62 => '2', 63 => '3', 64 => '4', 65 => '5', 
    66 => '6', 67 => '7', 68 => '8', 69 => '9', 70 => 'X',
    71 => 'J', 72 => 'Q', 73 => 'K', 74 => 'A'  
];

发牌逻辑

发牌逻辑主要包含:

1. 洗牌:使用shuffle()函数随机乱序牌组$pai。

2. 发牌:从牌组$pai中发17张牌给每位玩家,存储在$player[$i]['pai']中。

3. 底牌:将剩余2张牌设为底牌$global['dipai']。

4. 发送手牌:将每位玩家的手牌发送到对应前端,展示给用户。

5. 出牌记录:每个玩家都有一个出牌记录$player[$i]['out']数组,初始为空。

发牌是棋牌游戏的开始,需要公平与完全随机。牌组的数据结构设计也需要合理,方便进行各种算法判断与操作

function fa_pai() {
    global $pai, $player;
    
    // 洗牌
    shuffle($pai);
    
    // 发17张牌给每个玩家
    for ($i=0; $i<4; $i++) {
        $player[$i]['pai'] = array_slice($pai, $i * 17, 17);
        $player[$i]['out'] = [];    // 出牌记录 
    }  
    
    // 剩余两张作为底牌
    $global['dipai'] = array_slice($pai, 68, 2); 
    
    // 发送玩家手牌到前端
    foreach ($player as $p) {
        $p['connection']->send(json_encode($p['pai']));
    }
}

出牌的逻辑

出牌逻辑主要包含:

1. 获取请求出牌的玩家$p。

2. 调用can_chu_pai()函数判断请求出的牌$pai['pai']是否合法。如果不合法,发送出牌失败提示到玩家前端。 

3. 如果合法,从玩家手中移除要出的牌。

4. 添加至玩家的出牌记录和公共出牌记录$chu_pai。

5. 发送最新出牌记录$chu_pai到所有前端。

6. can_chu_pai()函数判断首出牌可以任意出,否则需要出最大牌+1或炸弹。

function chu_pai($pai) {
    global $player, $chu_pai;
    
    // 获取出牌玩家
    $p = $player[$pai['p']];
    
    // 判断是否合法出牌
    if (!can_chu_pai($pai['pai'], $chu_pai)) {
        $p['connection']->send(json_encode([
            'type' => 'chu_pai_fail'
        ]));
        return;
    }
    
    // 出牌,从手中移除
    $p['pai'] = array_diff($p['pai'], [$pai['pai']]);
    
    // 添加至出牌记录
    $p['out'][] = $pai['pai'];
    $chu_pai[] = $pai['pai'];  
    
    // 发送最新出牌记录到前端 
    send_chu_pai(); 
}

// 判断是否可以出牌  
function can_chu_pai($pai, $chu_pai) {
    if (empty($chu_pai)) {
        return true;   // 首出牌,任意一张都可以出
    } else {
        $max_pai = max($chu_pai);
        
        // 最大牌+1或炸弹
        return ($pai > $max_pai) || ($pai == $max_pai && count($chu_pai) >= 3);  
    }

升级逻辑主要包含:

1. 判断是否需要升级:如果出牌记录$chu_pai数量达到当前级别$level的17倍,即可升级。

2. 升到下一级:级别$level加1,发送升级提示到前端。

3. 执行对应级别规则:不同级别有不同的规则,如第二级和第三级规则函数。

4. 规则实现:根据产品需求,实现不同级别的规则,如特殊牌型、特殊操作等。升级是棋牌游戏的重要规则之一,需要根据不同级别设计丰富的规则,不断增加游戏难度和趣味性,给玩家带来全新的游戏体验。

php
// 升级  
function sheng_ji() {
    global $chu_pai, $level;
    if (count($chu_pai) >= 17 * $level) {
        $level++;  // 升到下一级
         
        // 发送升级提示到前端
        broadcast(json_encode([
            'type' => 'sheng_ji',
            'level' => $level
        ]));  
        
        // 执行下一级牌型判断规则
        switch ($level) {
            case 2:
                sheng_ji_rule_2();
                break; 
            case 3:
                sheng_ji_rule_3();
                break;
            ...
        }
    } 
}

// 第二级升级规则  
function sheng_ji_rule_2() { 
    ...  
}

// 第三级升级规则
function sheng_ji_rule_3() {
    ...
}

进贡逻辑主要包含:

1. 设置最大进贡次数$max_jin_gong,默认为3次,每轮开始前重置每个玩家的进贡次数。

2. 判断每个玩家是否调用前端的JinGong方法进行进贡,如果进贡次数未超过最大次数则进行进贡。3. 进贡次数+1,并发送进贡提示到前端,提示上一张出的牌。

4. 从底牌中弹出一张牌,添加至玩家的出牌记录中。

5. 重新发两张底牌,以备其他玩家进贡。进贡是掼蛋游戏的特色规则之一,需要根据不同级别和玩家状态设计周全的规则,增加游戏趣味性和策略性,是该游戏的重要特色。

function jin_gong() {
    global $player, $level;
    $max_jin_gong = 3;  // 最多进贡次数
    
    // 每轮开始前,重置每个玩家的进贡次数
    foreach ($player as &$p) {
        $p['jin_gong_num'] = 0;
    }
    
    // 判断是否有玩家进贡
    foreach ($player as $p) {
        if ($p['jin_gong_num'] < $max_jin_gong && $p['connection']-> JinGong) {   // 调用前端JinGong方法
            $p['jin_gong_num']++;   // 进贡次数+1
            
            // 发送进贡提示
            broadcast(json_encode([
                'type' => 'jin_gong',
                'pai' => $p['out'][count($p['out']) - 1]   // 上一张出的牌
            ]));
            
            // 添加底牌至出牌记录
            $p['out'][] = array_pop($global['dipai']);
            
            // 重新发两张底牌
            $global['dipai'] = [get_random_pai(), get_random_pai()];
        }
    }
}  

炸弹判断逻辑主要包含:

1. 获取当前出牌池$chu_pai中的最大牌$max_pai。

2. 遍历每个玩家,判断手中是否有2张或更多的最大牌。

3. 如果有,则发送炸弹提示到对应玩家前端。

4. 出两张最大牌作为炸弹,从手中移除,添加至出牌记录和出牌池。

5. 重新发两张随机牌给触发炸弹的玩家。 

6. 结束循环,每个回合只判断一次炸弹。炸弹是掼蛋游戏的重要规则,需要根据当前出牌情况与每个玩家的手牌判断是否有炸弹,并执行对应的操作与提示。这需要对各种可能的牌型和玩家手牌状态进行全面考虑,保证规则的准确性与高效性。

function zha_dan() {
    global $player, $chu_pai;
    
    // 获取当前可出的最大牌
    $max_pai = max($chu_pai);  
    
    foreach ($player as $p) {
        // 玩家手中是否有2张或更多最大牌
        if (count($p['pai']) >= 2 && in_array($max_pai, $p['pai'], true)) {  
            // 发送炸弹提示
            $p['connection']->send(json_encode([
                'type' => 'zha_dan'
            ]));  
            
            // 出炸弹,多个最大牌从手中移除  
            $zha_dan_pai = array_splice($p['pai'], 
                array_search($max_pai, $p['pai'], true), 2);
            $chu_pai = array_merge($chu_pai, $zha_dan_pai);
            
            // 添加至出牌记录
            $p['out'] = array_merge($p['out'], $zha_dan_pai);  
            
            // 重新发两张牌
            $p['pai'][] = get_random_pai();
            $p['pai'][] = get_random_pai();
            
            break;
        }
    }
}

这里是一个掼蛋游戏胜负判断逻辑的实现:


胜负判断逻辑主要包含:

1. 初始化胜利玩家$winner为null。

2. 遍历每个玩家,先判断是否有出牌,如果未出牌则不判断。

3. 判断该玩家出的牌是否为最大炸弹或最大对子,如果是则标记为最大$is_max。

4. 继续遍历其他玩家,如果找到更大的牌则标记$is_max为false,并退出内层循环。

5. 如果$is_max为true,则找到胜利玩家,退出外层循环。

 6. 如果找到胜利玩家,则发送胜利提示到前端,显示胜利玩家序号。

7. 如果未找到,则本轮没有胜负结果,继续下一轮。

// 胜负判断  
function sheng_fu() {
    global $player;
    
    $winner = null;   // 胜利玩家
    
    // 判断牌型和数量
    foreach ($player as $p) {
        if (count($p['out']) == 0) {
            continue;   // 未出牌者不判断
        }
        
        // 是否为炸弹或对子最大
        $is_max = true;  
        foreach ($player as $other) {
            if ($other != $p && count($other['out']) > 0 
                && max($other['out']) > max($p['out'])) {
                $is_max = false;
                break;  
            }  
        } 
        
        if ($is_max) {
            $winner = $p;   // 找到胜利玩家
            break;
        }
    }
    
    if ($winner) {
        // 发送胜利提示
        broadcast(json_encode([
            'type' => 'sheng_li',
            'winner' => $winner['idx']   // 玩家序号
        ]));  
    }

在掼蛋游戏的代码规则上,我还有以下几点补充:

1. 针对不同的级别设计丰富的规则,如三带二、飞机等复杂的牌型,增加游戏难度和趣味性。这需要对各种牌型进行深入研究与判断。

2. 对庄家和闲家设定不同的规则,如庄家必须出首张牌等,增加游戏策略性。

3. 设计吃牌规则,如吃三张相连的牌。这需要判断手中是否有满足条件的组合,以及与当前出牌池的关系。

4. 实现跟牌与不跟牌,如连续三次最大出牌后不必跟上一次的最大牌。这需要对出牌历史进行判断与限制。

5. 添加选项设置,如扣底牌规则、最大进贡次数等。这需要添加对应的参数并在逻辑中进行判断。 

6. 实现超级玩家和钻石玩家等特权玩家的特殊规则。这需要在玩家初始化阶段进行判断与分类。

7. 进行高级策略判断,如统计每个玩家的出牌频率与喜好,预测对手可能的出牌策略。这需要记录各种出牌数据并进行算法计算。 

8. 在游戏过程中增加随机事件,如中途出现王炸等。这需要在发牌时留有余地,以便在后续过程中出现。

9. 增加聊天窗口,用于玩家交流与信任增加。需要实现双向实时通信与过滤不良信息。

10. 实现背景音乐、游戏特效等,增强游戏氛围与乐趣。需要进行网页音视频的开发与应用。

你可能感兴趣的:(php)