有没有一种简单的方法可以在PHP中操作按位枚举?

时间:2019-01-22 21:16:18

标签: php bit-manipulation

我正在为游戏(osu!)创建自定义用户个人资料,并且试图在“热门游戏”中使用“ mods”。 该API提供了一个十进制数字,其中包含玩家在游戏中使用的每个mod。

例如:DoubleTime + Hidden mods为72,因为DoubleTime为64,而Hidden 8为隐藏

$hidden = 8;
$doubletime = 64;
$hiddendoubletime = ($hidden|$doubletime);
我想从72开始知道它的8和64。 甚至从88开始,分别是8、16和64。

我正在考虑以二进制(01011000)为例的tansform 88,然后检测所有“ 1”位置,因为每个“ 1”都给出了一个mod。

此处:01011000- 位置4的第一个“ 1”是“隐藏” mod,位置5的第二个“ 1”是Hardrock mod,最后,位置7的“ 1”是DoubleTime mod。

则枚举如下:

enum Mods
{
    None           = 0,
    NoFail         = 1,
    Easy           = 2,
    TouchDevice    = 4,
    Hidden         = 8,
    HardRock       = 16,
    SuddenDeath    = 32,
    DoubleTime     = 64,
    Relax          = 128,
    HalfTime       = 256,
    Nightcore      = 512, // Only set along with DoubleTime. i.e: NC only gives 576
    Flashlight     = 1024,
    Autoplay       = 2048,
    SpunOut        = 4096,
    Relax2         = 8192,  // Autopilot
    Perfect        = 16384, // Only set along with SuddenDeath. i.e: PF only gives 16416  
    Key4           = 32768,
    Key5           = 65536,
    Key6           = 131072,
    Key7           = 262144,
    Key8           = 524288,
    FadeIn         = 1048576,
    Random         = 2097152,
    Cinema         = 4194304,
    Target         = 8388608,
    Key9           = 16777216,
    KeyCoop        = 33554432,
    Key1           = 67108864,
    Key3           = 134217728,
    Key2           = 268435456,
    ScoreV2        = 536870912,
    LastMod        = 1073741824,
}

如您所见,列表很大,所以我不能在if()条件下尝试每个mod组合。

2 个答案:

答案 0 :(得分:1)

我会做这样的事情。...

<?php

$user_options = 88;

$no_options = array ( 'None' => 0 );

$game_options = array (
'NoFail' => 1, 
'Easy' => 2, 
'TouchDevice'=> 4, 
'Hidden' => 8, 
'HardRock' => 16, 
'SuddenDeath' => 32, 
'DoubleTime' => 64, 
'Relax' => 128, 
'HalfTime' => 256, 
'Nightcore' => 512, 
'Flashlight' => 1024, 
'Autoplay' => 2048, 
'SpunOut' => 4096, 
'Relax2' => 8192, 
'Perfect' => 16384,  
'Key4' => 32768, 
'Key5' => 65536, 
'Key6' => 131072, 
'Key7' => 262144, 
'Key8' => 524288, 
'FadeIn' => 1048576, 
'Random' => 2097152, 
'Cinema' => 4194304, 
'Target' => 8388608, 
'Key9' => 16777216, 
'KeyCoop' => 33554432, 
'Key1' => 67108864, 
'Key3' => 134217728, 
'Key2' => 268435456, 
'ScoreV2' => 536870912, 
'LastMod' => 1073741824
);

$filtered = array_filter ( $game_options, function ( $value ) use ( $user_options )
{
    return ( $value & $user_options ) == $value ? $value : NULL;
});

if ( empty ( $filtered ) )
{
    print_r ( $no_options );
}
else
{
    print_r ( $filtered );
}

?>

答案 1 :(得分:0)

我在想,最好只循环浏览用户设置的选项,这样,当只设置了一些较低编号的位时,您就不必循环浏览所有的game_options ... < / p>

<?php

$user_options = 344;

$game_options = array (
'NoFail' => 1, 
'Easy' => 2, 
'TouchDevice'=> 4, 
'Hidden' => 8, 
'HardRock' => 16, 
'SuddenDeath' => 32, 
'DoubleTime' => 64, 
'Relax' => 128, 
'HalfTime' => 256, 
'Nightcore' => 512, 
'Flashlight' => 1024, 
'Autoplay' => 2048, 
'SpunOut' => 4096, 
'Relax2' => 8192, 
'Perfect' => 16384,  
'Key4' => 32768, 
'Key5' => 65536, 
'Key6' => 131072, 
'Key7' => 262144, 
'Key8' => 524288, 
'FadeIn' => 1048576, 
'Random' => 2097152, 
'Cinema' => 4194304, 
'Target' => 8388608, 
'Key9' => 16777216, 
'KeyCoop' => 33554432, 
'Key1' => 67108864, 
'Key3' => 134217728, 
'Key2' => 268435456, 
'ScoreV2' => 536870912, 
'LastMod' => 1073741824
);

function get_options ( $game_options, $user_options )
{
    /* if no options are set, return this */

    $nil = array ( 'None' => 0 );

    /* if option(s) are set, return the array of set option(s) */

    $set = array ( );

    /* only loop the $game_options up until the max set $user_options */

    $stop = $user_options;

    foreach ( $game_options AS $on => $ov )
    {
        if ( $ov > $stop )
        {
            break;
        }
        else if ( ( $ov & $user_options ) == $ov )
        {
            $set[$on] = $ov;

            $stop -= $ov;
        }
    }

    return empty ( $set ) ? $nil : $set;
}

print_r ( get_options ( $game_options, $user_options ) );


?>