bcdice 3.0.0.pre.alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +21 -0
  3. data/.github/.codecov.yaml +10 -0
  4. data/.github/workflows/coverage.yaml +21 -0
  5. data/.github/workflows/lint.yaml +13 -0
  6. data/.github/workflows/test.yml +20 -0
  7. data/.gitignore +14 -0
  8. data/.rubocop.yml +96 -0
  9. data/.rubocop_todo.yml +113 -0
  10. data/CHANGELOG.md +868 -0
  11. data/Gemfile +11 -0
  12. data/LICENSE +29 -0
  13. data/README.md +38 -0
  14. data/ROADMAP.md +30 -0
  15. data/Rakefile +118 -0
  16. data/bcdice.gemspec +27 -0
  17. data/bin/repl.rb +21 -0
  18. data/docs/README.txt +2028 -0
  19. data/docs/dicebot_sort_key.md +72 -0
  20. data/docs/how_to_make_dicebot.md +453 -0
  21. data/lib/bcdice.rb +8 -0
  22. data/lib/bcdice/arithmetic_evaluator.rb +167 -0
  23. data/lib/bcdice/base.rb +423 -0
  24. data/lib/bcdice/command_parser.rb +242 -0
  25. data/lib/bcdice/common_command.rb +23 -0
  26. data/lib/bcdice/common_command/add_dice.rb +54 -0
  27. data/lib/bcdice/common_command/add_dice/node.rb +488 -0
  28. data/lib/bcdice/common_command/add_dice/parser.rb +282 -0
  29. data/lib/bcdice/common_command/add_dice/randomizer.rb +48 -0
  30. data/lib/bcdice/common_command/barabara_dice.rb +57 -0
  31. data/lib/bcdice/common_command/calc.rb +39 -0
  32. data/lib/bcdice/common_command/choice.rb +35 -0
  33. data/lib/bcdice/common_command/d66_dice.rb +63 -0
  34. data/lib/bcdice/common_command/reroll_dice.rb +190 -0
  35. data/lib/bcdice/common_command/upper_dice.rb +165 -0
  36. data/lib/bcdice/common_command/version.rb +26 -0
  37. data/lib/bcdice/dice_table.rb +8 -0
  38. data/lib/bcdice/dice_table/chain_table.rb +33 -0
  39. data/lib/bcdice/dice_table/d66_grid_table.rb +26 -0
  40. data/lib/bcdice/dice_table/d66_range_table.rb +26 -0
  41. data/lib/bcdice/dice_table/d66_table.rb +34 -0
  42. data/lib/bcdice/dice_table/range_table.rb +267 -0
  43. data/lib/bcdice/dice_table/roll_result.rb +43 -0
  44. data/lib/bcdice/dice_table/sai_fic_skill_table.rb +32 -0
  45. data/lib/bcdice/dice_table/table.rb +35 -0
  46. data/lib/bcdice/enum.rb +15 -0
  47. data/lib/bcdice/format.rb +36 -0
  48. data/lib/bcdice/game_system.rb +187 -0
  49. data/lib/bcdice/game_system/AFF2e.rb +141 -0
  50. data/lib/bcdice/game_system/AceKillerGene.rb +55 -0
  51. data/lib/bcdice/game_system/Airgetlamh.rb +117 -0
  52. data/lib/bcdice/game_system/Alsetto.rb +124 -0
  53. data/lib/bcdice/game_system/Alshard.rb +27 -0
  54. data/lib/bcdice/game_system/AlterRaise.rb +282 -0
  55. data/lib/bcdice/game_system/Amadeus.rb +622 -0
  56. data/lib/bcdice/game_system/Amadeus_Korean.rb +501 -0
  57. data/lib/bcdice/game_system/AnimaAnimus.rb +96 -0
  58. data/lib/bcdice/game_system/Arianrhod.rb +50 -0
  59. data/lib/bcdice/game_system/ArsMagica.rb +149 -0
  60. data/lib/bcdice/game_system/Avandner.rb +101 -0
  61. data/lib/bcdice/game_system/BBN.rb +143 -0
  62. data/lib/bcdice/game_system/BadLife.rb +435 -0
  63. data/lib/bcdice/game_system/BarnaKronika.rb +188 -0
  64. data/lib/bcdice/game_system/BattleTech.rb +530 -0
  65. data/lib/bcdice/game_system/BeastBindTrinity.rb +348 -0
  66. data/lib/bcdice/game_system/BeginningIdol.rb +2527 -0
  67. data/lib/bcdice/game_system/BeginningIdol_Korean.rb +2378 -0
  68. data/lib/bcdice/game_system/BladeOfArcana.rb +252 -0
  69. data/lib/bcdice/game_system/BlindMythos.rb +460 -0
  70. data/lib/bcdice/game_system/BloodCrusade.rb +423 -0
  71. data/lib/bcdice/game_system/BloodMoon.rb +213 -0
  72. data/lib/bcdice/game_system/CardRanker.rb +249 -0
  73. data/lib/bcdice/game_system/ChaosFlare.rb +181 -0
  74. data/lib/bcdice/game_system/Chill.rb +163 -0
  75. data/lib/bcdice/game_system/Chill3.rb +52 -0
  76. data/lib/bcdice/game_system/CodeLayerd.rb +132 -0
  77. data/lib/bcdice/game_system/ColossalHunter.rb +569 -0
  78. data/lib/bcdice/game_system/CrashWorld.rb +81 -0
  79. data/lib/bcdice/game_system/Cthulhu.rb +252 -0
  80. data/lib/bcdice/game_system/Cthulhu7th.rb +767 -0
  81. data/lib/bcdice/game_system/Cthulhu7th_ChineseTraditional.rb +386 -0
  82. data/lib/bcdice/game_system/Cthulhu7th_Korean.rb +383 -0
  83. data/lib/bcdice/game_system/CthulhuTech.rb +263 -0
  84. data/lib/bcdice/game_system/Cthulhu_ChineseTraditional.rb +243 -0
  85. data/lib/bcdice/game_system/Cthulhu_Korean.rb +240 -0
  86. data/lib/bcdice/game_system/DarkBlaze.rb +207 -0
  87. data/lib/bcdice/game_system/DarkDaysDrive.rb +425 -0
  88. data/lib/bcdice/game_system/DarkSouls.rb +91 -0
  89. data/lib/bcdice/game_system/DeadlineHeroes.rb +583 -0
  90. data/lib/bcdice/game_system/DemonParasite.rb +524 -0
  91. data/lib/bcdice/game_system/DetatokoSaga.rb +310 -0
  92. data/lib/bcdice/game_system/DetatokoSaga_Korean.rb +310 -0
  93. data/lib/bcdice/game_system/DiceBot.rb +17 -0
  94. data/lib/bcdice/game_system/DiceOfTheDead.rb +111 -0
  95. data/lib/bcdice/game_system/DoubleCross.rb +373 -0
  96. data/lib/bcdice/game_system/DoubleCross_Korean.rb +371 -0
  97. data/lib/bcdice/game_system/Dracurouge.rb +1856 -0
  98. data/lib/bcdice/game_system/Dracurouge_Korean.rb +310 -0
  99. data/lib/bcdice/game_system/DungeonsAndDragons.rb +19 -0
  100. data/lib/bcdice/game_system/EarthDawn.rb +225 -0
  101. data/lib/bcdice/game_system/EarthDawn3.rb +275 -0
  102. data/lib/bcdice/game_system/EarthDawn4.rb +272 -0
  103. data/lib/bcdice/game_system/EclipsePhase.rb +51 -0
  104. data/lib/bcdice/game_system/Elric.rb +36 -0
  105. data/lib/bcdice/game_system/Elysion.rb +1213 -0
  106. data/lib/bcdice/game_system/EmbryoMachine.rb +227 -0
  107. data/lib/bcdice/game_system/EndBreaker.rb +132 -0
  108. data/lib/bcdice/game_system/EtrianOdysseySRS.rb +27 -0
  109. data/lib/bcdice/game_system/Fiasco.rb +123 -0
  110. data/lib/bcdice/game_system/Fiasco_Korean.rb +122 -0
  111. data/lib/bcdice/game_system/FilledWith.rb +1543 -0
  112. data/lib/bcdice/game_system/FullMetalPanic.rb +27 -0
  113. data/lib/bcdice/game_system/FutariSousa.rb +994 -0
  114. data/lib/bcdice/game_system/FutariSousa_Korean.rb +994 -0
  115. data/lib/bcdice/game_system/Garako.rb +559 -0
  116. data/lib/bcdice/game_system/GardenOrder.rb +451 -0
  117. data/lib/bcdice/game_system/GehennaAn.rb +136 -0
  118. data/lib/bcdice/game_system/GeishaGirlwithKatana.rb +120 -0
  119. data/lib/bcdice/game_system/GoblinSlayer.rb +168 -0
  120. data/lib/bcdice/game_system/GoldenSkyStories.rb +77 -0
  121. data/lib/bcdice/game_system/Gorilla.rb +44 -0
  122. data/lib/bcdice/game_system/GranCrest.rb +518 -0
  123. data/lib/bcdice/game_system/Gundog.rb +52 -0
  124. data/lib/bcdice/game_system/GundogRevised.rb +294 -0
  125. data/lib/bcdice/game_system/GundogZero.rb +261 -0
  126. data/lib/bcdice/game_system/Gurps.rb +403 -0
  127. data/lib/bcdice/game_system/GurpsFW.rb +2330 -0
  128. data/lib/bcdice/game_system/HarnMaster.rb +208 -0
  129. data/lib/bcdice/game_system/HatsuneMiku.rb +706 -0
  130. data/lib/bcdice/game_system/Hieizan.rb +48 -0
  131. data/lib/bcdice/game_system/HouraiGakuen.rb +270 -0
  132. data/lib/bcdice/game_system/HuntersMoon.rb +503 -0
  133. data/lib/bcdice/game_system/Illusio.rb +89 -0
  134. data/lib/bcdice/game_system/InfiniteFantasia.rb +51 -0
  135. data/lib/bcdice/game_system/Insane.rb +822 -0
  136. data/lib/bcdice/game_system/Insane_Korean.rb +773 -0
  137. data/lib/bcdice/game_system/IthaWenUa.rb +38 -0
  138. data/lib/bcdice/game_system/JamesBond.rb +45 -0
  139. data/lib/bcdice/game_system/Kamigakari.rb +394 -0
  140. data/lib/bcdice/game_system/Kamigakari_Korean.rb +428 -0
  141. data/lib/bcdice/game_system/KanColle.rb +938 -0
  142. data/lib/bcdice/game_system/KemonoNoMori.rb +258 -0
  143. data/lib/bcdice/game_system/KillDeathBusiness.rb +1420 -0
  144. data/lib/bcdice/game_system/KillDeathBusiness_Korean.rb +1510 -0
  145. data/lib/bcdice/game_system/KurayamiCrying.rb +49 -0
  146. data/lib/bcdice/game_system/LiveraDoll.rb +375 -0
  147. data/lib/bcdice/game_system/LogHorizon.rb +3567 -0
  148. data/lib/bcdice/game_system/LogHorizon_Korean.rb +1407 -0
  149. data/lib/bcdice/game_system/LostRecord.rb +30 -0
  150. data/lib/bcdice/game_system/LostRoyal.rb +242 -0
  151. data/lib/bcdice/game_system/MagicaLogia.rb +1148 -0
  152. data/lib/bcdice/game_system/MeikyuDays.rb +415 -0
  153. data/lib/bcdice/game_system/MeikyuKingdom.rb +466 -0
  154. data/lib/bcdice/game_system/MeikyuKingdomBasic.rb +269 -0
  155. data/lib/bcdice/game_system/MetalHead.rb +249 -0
  156. data/lib/bcdice/game_system/MetalHeadExtream.rb +917 -0
  157. data/lib/bcdice/game_system/MetallicGuardian.rb +31 -0
  158. data/lib/bcdice/game_system/MonotoneMuseum.rb +354 -0
  159. data/lib/bcdice/game_system/MonotoneMuseum_Korean.rb +304 -0
  160. data/lib/bcdice/game_system/Nechronica.rb +211 -0
  161. data/lib/bcdice/game_system/Nechronica_Korean.rb +160 -0
  162. data/lib/bcdice/game_system/NeverCloud.rb +74 -0
  163. data/lib/bcdice/game_system/NightWizard.rb +231 -0
  164. data/lib/bcdice/game_system/NightWizard3rd.rb +24 -0
  165. data/lib/bcdice/game_system/NightmareHunterDeep.rb +117 -0
  166. data/lib/bcdice/game_system/NinjaSlayer.rb +274 -0
  167. data/lib/bcdice/game_system/NjslyrBattle.rb +54 -0
  168. data/lib/bcdice/game_system/Nuekagami.rb +293 -0
  169. data/lib/bcdice/game_system/OneWayHeroics.rb +134 -0
  170. data/lib/bcdice/game_system/OracleEngine.rb +265 -0
  171. data/lib/bcdice/game_system/OrgaRain.rb +77 -0
  172. data/lib/bcdice/game_system/Oukahoushin3rd.rb +162 -0
  173. data/lib/bcdice/game_system/Paradiso.rb +323 -0
  174. data/lib/bcdice/game_system/Paranoia.rb +64 -0
  175. data/lib/bcdice/game_system/ParanoiaRebooted.rb +109 -0
  176. data/lib/bcdice/game_system/ParasiteBlood.rb +231 -0
  177. data/lib/bcdice/game_system/Pathfinder.rb +21 -0
  178. data/lib/bcdice/game_system/Peekaboo.rb +324 -0
  179. data/lib/bcdice/game_system/Pendragon.rb +39 -0
  180. data/lib/bcdice/game_system/PhantasmAdventure.rb +73 -0
  181. data/lib/bcdice/game_system/Postman.rb +185 -0
  182. data/lib/bcdice/game_system/PulpCthulhu.rb +184 -0
  183. data/lib/bcdice/game_system/Raisondetre.rb +171 -0
  184. data/lib/bcdice/game_system/RecordOfLodossWar.rb +58 -0
  185. data/lib/bcdice/game_system/RecordOfSteam.rb +149 -0
  186. data/lib/bcdice/game_system/RokumonSekai2.rb +110 -0
  187. data/lib/bcdice/game_system/RoleMaster.rb +24 -0
  188. data/lib/bcdice/game_system/RuneQuest.rb +47 -0
  189. data/lib/bcdice/game_system/RyuTuber.rb +266 -0
  190. data/lib/bcdice/game_system/Ryutama.rb +199 -0
  191. data/lib/bcdice/game_system/SRS.rb +348 -0
  192. data/lib/bcdice/game_system/SamsaraBallad.rb +111 -0
  193. data/lib/bcdice/game_system/Satasupe.rb +1173 -0
  194. data/lib/bcdice/game_system/ScreamHighSchool.rb +128 -0
  195. data/lib/bcdice/game_system/SevenFortressMobius.rb +34 -0
  196. data/lib/bcdice/game_system/ShadowRun.rb +26 -0
  197. data/lib/bcdice/game_system/ShadowRun4.rb +49 -0
  198. data/lib/bcdice/game_system/ShadowRun5.rb +80 -0
  199. data/lib/bcdice/game_system/SharedFantasia.rb +69 -0
  200. data/lib/bcdice/game_system/ShinMegamiTenseiKakuseihen.rb +85 -0
  201. data/lib/bcdice/game_system/ShinkuuGakuen.rb +506 -0
  202. data/lib/bcdice/game_system/ShinobiGami.rb +680 -0
  203. data/lib/bcdice/game_system/ShoujoTenrankai.rb +677 -0
  204. data/lib/bcdice/game_system/Skynauts.rb +324 -0
  205. data/lib/bcdice/game_system/SteamPunkers.rb +485 -0
  206. data/lib/bcdice/game_system/StellarKnights.rb +856 -0
  207. data/lib/bcdice/game_system/SterileLife.rb +452 -0
  208. data/lib/bcdice/game_system/StrangerOfSwordCity.rb +103 -0
  209. data/lib/bcdice/game_system/StratoShout.rb +316 -0
  210. data/lib/bcdice/game_system/StratoShout_Korean.rb +314 -0
  211. data/lib/bcdice/game_system/Strave.rb +223 -0
  212. data/lib/bcdice/game_system/SwordWorld.rb +491 -0
  213. data/lib/bcdice/game_system/SwordWorld2_0.rb +295 -0
  214. data/lib/bcdice/game_system/SwordWorld2_5.rb +121 -0
  215. data/lib/bcdice/game_system/TherapieSein.rb +93 -0
  216. data/lib/bcdice/game_system/TokumeiTenkousei.rb +96 -0
  217. data/lib/bcdice/game_system/TokyoGhostResearch.rb +122 -0
  218. data/lib/bcdice/game_system/TokyoNova.rb +19 -0
  219. data/lib/bcdice/game_system/Torg.rb +364 -0
  220. data/lib/bcdice/game_system/Torg1_5.rb +139 -0
  221. data/lib/bcdice/game_system/TorgEternity.rb +414 -0
  222. data/lib/bcdice/game_system/TrinitySeven.rb +364 -0
  223. data/lib/bcdice/game_system/TunnelsAndTrolls.rb +287 -0
  224. data/lib/bcdice/game_system/TwilightGunsmoke.rb +527 -0
  225. data/lib/bcdice/game_system/Utakaze.rb +153 -0
  226. data/lib/bcdice/game_system/VampireTheMasquerade5th.rb +132 -0
  227. data/lib/bcdice/game_system/Villaciel.rb +555 -0
  228. data/lib/bcdice/game_system/WARPS.rb +33 -0
  229. data/lib/bcdice/game_system/WaresBlade.rb +34 -0
  230. data/lib/bcdice/game_system/Warhammer.rb +336 -0
  231. data/lib/bcdice/game_system/WitchQuest.rb +275 -0
  232. data/lib/bcdice/game_system/WorldOfDarkness.rb +135 -0
  233. data/lib/bcdice/game_system/YankeeYogSothoth.rb +440 -0
  234. data/lib/bcdice/game_system/YearZeroEngine.rb +134 -0
  235. data/lib/bcdice/game_system/ZettaiReido.rb +142 -0
  236. data/lib/bcdice/game_system/meikyu_kingdom/item_table.rb +383 -0
  237. data/lib/bcdice/game_system/meikyu_kingdom/kingdom_name_table.rb +89 -0
  238. data/lib/bcdice/game_system/meikyu_kingdom/landscape_table.rb +196 -0
  239. data/lib/bcdice/game_system/meikyu_kingdom/name_tables.rb +223 -0
  240. data/lib/bcdice/game_system/meikyu_kingdom/placename_table.rb +214 -0
  241. data/lib/bcdice/game_system/meikyu_kingdom/tables.rb +610 -0
  242. data/lib/bcdice/game_system/meikyu_kingdom/word_table.rb +117 -0
  243. data/lib/bcdice/game_system/meikyu_kingdom_basic/item_table.rb +380 -0
  244. data/lib/bcdice/game_system/meikyu_kingdom_basic/kingdom_table.rb +184 -0
  245. data/lib/bcdice/game_system/meikyu_kingdom_basic/name_table.rb +417 -0
  246. data/lib/bcdice/game_system/meikyu_kingdom_basic/table.rb +912 -0
  247. data/lib/bcdice/game_system/meikyu_kingdom_basic/word_table.rb +121 -0
  248. data/lib/bcdice/game_system/one_way_heroics/dungeon_table.rb +67 -0
  249. data/lib/bcdice/game_system/one_way_heroics/random_event_table.rb +166 -0
  250. data/lib/bcdice/game_system/one_way_heroics/tables.rb +668 -0
  251. data/lib/bcdice/loader.rb +37 -0
  252. data/lib/bcdice/normalize.rb +38 -0
  253. data/lib/bcdice/preprocessor.rb +87 -0
  254. data/lib/bcdice/randomizer.rb +137 -0
  255. data/lib/bcdice/repl.rb +155 -0
  256. data/lib/bcdice/user_defined_dice_table.rb +153 -0
  257. data/lib/bcdice/version.rb +3 -0
  258. metadata +304 -0
