Subversion-Projekte lars-tiefland.laravel_shop

Revision

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