7

I am about to create a script that choose a winner for my lottery. The amount of tickets is chosen by following: amount of money * 100 So $1.26 = 126 tickets.

I made this, which give me the winning ticket number, but then I cannot get the winning user:

$totaltickets = 0;

foreach($players as $player){

    $totaltickets += $player->depositedValue*100;
}

$winningTicket = rand(1,$totaltickets);

I have rows like this:

Player1 - 1.25$
Player2 - 5.99$
etc..

If it is possible then I would like to keep it like this, and not have 1000s of rows in the database with each ticket.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Søren Efa
  • 145
  • 3
  • 10
  • So how do you assign ticket numbers? Is it based on the order of the players, such that player 1 on this case has tickets #1 - #125? – kittykittybangbang Jul 12 '15 at 19:04
  • It is random right now.. – Søren Efa Jul 12 '15 at 19:05
  • Hey running this above script gave a warning on the for loop. Warning: Invalid argument supplied for foreach() on Line 4. Unsure why you have this part $player->depositedValue*100? – pal4life Jul 12 '15 at 19:15
  • @pal4life It is from a MySQL query, so i can get the amount of money deposited.. – Søren Efa Jul 12 '15 at 19:17
  • Please don't use `rand()` for this. Have a look at http://php.net/manual/en/function.random-int.php instead – rjdown Jul 12 '15 at 19:19
  • @rjdown And how am I going to get the player? – Søren Efa Jul 12 '15 at 19:20
  • Use a weighted array like you've described. Here's an example http://stackoverflow.com/questions/445235/generating-random-results-by-weight-in-php but substitute `mt_rand` for `random_int` – rjdown Jul 12 '15 at 19:25
  • Ref an answer below, also note that `array_rand` uses the same (rather poor) library as `rand`, so please don't use that either if you want fair results. – rjdown Jul 12 '15 at 19:29
  • @rjdown Is there a substitute for random arrays yet? – pal4life Jul 12 '15 at 19:30
  • Not specifically, but you can just do `$array[random_int(1, count($array))]` I guess – rjdown Jul 12 '15 at 19:32

4 Answers4

3

You can use this code:

<?php

    function getWinnerPlayer($players) {
        /* get total amount of tickets */
        $total_tickets = 0;
        foreach ($players as $player) {
            /* var_dump($player->depositedValue); */
            $total_tickets += $player->depositedValue * 100;
        }

        /* get winner ticket */
        $winner = rand(1, $total_tickets);

        /* return winner player */
        $count = 0;
        foreach ($players as $player) {
            // $total_tickets is not the correct variable, sorry
            // $count += $total_tickets->depositedValue * 100;
            $count += $player->depositedValue * 100;
            if ($count >= $winner) return $player;
        }
    }

?>
Nomad Webcode
  • 816
  • 5
  • 9
2

I'm thinking of keeping your idea of numbers instead of bring in an array.

I'm going to have the players hold their ticket positions (start/end). When I pick a random ticket, I'm going to see if my number is within their bounds, and if it is, then I have found the winner.

<?php

class TicketMaster {
    private $players = array();
    public $total = 0;

    public function addPlayer($player) {
        $player->tickets[0] = $this->total;
        $this->total += $player->value;
        $player->tickets[1] = $this->total;
        $this->players[] = $player;
    }

    public function selectWinner() {
        $ticket = rand(0, $this->total);

        foreach ($this->players as $player)
            if ($ticket >= $player->tickets[0] && $ticket <= $player->tickets[1])
                return $player;
        return false;
    }
}

class Player {
    public $name = '';
    public $value = 0;
    public $tickets = array(0, 0);

    function __construct($name, $value) {
        $this->name = $name;
        $this->value = $value;
    }
}

$ticketMaster = new TicketMaster();

$ticketMaster->addPlayer(new Player("John", 200));
$ticketMaster->addPlayer(new Player("Mike", 200));
$ticketMaster->addPlayer(new Player("Dave", 1000));

echo $ticketMaster->selectWinner()->name;

Also

$ticket = rand(0, $this->total); //change to random_int, but I kept it at rand because eval.in only works with this one

Output: Dave

Dave wins most of the time because he has like 1000 tickets, over the other two players who only have 400 combined.