@@ -0,0 +1,8 @@
1
+ require "bcdice/version"
2
+ require "bcdice/arithmetic_evaluator.rb"
3
+
4
+ require "bcdice/base"
5
+ require "bcdice/loader"
6
+ require "bcdice/game_system/DiceBot"
7
+ require "bcdice/common_command"
8
+ require "bcdice/preprocessor"
@@ -0,0 +1,167 @@
1
+ module BCDice
2
+ #
3
+ # 四則演算を評価するクラス
4
+ #
5
+ class ArithmeticEvaluator
6
+ class << self
7
+ # 四則演算を評価する
8
+ # @param expr [String] 評価する式
9
+ # @param round_type [Symbol] 端数処理の種類
10
+ # @return [Integer] 評価結果を返す。不正な式の場合には0を返す。
11
+ def eval(expr, round_type: RoundType::FLOOR)
12
+ ArithmeticEvaluator.new(expr, round_type: round_type).eval()
13
+ end
14
+ end
15
+
16
+ # @param [String, nil] expr 評価する式
17
+ # @param [Symbol] round_type 端数処理の種類
18
+ def initialize(expr, round_type: RoundType::FLOOR)
19
+ @expr = expr
20
+ @round_type = round_type
21
+
22
+ @error = false
23
+ end
24
+
25
+ # @return [Boolean] 式の評価時にエラーが発生したか
26
+ def error?
27
+ @error
28
+ end
29
+
30
+ # 四則演算を評価する
31
+ # 同一インスタンスでevalを二回以上実行した場合の挙動は未定義とする
32
+ #
33
+ # @return [Integer] 評価結果を返す。不正な式の場合には0を返す。
34
+ def eval
35
+ if @expr.nil?
36
+ return 0
37
+ end
38
+
39
+ unless @expr.is_a?(String)
40
+ raise TypeError, "expr must be String, not #{@expr.class}"
41
+ end
42
+
43
+ @tokens = tokenize(@expr)
44
+ @idx = 0
45
+ @error = false
46
+
47
+ ret = expr()
48
+ if @error
49
+ return 0
50
+ else
51
+ return ret
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def tokenize(expr)
58
+ expr.gsub(%r{[\(\)\+\-\*/]}) { |e| " #{e} " }.split(" ")
59
+ end
60
+
61
+ def add
62
+ ret = mul()
63
+
64
+ loop do
65
+ if consume("+")
66
+ ret += mul()
67
+ elsif consume("-")
68
+ ret -= mul()
69
+ else
70
+ break
71
+ end
72
+ end
73
+
74
+ return ret
75
+ end
76
+ alias expr add
77
+
78
+ def mul
79
+ ret = unary()
80
+
81
+ loop do
82
+ if consume("*")
83
+ ret *= unary()
84
+ elsif consume("/")
85
+ ret = div(ret, unary())
86
+ else
87
+ break
88
+ end
89
+ end
90
+
91
+ return ret
92
+ end
93
+
94
+ def div(left, right)
95
+ if right.zero?
96
+ @error = true
97
+ return 0
98
+ end
99
+
100
+ case @round_type
101
+ when RoundType::CEIL
102
+ return (left.to_f / right).ceil
103
+ when RoundType::ROUND
104
+ return (left.to_f / right).round
105
+ when RoundType::FLOOR
106
+ return left / right
107
+ else
108
+ raise ArgumentError, "unknown round type: #{@round_type.inspect}"
109
+ end
110
+ end
111
+
112
+ def unary
113
+ if consume("+")
114
+ unary()
115
+ elsif consume("-")
116
+ -unary()
117
+ else
118
+ term()
119
+ end
120
+ end
121
+
122
+ def term
123
+ if consume("(")
124
+ ret = expr()
125
+ expect(")")
126
+ return ret
127
+ else
128
+ return expect_number()
129
+ end
130
+ end
131
+
132
+ def consume(str)
133
+ if @tokens[@idx] != str
134
+ return false
135
+ end
136
+
137
+ @idx += 1
138
+ return true
139
+ end
140
+
141
+ def expect(str)
142
+ if @tokens[@idx] != str
143
+ @error = true
144
+ end
145
+
146
+ @idx += 1
147
+ end
148
+
149
+ def expect_number()
150
+ unless integer?(@tokens[@idx])
151
+ @error = true
152
+ @idx += 1
153
+ return 0
154
+ end
155
+
156
+ ret = @tokens[@idx].to_i
157
+ @idx += 1
158
+ return ret
159
+ end
160
+
161
+ def integer?(str)
162
+ # Ruby 1.9 以降では Kernel.#Integer を使うべき
163
+ # Ruby 1.8 にもあるが、基数を指定できない問題がある
164
+ !/^\d+$/.match(str).nil?
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,423 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bcdice/randomizer"
4
+ require "bcdice/dice_table"
5
+ require "bcdice/enum"
6
+
7
+ module BCDice
8
+ class Base
9
+ class << self
10
+ # 接頭辞(反応するコマンド)の配列を返す
11
+ # @return [Array<String>]
12
+ attr_reader :prefixes
13
+
14
+ # 応答するコマンドのprefixを登録する
15
+ # @param prefixes [Array<String>]
16
+ def register_prefix(*prefixes)
17
+ @prefixes ||= []
18
+ @prefixes.concat(prefixes.flatten)
19
+ end
20
+
21
+ # ゲームシステム固有のコマンドにマッチする正規表現を返す
22
+ # 正規表現を一度生成したら、以後コマンドの登録はできないようにする
23
+ #
24
+ # @return [Regexp]
25
+ def prefixes_pattern
26
+ @prefixes_pattern ||= nil
27
+ return @prefixes_pattern if @prefixes_pattern
28
+
29
+ @prefixes ||= []
30
+ @prefixes.freeze
31
+ @prefixes_pattern =
32
+ if @prefixes.empty?
33
+ /(?!)/ # 何にもマッチしない正規表現
34
+ else
35
+ /^(S)?(#{@prefixes.join('|')})/i
36
+ end.freeze
37
+ end
38
+
39
+ # 応答するコマンド全てにマッチする正規表現を返す
40
+ # 正規表現を一度生成したら、以後コマンドの登録はできないようにする
41
+ #
42
+ # @return [Regexp]
43
+ def command_pattern
44
+ @command_pattern ||= nil
45
+ return @command_pattern if @command_pattern
46
+
47
+ @prefixes ||= []
48
+ @prefixes.freeze
49
+ pattarns = CommonCommand::COMMANDS.map { |c| c::PREFIX_PATTERN.source } + @prefixes
50
+
51
+ @command_pattern = /^S?(#{pattarns.join("|")})/i.freeze
52
+ end
53
+ end
54
+
55
+ def initialize(command)
56
+ @raw_input = command
57
+
58
+ @sort_add_dice = false # 加算ダイスでダイス目をソートするかどうか
59
+ @sort_barabara_dice = false # バラバラダイスでダイス目をソートするかどうか
60
+
61
+ @enabled_d66 = true # D66ダイスを利用するかどうか
62
+ @d66_sort_type = D66SortType::NO_SORT # 入れ替えの種類 詳しくはBCDice::D66SortTypeを参照すること
63
+
64
+ @enabled_d9 = false # D9ダイスを有効にするか(ガンドッグ)で使用
65
+
66
+ @round_type = RoundType::FLOOR # 割り算をした時の端数の扱い (FLOOR: 切り捨て, CEIL: 切り上げ, ROUND: 四捨五入)
67
+
68
+ @upper_dice_reroll_threshold = nil # UpperDiceで振り足しをする出目の閾値 nilの場合デフォルト設定なし
69
+ @reroll_dice_reroll_threshold = nil # RerollDiceで振り足しをする出目の閾値 nilの場合デフォルト設定なし
70
+
71
+ @default_cmp_op = nil # 目標値が空欄の場合の比較演算子をシンボルで指定する (:>, :>= :<, :<=, :==, :!=)
72
+ @default_target_number = nil # 目標値が空欄の場合の目標値 こちらだけnilにするのは想定していないので注意
73
+
74
+ @enabled_upcase_input = true # 入力を String#upcase するかどうか
75
+
76
+ @is_secret = false
77
+ @is_success = false
78
+ @is_failure = false
79
+ @is_critical = false
80
+ @is_fumble = false
81
+
82
+ @randomizer = BCDice::Randomizer.new
83
+ @debug = false
84
+ end
85
+
86
+ attr_accessor :randomizer
87
+
88
+ # D66のダイス入れ替えの種類
89
+ #
90
+ # @return [Symbol]
91
+ attr_reader :d66_sort_type
92
+
93
+ # 端数処理の種類
94
+ #
95
+ # @return [Symbol]
96
+ attr_reader :round_type
97
+
98
+ # UpperDiceで振り足しをする出目の閾値
99
+ #
100
+ # @return [Integer, nil]
101
+ attr_reader :upper_dice_reroll_threshold
102
+
103
+ # RerollDiceで振り足しをする出目の閾値
104
+ #
105
+ # @return [Integer, nil]
106
+ attr_reader :reroll_dice_reroll_threshold
107
+
108
+ # デフォルトの比較演算子
109
+ #
110
+ # @return [Symbol, nil]
111
+ attr_reader :default_cmp_op
112
+
113
+ # デフォルトの目標値
114
+ #
115
+ # @return [Integer, nil]
116
+ attr_reader :default_target_number
117
+
118
+ # 加算ダイスでダイス目をソートするかどうか
119
+ #
120
+ # @return [Boolean]
121
+ def sort_add_dice?
122
+ @sort_add_dice
123
+ end
124
+
125
+ # バラバラダイスでダイス目をソートするかどうか
126
+ #
127
+ # @return [Boolean]
128
+ def sort_barabara_dice?
129
+ @sort_barabara_dice
130
+ end
131
+
132
+ # D66ダイスが有効か
133
+ #
134
+ # @return [Boolean]
135
+ def enabled_d66?
136
+ @enabled_d66
137
+ end
138
+
139
+ # D9ダイスが有効か
140
+ #
141
+ # @return [Boolean]
142
+ def enabled_d9?
143
+ @enabled_d9
144
+ end
145
+
146
+ # シークレットコマンドか
147
+ #
148
+ # @return [Boolean]
149
+ def secret?
150
+ @is_secret
151
+ end
152
+
153
+ # 結果が成功か
154
+ # @return [Boolean]
155
+ def success?
156
+ @is_success
157
+ end
158
+
159
+ # 結果が失敗か
160
+ # @return [Boolean]
161
+ def failure?
162
+ @is_failure
163
+ end
164
+
165
+ # 結果がクリティカルか
166
+ # @return [Boolean]
167
+ def critical?
168
+ @is_critical
169
+ end
170
+
171
+ # 結果がファンブルか
172
+ # @return [Boolean]
173
+ def fumble?
174
+ @is_fumble
175
+ end
176
+
177
+ # デバッグを有用にする
178
+ def enable_debug
179
+ @debug = true
180
+ end
181
+
182
+ # コマンドを評価する
183
+ # @return [String, nil] コマンド実行結果。コマンドが実行できなかった場合はnilを返す
184
+ def eval
185
+ command = BCDice::Preprocessor.process(@raw_input, @randomizer, self)
186
+ upcased_command = command.upcase
187
+
188
+ result = dice_command(command)
189
+ result ||= eval_common_command(upcased_command)
190
+
191
+ return result
192
+ end
193
+
194
+ # ゲームシステムごとの入力コマンドの前処理
195
+ # @deprecated これを使わずに +eval_common_command+ 内でパースすることを推奨する
196
+ # @param string [String]
197
+ # @return [String]
198
+ def change_text(string)
199
+ string
200
+ end
201
+
202
+ # @param total [Integer] コマンド合計値
203
+ # @param dice_total [Integer] ダイス目の合計値
204
+ # @param dice_list [Array<Integer>] ダイスの一覧
205
+ # @param sides [Integer] 振ったダイスの面数
206
+ # @param cmp_op [Symbol] 比較演算子
207
+ # @param target [Integer, String] 目標値の整数か'?'
208
+ # @return [String]
209
+ def check_result(total, dice_total, dice_list, sides, cmp_op, target)
210
+ ret =
211
+ case [dice_list.size, sides]
212
+ when [1, 100]
213
+ check_1D100(total, dice_total, cmp_op, target)
214
+ when [1, 20]
215
+ check_1D20(total, dice_total, cmp_op, target)
216
+ when [2, 6]
217
+ check_2D6(total, dice_total, dice_list, cmp_op, target)
218
+ end
219
+
220
+ return ret unless ret.nil? || ret.empty?
221
+
222
+ ret =
223
+ case sides
224
+ when 10
225
+ check_nD10(total, dice_total, dice_list, cmp_op, target)
226
+ when 6
227
+ check_nD6(total, dice_total, dice_list, cmp_op, target)
228
+ end
229
+
230
+ return ret unless ret.nil? || ret.empty?
231
+
232
+ check_nDx(total, cmp_op, target)
233
+ end
234
+
235
+ # シャドウラン用グリッチ判定
236
+ # @param count_one [Integer] 出目1の数
237
+ # @param dice_total_count [Integer] ダイスロールしたダイスの数
238
+ # @param count_success [Integer] 成功数
239
+ # @return [String, nil]
240
+ def grich_text(count_one, dice_total_count, count_success); end
241
+
242
+ private
243
+
244
+ def eval_common_command(command)
245
+ CommonCommand::COMMANDS.each do |klass|
246
+ cmd = klass.new(command, @randomizer, self)
247
+ out = cmd.eval()
248
+
249
+ @is_secret = cmd.secret?
250
+ return out if out
251
+ end
252
+
253
+ return nil
254
+ end
255
+
256
+ def dice_command(command)
257
+ command = command.upcase if @enabled_upcase_input
258
+
259
+ m = self.class.prefixes_pattern.match(command)
260
+ unless m
261
+ return nil
262
+ end
263
+
264
+ secret = !m[1].nil?
265
+ command = command[1..-1] if secret # 先頭の 'S' をとる
266
+
267
+ output = eval_game_system_specific_command(command)
268
+ @is_secret ||= secret
269
+ if output.nil? || output.empty? || output == "1"
270
+ return nil
271
+ else
272
+ return output.to_s
273
+ end
274
+ end
275
+
276
+ # @param command [String]
277
+ # @return [String, nil]
278
+ def eval_game_system_specific_command(command); end
279
+
280
+ # 成功か失敗かを文字列で返す
281
+ #
282
+ # @param (see #check_result)
283
+ # @return [String]
284
+ def check_nDx(total, cmp_op, target)
285
+ return " > 失敗" if target.is_a?(String)
286
+
287
+ if total.send(cmp_op, target)
288
+ " > 成功"
289
+ else
290
+ " > 失敗"
291
+ end
292
+ end
293
+
294
+ # @param (see #check_result)
295
+ # @return [nil]
296
+ def check_1D100(total, dice_total, cmp_op, target); end
297
+
298
+ # @param (see #check_result)
299
+ # @return [nil]
300
+ def check_1D20(total, dice_total, cmp_op, target); end
301
+
302
+ # @param (see #check_result)
303
+ # @return [nil]
304
+ def check_nD10(total, dice_total, dice_list, cmp_op, target); end
305
+
306
+ # @param (see #check_result)
307
+ # @return [nil]
308
+ def check_2D6(total, dice_total, dice_list, cmp_op, target); end
309
+
310
+ # @param (see #check_result)
311
+ # @return [nil]
312
+ def check_nD6(total, dice_total, dice_list, cmp_op, target); end
313
+
314
+ def get_table_by_2d6(table)
315
+ get_table_by_nD6(table, 2)
316
+ end
317
+
318
+ def get_table_by_1d6(table)
319
+ get_table_by_nD6(table, 1)
320
+ end
321
+
322
+ def get_table_by_nD6(table, count)
323
+ get_table_by_nDx(table, count, 6)
324
+ end
325
+
326
+ def get_table_by_nDx(table, count, diceType)
327
+ num = @randomizer.roll_sum(count, diceType)
328
+
329
+ text = get_table_value(table[num - count])
330
+
331
+ return "1", 0 if text.nil?
332
+
333
+ return text, num
334
+ end
335
+
336
+ def get_table_by_1d3(table)
337
+ debug("get_table_by_1d3")
338
+
339
+ count = 1
340
+ num = @randomizer.roll_sum(count, 6)
341
+ debug("num", num)
342
+
343
+ index = ((num - 1) / 2)
344
+ debug("index", index)
345
+
346
+ text = table[index]
347
+
348
+ return "1", 0 if text.nil?
349
+
350
+ return text, num
351
+ end
352
+
353
+ # D66 ロール用(スワップ、たとえば出目が【6,4】なら「64」ではなく「46」とする
354
+ def get_table_by_d66_swap(table)
355
+ number = @randomizer.roll_d66(D66SortType::ASC)
356
+ return get_table_by_number(number, table), number
357
+ end
358
+
359
+ # D66 ロール用
360
+ def get_table_by_d66(table)
361
+ dice1 = @randomizer.roll_once(6)
362
+ dice2 = @randomizer.roll_once(6)
363
+
364
+ num = (dice1 - 1) * 6 + (dice2 - 1)
365
+
366
+ text = table[num]
367
+
368
+ indexText = "#{dice1}#{dice2}"
369
+
370
+ return "1", indexText if text.nil?
371
+
372
+ return text, indexText
373
+ end
374
+
375
+ # ** 汎用表サブルーチン
376
+ def get_table_by_number(index, table, default = "1")
377
+ table.each do |item|
378
+ number = item[0]
379
+ if number >= index
380
+ return get_table_value(item[1])
381
+ end
382
+ end
383
+
384
+ return get_table_value(default)
385
+ end
386
+
387
+ def get_table_value(data)
388
+ if data.is_a?(Proc)
389
+ return data.call()
390
+ end
391
+
392
+ return data
393
+ end
394
+
395
+ def roll_tables(command, tables)
396
+ table = tables[command]
397
+ unless table
398
+ return nil
399
+ end
400
+
401
+ return table.roll(@randomizer).to_s
402
+ end
403
+
404
+ # デバッグ出力を行う
405
+ # @param [Object] target 対象項目
406
+ # @param [Object] values 値
407
+ def debug(target, *values)
408
+ return unless @debug
409
+
410
+ targetStr = target.is_a?(String) ? target : target.inspect
411
+
412
+ if values.empty?
413
+ warn targetStr
414
+ else
415
+ valueStrs = values.map do |value|
416
+ value.is_a?(String) ? %("#{value}") : value.inspect
417
+ end
418
+
419
+ warn "#{targetStr}: #{valueStrs.join(', ')}"
420
+ end
421
+ end
422
+ end
423
+ end