1<?php 2 3namespace TableRoller\Table; 4 5class BaseTable implements TableInterface 6{ 7 protected array $options = []; 8 protected int $count; 9 protected int $upper_bound; 10 protected array $keys; 11 12 protected function pickOne() : int { 13 return $this->keys[rand(0, $this->count - 1)]; 14 } 15 16 public function roll(int $times = 1) : array { 17 $result = []; 18 19 for ($i = 0; $i < $times; $i++) { 20 $result[] = $this->proceessResult($this->options[$this->pickOne()]); 21 } 22 23 return $result; 24 } 25 26 protected function setOptions(array $options) { 27 28 foreach ($options as $entry) { 29 if (preg_match('/^(\d+)\:(.*)$/', $entry, $match)) { 30 $this->options[(int)$match[1]] = trim($match[2]); 31 } elseif (preg_match('/^(\d+)\-(\d+)\:(.*)$/', $entry, $match)) { 32 foreach(range($match[1], $match[2]) as $key) { 33 $this->options[$key] = $match[3]; 34 } 35 } else { 36 $this->options[] = $entry; 37 } 38 } 39 40 $this->count = count($this->options); 41 $this->keys = array_keys($this->options); 42 } 43 44 public function rollOnce() : string { 45 return $this->proceessResult($this->options[$this->pickOne()]); 46 } 47 48 public function rollWithoutRepeats(int $times = 1) : array { 49 $result = []; 50 $used = []; 51 52 while (count($result) < $times) { 53 $pick = $this->pickOne(); 54 55 if (!in_array($pick, $used)) { 56 $result[] = $this->proceessResult($this->options[$pick]); 57 $used[] = $pick; 58 } 59 } 60 61 return $result; 62 } 63 64 private function proceessResult(string $result) { 65 66 if (false !== strpos($result, '[')) { 67 $result = preg_replace_callback('/\[([^]]+)\]/', function($match) { 68 $options = explode('|', $match[1]); 69 shuffle($options); 70 return $options[0]; 71 }, $result); 72 73 } 74 75 if (false !== strpos($result, '{')) { 76 $result = preg_replace_callback('/{(\d*)[Dd](\d+)(\+|\-)?(\d+)?}/', function($match) { 77 return $this->rollDie($match[0]); 78 }, $result); 79 80 } 81 82 return $result; 83 } 84 85 public function rollDie(string $formula) { 86 $formula = strtoupper(trim($formula)); 87 preg_match('/(\d*)[Dd](\d+)(\+|\-)?(\d+)?/', $formula, $parts); 88 $rolls = empty($parts[1]) ? 1 : $parts[1]; 89 $die = (int) $parts[2]; 90 91 $mod = 0; 92 if (!empty($parts[3])) { 93 $mod = (int)($parts[3] . $parts[4]); 94 } 95 $result = 0; 96 97 for ($i = 0; $i < $rolls; $i++) { 98 $result += rand(1, $die); 99 } 100 101 $result += $mod; 102 return $result; 103 } 104 105 public function __invoke() : string { 106 return $this->rollOnce(); 107 } 108 109 public function __toString() : string { 110 return $this->rollOnce(); 111 } 112}