Dave Chen
  • 10,887
  • 8
  • 39
  • 67
  • Thats overcomplicating things, and you didn't even avoid having to iterate the players twice. – Havenard Jul 12 '15 at 19:43
  • Works perfectly. Thanks! – Søren Efa Jul 12 '15 at 19:44
  • @Havenard I've updated my code to avoid looping through the players twice. And of course, I used this method instead to avoid creating an array with an enormous size. (Imagine 100 tickets per person, and 10,000 people, the array size wouldn't be scalable) But a huge number should be fine for PHP to handle. – Dave Chen Jul 12 '15 at 20:00
  • @DaveChen The point is, since you are iterating twice, no point in creating those classes. See [Oscargeek's answer](http://stackoverflow.com/a/31371654/156811). I didn't post an answer because I had to go out, but I'd do something aproximate to his solution. – Havenard Jul 12 '15 at 21:20
1

-- No php required, just mysql. No crazy rowcounts just 12 in this example.

create table rg
(   -- RaffleGuy
    guyId int auto_increment primary key,
    fullName varchar(100) not null,
    cellPhone varchar(20) not null,
    ticketCount int not null,
    winLow int null,
    winHigh int null
);

-- trucate table rg;    -- for testing next time
insert rg (fullName,cellPhone,ticketCount) values ('johnny two thumbs','11111',126);
insert rg (fullName,cellPhone,ticketCount) values ('kim','153111',500);
insert rg (fullName,cellPhone,ticketCount) values ('Lady with Hat','113211',1);
insert rg (fullName,cellPhone,ticketCount) values ('Guy with Nose','14454111',900);
insert rg (fullName,cellPhone,ticketCount) values ('Kipper','2211111',100);
insert rg (fullName,cellPhone,ticketCount) values ('Jipper','222888',400);
insert rg (fullName,cellPhone,ticketCount) values ('smith family','534511111',500);
insert rg (fullName,cellPhone,ticketCount) values ('First Pentacostal Church','3153111',200);
insert rg (fullName,cellPhone,ticketCount) values ('Lady with Hat','1132141',123);
insert rg (fullName,cellPhone,ticketCount) values ('Guy with Nose','14441311',500);
insert rg (fullName,cellPhone,ticketCount) values ('Kipper','2211711',300);
insert rg (fullName,cellPhone,ticketCount) values ('Jipper','2272',200);

update rg
join
(select rg.guyId,(select ifnull(sum(ticketCount)+1,1) from rg r2 where r2.guyId<rg.guyId) below
from rg) nnn
on nnn.guyId=rg.guyId
set winLow=nnn.below,winHigh=nnn.below+ticketCount-1

select * from rg;
#   fullName                    cell#       tix     wLow    wHigh   

1   johnny two thumbs           11111       126     1       126
2   kim                         153111      500     127     626
3   Lady with Hat               113211      1       627     627
4   Guy with Nose               14454111    900     628     1527
5   Kipper                      2211111     100     1528    1627
6   Jipper                      222888      400     1628    2027
7   smith family                534511111   500     2028    2527
8   First Pentacostal Church    3153111     200     2528    2727
9   Lady with Hat               1132141     123     2728    2850
10  Guy with Nose               14441311    500     2851    3350
11  Kipper                      2211711     300     3351    3650
12  Jipper                      2272        200     3651    3850


select sum(ticketCount) into @tottix from rg;   -- 3850

-- seed your random number, I leave that to you
select rand(unix_timestamp()); -- example

select floor(rand()*@tottix)+1 into @thernd; -- 531

select * from rg where winLow<=@thernd and winHigh>=@thernd;
    2   kim 153111  500 127 626

Kim wins, call her
Drew
  • 24,851
  • 10
  • 43
  • 78
0

Here is pseudo code that can help draw the lottery randomly and identify the winner. The best approach in this case of multiple numbers since you are using foreach is to use arrays. So in the code below

<?php
 //Array that holds the players
  $players[] =0;

 //Run this loop from 0 until how many tickets were issued
  for($i=0; $i<100; $i++){
      $players[$i] = $i * 100;
  }

 //Choosing the randomly winning ticket
  $winningTicket = array_rand($players, 1);

//what ticket number won the lottery, (var_dump to be able to see the output)
  echo "Winning Number = ".$players[$winningTicket]."<br/>";;

  //Who won the lottery, (var_dump to be able to see the output)
  echo "Winning Person = Person No.".$winningTicket;


?>
pal4life
  • 3,210
  • 5
  • 36
  • 57
  • sorry but in your code all the players has the same oportunity to win and the question say that all players has a number of tickets equal to amount payed * 100. Also you has a 100 players limit for any reason. – Nomad Webcode Jul 12 '15 at 19:34
  • It outputs: `int(68) int(6800) ` and that does not really helps me with finding the player who won. – Søren Efa Jul 12 '15 at 19:36
  • There is also 2 other things in this answer. 1-> Pseudo code. 2. The comment above 100 mentions , run this loop until how many tickets are issued. I am not sure what the input method is hence. – pal4life Jul 12 '15 at 19:36
  • @SørenEfa Updated the code so you get clear comments instead of dumps. Seems like a new introduction of var_dump to you. – pal4life Jul 12 '15 at 19:41