>  기사  >  백엔드 개발  >  PHP 복권 알고리즘 아이디어?

PHP 복권 알고리즘 아이디어?

WBOY
WBOY원래의
2016-08-04 09:20:241405검색

인터넷에 잘못된 알고리즘이 있습니다. 자세한 내용은 링크를 참조하세요

일반 원칙은 다음과 같습니다.
1, 난수를 생성합니다.
2, N번째 상품의 확률을 비교합니다.
3, 상품을 결정합니다.

이 알고리즘을 따르면 주관적으로는 한 번 추첨되지만 객관적으로 각 상품은 한 주기에 한 번 추첨됩니다. 실제로는 제 이해가 맞는지 모르겠습니다. .

다음은 제가 작성한 알고리즘입니다.

1. 먼저 난수(행운의 숫자)의 범위를 결정합니다.
2. 특정 상품은 한 번만 매칭될 수 있습니다.
3, 범위에 따라 행운의 숫자가 생성됩니다.
4, 범위에 따라 상품이 결정됩니다.
전문가에게 물어보세요. 더 좋은 알고리즘이나 아이디어가 있나요?

<code>$goods = [
            0 => [
                'id'    => 1,
                'name'  => '苹果电脑',
                'odds'  => '0.01' //概率
            ],
            1 => [
                'id'    => 2,
                'name'  => 'Iphone',
                'odds'  => '10.99'
            ],
            2 => [
                'id'    => 3,
                'name'  => '200元红包',
                'odds'  => '19'
            ],
            3 => [
                'id'    => 4,
                'name'  => '安慰奖',
                'odds'  => '30'
            ],
            4 => [
                'id'    => 5,
                'name'  => '什么都没抽到',
                'odds'  => '40'
            ],
        ];


        $baseOdds = 100; //抽奖概率基数,默认100%
        $maxBase = 1; //抽奖概率基数倍数,默认1,如果奖品概率有小数位,该倍数为10的小数位数平方,具体看下面

        foreach ($goods as $good) {
            $decimal = strpbrk($good['odds'], '.'); //获取小数点后面的内容
            if ($decimal !== false) {
                $decimalCount = strlen($decimal) - 1;//获取小数点后面的位数
                $newMaxBase = pow(10, $decimalCount); //例如概率如果是0.01,则全局的抽奖概率基数需要以10的平方倍数上涨
                if ($newMaxBase > $maxBase) {
                    $maxBase = $newMaxBase; //更新基数倍数
                }
            }
        }
        $baseOdds = $maxBase ? $baseOdds * $maxBase : $baseOdds; //更新概率基数

        $start = 1;
        $end = 0;
        $luckyCompare = $tickets = [];
        //为每个奖品生成一个幸运数区间
        foreach ($goods as $key => $good) {
            $newOdds = $good['odds'] * $maxBase;
            $end = $end + $newOdds;
            $luckyCompare[$good['id']] = [$start, $end];
            $tick = mt_rand($start, $end);
            $start = $start + $newOdds;
            $tickets[$good['id']] = $tick;
        }
        $luckyNumber = mt_rand(1, $baseOdds);
        var_dump($luckyNumber);
        var_dump($luckyCompare);
        foreach ($luckyCompare as $goodId => $compare) {
            if ($compare[0] <= $luckyNumber && $compare[1] >= $luckyNumber) {
                $luckyGood = $goodId; //最终的奖品
                break;
            }
        }

        var_dump($luckyGood);</code>
답글 내용:

인터넷에 잘못된 알고리즘이 있습니다. 자세한 내용은 링크를 참조하세요

일반 원칙은 다음과 같습니다.

1, 난수를 생성합니다.

2, N번째 상품의 확률을 비교합니다.
3, 상품을 결정합니다.
이 알고리즘을 따르면 주관적으로는 한 번 추첨되지만 객관적으로 각 상품은 한 주기에 한 번 추첨됩니다. 실제로는 제 이해가 맞는지 모르겠습니다. .

다음은 제가 작성한 알고리즘입니다.

1. 먼저 난수(행운의 숫자)의 범위를 결정합니다.

2. 특정 상품은 한 번만 매칭될 수 있습니다.

3, 범위에 따라 행운의 숫자가 생성됩니다.
4, 범위에 따라 상품이 결정됩니다.
전문가에게 물어보세요. 더 좋은 알고리즘이나 아이디어가 있나요?

