Subversion-Projekte lars-tiefland.laravel_shop

Revision

Revision 148 | Zur aktuellen Revision | Details | Vergleich mit vorheriger | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Illuminate\Support;
4
 
5
use RuntimeException;
6
 
7
class Lottery
8
{
9
    /**
10
     * The number of expected wins.
11
     *
12
     * @var int|float
13
     */
14
    protected $chances;
15
 
16
    /**
17
     * The number of potential opportunities to win.
18
     *
19
     * @var int|null
20
     */
21
    protected $outOf;
22
 
23
    /**
24
     * The winning callback.
25
     *
26
     * @var null|callable
27
     */
28
    protected $winner;
29
 
30
    /**
31
     * The losing callback.
32
     *
33
     * @var null|callable
34
     */
35
    protected $loser;
36
 
37
    /**
38
     * The factory that should be used to generate results.
39
     *
40
     * @var callable|null
41
     */
42
    protected static $resultFactory;
43
 
44
    /**
45
     * Create a new Lottery instance.
46
     *
47
     * @param  int|float  $chances
150 lars 48
     * @param  int|null  $outOf
49
     * @return void
148 lars 50
     */
51
    public function __construct($chances, $outOf = null)
52
    {
53
        if ($outOf === null && is_float($chances) && $chances > 1) {
54
            throw new RuntimeException('Float must not be greater than 1.');
55
        }
56
 
57
        $this->chances = $chances;
58
 
59
        $this->outOf = $outOf;
60
    }
61
 
62
    /**
63
     * Create a new Lottery instance.
64
     *
65
     * @param  int|float  $chances
150 lars 66
     * @param  int|null  $outOf
148 lars 67
     * @return static
68
     */
69
    public static function odds($chances, $outOf = null)
70
    {
71
        return new static($chances, $outOf);
72
    }
73
 
74
    /**
75
     * Set the winner callback.
76
     *
77
     * @param  callable  $callback
78
     * @return $this
79
     */
80
    public function winner($callback)
81
    {
82
        $this->winner = $callback;
83
 
84
        return $this;
85
    }
86
 
87
    /**
88
     * Set the loser callback.
89
     *
90
     * @param  callable  $callback
91
     * @return $this
92
     */
93
    public function loser($callback)
94
    {
95
        $this->loser = $callback;
96
 
97
        return $this;
98
    }
99
 
100
    /**
101
     * Run the lottery.
102
     *
103
     * @param  mixed  ...$args
104
     * @return mixed
105
     */
106
    public function __invoke(...$args)
107
    {
108
        return $this->runCallback(...$args);
109
    }
110
 
111
    /**
112
     * Run the lottery.
113
     *
114
     * @param  null|int  $times
115
     * @return mixed
116
     */
117
    public function choose($times = null)
118
    {
119
        if ($times === null) {
120
            return $this->runCallback();
121
        }
122
 
123
        $results = [];
124
 
125
        for ($i = 0; $i < $times; $i++) {
126
            $results[] = $this->runCallback();
127
        }
128
 
129
        return $results;
130
    }
131
 
132
    /**
133
     * Run the winner or loser callback, randomly.
134
     *
135
     * @param  mixed  ...$args
136
     * @return callable
137
     */
138
    protected function runCallback(...$args)
139
    {
140
        return $this->wins()
141
            ? ($this->winner ?? fn () => true)(...$args)
142
            : ($this->loser ?? fn () => false)(...$args);
143
    }
144
 
145
    /**
146
     * Determine if the lottery "wins" or "loses".
147
     *
148
     * @return bool
149
     */
150
    protected function wins()
151
    {
152
        return static::resultFactory()($this->chances, $this->outOf);
153
    }
154
 
155
    /**
156
     * The factory that determines the lottery result.
157
     *
158
     * @return callable
159
     */
160
    protected static function resultFactory()
161
    {
162
        return static::$resultFactory ?? fn ($chances, $outOf) => $outOf === null
163
            ? random_int(0, PHP_INT_MAX) / PHP_INT_MAX <= $chances
164
            : random_int(1, $outOf) <= $chances;
165
    }
166
 
167
    /**
168
     * Force the lottery to always result in a win.
169
     *
170
     * @param  callable|null  $callback
171
     * @return void
172
     */
173
    public static function alwaysWin($callback = null)
174
    {
175
        self::setResultFactory(fn () => true);
176
 
177
        if ($callback === null) {
178
            return;
179
        }
180
 
181
        $callback();
182
 
183
        static::determineResultNormally();
184
    }
185
 
186
    /**
187
     * Force the lottery to always result in a lose.
188
     *
189
     * @param  callable|null  $callback
190
     * @return void
191
     */
192
    public static function alwaysLose($callback = null)
193
    {
194
        self::setResultFactory(fn () => false);
195
 
196
        if ($callback === null) {
197
            return;
198
        }
199
 
200
        $callback();
201
 
202
        static::determineResultNormally();
203
    }
204
 
205
    /**
206
     * Set the sequence that will be used to determine lottery results.
207
     *
208
     * @param  array  $sequence
209
     * @param  callable|null  $whenMissing
210
     * @return void
211
     */
212
    public static function fix($sequence, $whenMissing = null)
213
    {
214
        return static::forceResultWithSequence($sequence, $whenMissing);
215
    }
216
 
217
    /**
218
     * Set the sequence that will be used to determine lottery results.
219
     *
220
     * @param  array  $sequence
221
     * @param  callable|null  $whenMissing
222
     * @return void
223
     */
224
    public static function forceResultWithSequence($sequence, $whenMissing = null)
225
    {
226
        $next = 0;
227
 
228
        $whenMissing ??= function ($chances, $outOf) use (&$next) {
229
            $factoryCache = static::$resultFactory;
230
 
231
            static::$resultFactory = null;
232
 
233
            $result = static::resultFactory()($chances, $outOf);
234
 
235
            static::$resultFactory = $factoryCache;
236
 
237
            $next++;
238
 
239
            return $result;
240
        };
241
 
242
        static::setResultFactory(function ($chances, $outOf) use (&$next, $sequence, $whenMissing) {
243
            if (array_key_exists($next, $sequence)) {
244
                return $sequence[$next++];
245
            }
246
 
247
            return $whenMissing($chances, $outOf);
248
        });
249
    }
250
 
251
    /**
252
     * Indicate that the lottery results should be determined normally.
253
     *
254
     * @return void
255
     */
256
    public static function determineResultNormally()
257
    {
258
        static::$resultFactory = null;
259
    }
260
 
261
    /**
262
     * Set the factory that should be used to deterine the lottery results.
263
     *
264
     * @param  callable  $factory
265
     * @return void
266
     */
267
    public static function setResultFactory($factory)
268
    {
269
        self::$resultFactory = $factory;
270
    }
271
}