Data::Lotter - Data lottery module by its own weight


Data-Lotter documentation Contained in the Data-Lotter distribution.

Index


Code Index:

NAME

Top

Data::Lotter - Data lottery module by its own weight

SYNOPSIS

Top

  use Data::Lotter;

  # prepare a HASH data 
  my %candidates = (
    red    => 10,
    green  => 10,
    blue   => 10,
    yellow => 10,
    white  => 10, 
  );

  my $lotter = Data::Lotter->new(%candidates);

  # normal pickup 
  my $ret = $lotter->pickup(3);
  # ex. ( red, green, yellow ) = @ret

  # removal pickup ( => %candidates will be left 4 items )
  my @ret = $lotter->pickup(1, "REMOVE");

DESCRIPTION

Top

Data::Lotter is data lottery module. It provides both pattern such as the lottery and the election.

METHODS

Top

new()

pickup()

left_items()

left_item_waits()

debug()

AUTHOR

Top

Takeshi Miki <miki@cpan.org>

Original idea was spawned by KANEGON

Special thanks to Daisuke Maki

LICENSE

Top

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

SEE ALSO

Top


Data-Lotter documentation Contained in the Data-Lotter distribution.

package Data::Lotter;

use base qw( Class::Accessor::Fast );
use strict;
use warnings;
use Data::Dumper;
use constant DEBUG => $ENV{DATA_LOTTER_DEBUG};
use 5.8.1;

our $VERSION = '0.00003';

__PACKAGE__->mk_accessors qw( lists available );

*debug = DEBUG
  ? sub {
    my $mess = shift;
    print STDERR $mess, "\n";
  }
  : sub { };

sub new {
    my $class = shift;
    my %lists = @_;

    _scale_up(\%lists);

    my $cumulative = 0;
    foreach my $weight ( values %lists ) {
        $weight = int($weight);
        $cumulative += $weight;
    }

    return $class->SUPER::new( { available => $cumulative, lists => \%lists } );
}

sub _scale_up{
    my $lists_ref = shift;

    my ($i,$j);
    while ( my ( $key, $value ) = each %$lists_ref ) {
        $value =~ /\.(\d+)/;
        $1 and $i = length $1;
        if( !$j or $i > $j ){
            $j = $i;
        }
    }
    if($j){
        $j = 6 if $j > 6;
        my $scale = 10 ** $j;
        if($scale > 1){
            for(keys(%$lists_ref)){
                $lists_ref->{$_} *= $scale;
            }
        }
    }
}

sub pickup {
    my $self   = shift;
    my $num    = shift;
    my $remove = shift || '';
    my @ret;

    my $lists = $self->lists;
  OUTER:
    while ( $num-- ) {

        Dumper $lists; 
        # mysterious hack
        # If there is not this, I can't pass the test code. 

        my $n = int( rand( $self->available ) ) + 1;
        debug("-----------------------");
        debug("NUM: $num");
        debug("RANDOM: $n");
        debug( "BEFORE: " . Dumper($lists) );
        while ( my ( $item, $weight ) = each %$lists ) {
            if ( $weight > 0 && $weight >= $n ) {
                push @ret, $item;
                debug("HIT: $item");
                if ($remove) {
                    delete $lists->{$item};
                    $self->available( $self->available - $weight );
                }
                else {
                    $lists->{$item}--;
                    $self->available( $self->available - 1 );
                }
                debug( "AFTER: " . Dumper($lists) );
                next OUTER;
            }
            $n -= $weight;
        }
    }
    debug( "RETURN: " . join( ",", @ret ) );
    return @ret;
}

sub left_items {
    my $self  = shift;
    my @items = keys %{ $self->lists };
    return @items;
}

sub left_item_waits {
    my $self = shift;
    my $item = shift;
    return $self->lists->{$item};
}

1;

__END__