내가 할 수 있는 말은 헤헤. 복권 알고리즘의 의사 결정권은 프로그래머에게 있지 않습니다. 이것이 바로 요점입니다.

보통 복권 활동은 마케팅 부서에서 시작, 기획, 평가, 운영을 담당하며 이를 구현하는 것이 프로그래머의 역할입니다. 마케팅 실행 계획에는 경품 설정, 이벤트 기간, 프로모션 전략, 콜드/핫 타임, 경품 배포 배치 등이 포함되어야 합니다. 간단히 말하면 이는 마케팅 부서가 지시하는 장면이고 개발자는 현장 지휘자입니다. 프로그램이 편성을 담당하며, 로또 당첨자는 배우이다.
<code>$goods = [
            0 => [
                'id'    => 1,
                'name'  => '苹果电脑',
                'odds'  => '0.01' //概率
            ],
            1 => [
                'id'    => 2,
                'name'  => 'Iphone',
                'odds'  => '10.99'
            ],
            2 => [
                'id'    => 3,
                'name'  => '200元红包',
                'odds'  => '19'
            ],
            3 => [
                'id'    => 4,
                'name'  => '安慰奖',
                'odds'  => '30'
            ],
            4 => [
                'id'    => 5,
                'name'  => '什么都没抽到',
                'odds'  => '40'
            ],
        ];


        $baseOdds = 100; //抽奖概率基数,默认100%
        $maxBase = 1; //抽奖概率基数倍数,默认1,如果奖品概率有小数位,该倍数为10的小数位数平方,具体看下面

        foreach ($goods as $good) {
            $decimal = strpbrk($good['odds'], '.'); //获取小数点后面的内容
            if ($decimal !== false) {
                $decimalCount = strlen($decimal) - 1;//获取小数点后面的位数
                $newMaxBase = pow(10, $decimalCount); //例如概率如果是0.01,则全局的抽奖概率基数需要以10的平方倍数上涨
                if ($newMaxBase > $maxBase) {
                    $maxBase = $newMaxBase; //更新基数倍数
                }
            }
        }
        $baseOdds = $maxBase ? $baseOdds * $maxBase : $baseOdds; //更新概率基数

        $start = 1;
        $end = 0;
        $luckyCompare = $tickets = [];
        //为每个奖品生成一个幸运数区间
        foreach ($goods as $key => $good) {
            $newOdds = $good['odds'] * $maxBase;
            $end = $end + $newOdds;
            $luckyCompare[$good['id']] = [$start, $end];
            $tick = mt_rand($start, $end);
            $start = $start + $newOdds;
            $tickets[$good['id']] = $tick;
        }
        $luckyNumber = mt_rand(1, $baseOdds);
        var_dump($luckyNumber);
        var_dump($luckyCompare);
        foreach ($luckyCompare as $goodId => $compare) {
            if ($compare[0] <= $luckyNumber && $compare[1] >= $luckyNumber) {
                $luckyGood = $goodId; //最终的奖品
                break;
            }
        }

        var_dump($luckyGood);</code>
따라서, 귀하가 제공하는 상품이 상금 풀을 초과하지 않는 한, 복권 알고리즘은 쓸모가 없습니다.

복권의 공정성과 정의를 어떻게 반영할 수 있을까? 실제로 이 문제는 프로그램이 작성된 후 자동으로 실행되기 때문에 고려할 필요가 거의 없다. 이때는 모든 참여자에게 평등한 환경이고 불공정한 문제도 없다.
전형적인 의사 알고리즘은 다음과 같습니다.
비와 이슬 상: 5위안 소비 쿠폰, 승률 100%

퍼들 상: 10위안 소비 쿠폰, 승률 50%

Ben; 천둥상: 100위안 소비쿠폰, 승률 5%
천둥상: 아이패드 1개, 총 6개.
활동시간은 12시간이며, 복권 상한은 없습니다.
알고리즘: 복권 타임스탬프의 마이크로초 부분은 20의 배수 = 천둥이고 홀수 = 웅덩이입니다. 그렇지 않으면 비와 이슬입니다. 2시간마다 한 사이클이 진행되며, 다음 사이클 시작 시 첫 번째 복권 당첨자가 이전 사이클의 번개 상금을 받게 됩니다. 기간이 만료된 후 첫 번째 복권을 받으면 전체 이벤트가 완전히 종료됩니다.

불공평한 질문도 있나요? 그럼, 헤헤. 결국에는 필요에 따라 프로그램을 작성해야 합니다.

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.