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,37 @@
1
+ module BCDice
2
+ class << self
3
+ # クラス名を指定してゲームシステムのクラスを取得する
4
+ #
5
+ # @param class_name [String] クラス名
6
+ # @return [Class, nil]
7
+ def game_system_class(class_name)
8
+ BCDice::GameSystem.const_get(class_name)
9
+ rescue NameError
10
+ return nil
11
+ end
12
+
13
+ # 現在ロードされているゲームシステムのクラス一覧を返す
14
+ #
15
+ # @return [Array<Class>]
16
+ def all_game_systems()
17
+ BCDice::GameSystem.constants.map { |class_name| BCDice::GameSystem.const_get(class_name) }
18
+ end
19
+
20
+ # クラス名を指定して対象のソースコードを動的にロードし、そのクラスを取得する
21
+ #
22
+ # @param class_name [String] クラス名
23
+ # @return [Class, nil]
24
+ def dynamic_load(class_name)
25
+ # 対象ディレクトリの外にあるファイルをロードされないように制約を設ける
26
+ unless /\A[A-Z]\w*\z/.match?(class_name)
27
+ return nil
28
+ end
29
+
30
+ require "bcdice/game_system/#{class_name}"
31
+
32
+ return game_system_class(class_name)
33
+ rescue LoadError
34
+ return nil
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,38 @@
1
+ module BCDice
2
+ module Normalize
3
+ module_function
4
+
5
+ # 比較演算子をシンボルに正規化する
6
+ #
7
+ # @param op [String]
8
+ # @return [Symbol, nil]
9
+ def comparison_operator(op)
10
+ case op
11
+ when /<=|=</
12
+ :<=
13
+ when />=|=>/
14
+ :>=
15
+ when /<>|!=|=!/
16
+ :'!='
17
+ when /</
18
+ :<
19
+ when />/
20
+ :>
21
+ when /\=/
22
+ :==
23
+ end
24
+ end
25
+
26
+ # 目標値を正規化する
27
+ #
28
+ # @param val [String]
29
+ # @return [Integer, String] 整数か'?'
30
+ def target_number(val)
31
+ if val == "?"
32
+ val
33
+ else
34
+ val.to_i
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,87 @@
1
+ module BCDice
2
+ # 入力文字列に対して前処理を行う
3
+ #
4
+ # @example
5
+ # Preprocessor.process(
6
+ # "1d6+[2D6]+[40..50]+4D+(3*4) 切り取られる部分",
7
+ # randomizer,
8
+ # game_system
9
+ # ) #=> "1d6+3+46+4D6+7"
10
+ class Preprocessor
11
+ # @param (see #initialize)
12
+ # @return [String]
13
+ def self.process(text, randomizer, game_system)
14
+ Preprocessor.new(text, randomizer, game_system).process()
15
+ end
16
+
17
+ # @param text [String]
18
+ # @param randomizer [Randomizer]
19
+ # @param game_system [Base]
20
+ def initialize(text, randomizer, game_system)
21
+ @text = text
22
+ @randomizer = randomizer
23
+ @game_system = game_system
24
+ end
25
+
26
+ # @return [String]
27
+ def process
28
+ trim_after_whitespace()
29
+ replace_preroll()
30
+ replace_range()
31
+ replace_parentheses()
32
+
33
+ @text = @game_system.change_text(@text)
34
+
35
+ replace_implicit_d6()
36
+
37
+ return @text
38
+ end
39
+
40
+ private
41
+
42
+ # 空白より前だけを取る
43
+ def trim_after_whitespace()
44
+ @text = @text.strip.split(/\s/, 2).first
45
+ end
46
+
47
+ # [1D6]のような部分を事前ダイスロールする
48
+ def replace_preroll()
49
+ @text = @text.gsub(/\[\d+D\d+\]/i) do |matched|
50
+ # Remove '[' and ']'
51
+ command = matched[1..-2].upcase
52
+ times, sides = command.split("D").map(&:to_i)
53
+
54
+ @randomizer.roll_sum(times, sides)
55
+ end
56
+ end
57
+
58
+ # [1...6]のような部分を事前ダイスロールする
59
+ def replace_range
60
+ @text = @text.gsub(/\[(\d+)\.\.\.(\d+)\]/) do |matched|
61
+ first = Regexp.last_match(1).to_i
62
+ last = Regexp.last_match(2).to_i
63
+
64
+ if first > last
65
+ matched
66
+ else
67
+ steps = last - first + 1
68
+ dice = @randomizer.roll_once(steps)
69
+
70
+ first + dice - 1
71
+ end
72
+ end
73
+ end
74
+
75
+ # カッコ書きの数式を事前計算する
76
+ def replace_parentheses
77
+ @text = @text.gsub(%r{\([\d/\+\*\-\(\)]+\)}) do |expr|
78
+ ArithmeticEvaluator.eval(expr, round_type: @game_system.round_type)
79
+ end
80
+ end
81
+
82
+ # nDをnD6に置き換える
83
+ def replace_implicit_d6
84
+ @text = @text.gsub(/(\d+)D([^\w]|$)/i) { "#{Regexp.last_match(1)}D6#{Regexp.last_match(2)}" }
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,137 @@
1
+ module BCDice
2
+ # 乱数生成器
3
+ class Randomizer
4
+ UPPER_LIMIT_DICE_TIMES = 200
5
+ UPPER_LIMIT_DICE_SIDES = 1000
6
+
7
+ def initialize
8
+ @rand_results = []
9
+ @detailed_rand_results = []
10
+ end
11
+
12
+ # @return [Array<Array<(Integer, Integer)>>] ダイスの出目一覧
13
+ attr_reader :rand_results
14
+
15
+ # @return [Array<DetailedRandResult>]
16
+ attr_reader :detailed_rand_results
17
+
18
+ # 実行したダイスロールの詳細
19
+ # @!attribute [rw] kind
20
+ # @return [Symbol]
21
+ # @!attribute [rw] sides
22
+ # @return [Integer] ダイスロールしたダイスの面数
23
+ # @!attribute [rw] value
24
+ # @return [Integer] 値
25
+ DetailedRandResult = Struct.new(:kind, :sides, :value)
26
+
27
+ # 複数個のダイスを振る
28
+ #
29
+ # @param times [Integer] 振るダイスの個数
30
+ # @param sides [Integer] ダイスの面数
31
+ # @return [Array<Integer>] ダイスの出目一覧
32
+ def roll_barabara(times, sides)
33
+ if times <= 0 || times > UPPER_LIMIT_DICE_TIMES
34
+ return []
35
+ end
36
+
37
+ Array.new(times) { roll_once(sides) }
38
+ end
39
+
40
+ # 複数個のダイスを振って、その合計を求める
41
+ #
42
+ # @param times [Integer] 振るダイスの個数
43
+ # @param sides [Integer] ダイスの面数
44
+ # @return [Integer] 出目の合計
45
+ def roll_sum(times, sides)
46
+ roll_barabara(times, sides).sum()
47
+ end
48
+
49
+ # 1回だけダイスロールを行う
50
+ #
51
+ # @param sides [Integer] ダイスの面数
52
+ # @return [Integer] 1以上 *sides* 以下の値のいずれか
53
+ def roll_once(sides)
54
+ if sides <= 0 || sides > UPPER_LIMIT_DICE_SIDES
55
+ return 0
56
+ end
57
+
58
+ dice = rand_inner(sides)
59
+ push_to_detail(:normal, sides, dice)
60
+
61
+ return dice
62
+ end
63
+
64
+ # ダイス表などでindexを参照する用のダイスロール
65
+ # @param sides [Integer]
66
+ # @return [Integer] 0以上 *sides* 未満の整数
67
+ def roll_index(sides)
68
+ roll_once(sides) - 1
69
+ end
70
+
71
+ # 十の位をd10を使って決定するためのダイスロール
72
+ # @return [Integer] 0以上90以下で10の倍数となる整数
73
+ def roll_tens_d10()
74
+ # rand_innerの戻り値を10倍すればすむ話なのだが、既存のテストとの互換性の為に処理をする
75
+ dice = rand_inner(10)
76
+ if dice == 10
77
+ dice = 0
78
+ end
79
+
80
+ ret = dice * 10
81
+
82
+ push_to_detail(:tens_d10, 10, ret)
83
+ return ret
84
+ end
85
+
86
+ # d10を0~9として扱うダイスロール
87
+ # @return [Integer] 0以上9以下の整数
88
+ def roll_d9()
89
+ dice = rand_inner(10) - 1
90
+
91
+ push_to_detail(:d9, 10, dice)
92
+ return dice
93
+ end
94
+
95
+ # D66のダイスロールを行う
96
+ # @param sort_type [Symbol] BCDice::D66SortType
97
+ # @return [Integer]
98
+ def roll_d66(sort_type)
99
+ dice_list = Array.new(2) { roll_once(6) }
100
+
101
+ case sort_type
102
+ when D66SortType::ASC
103
+ dice_list.sort!
104
+ when D66SortType::DESC
105
+ dice_list.sort!.reverse!
106
+ end
107
+
108
+ return dice_list[0] * 10 + dice_list[1]
109
+ end
110
+
111
+ private
112
+
113
+ # @param sides [Integer]
114
+ # @return [Integer] 1以上sides以下の整数
115
+ def rand_inner(sides)
116
+ dice = random(sides)
117
+
118
+ @rand_results << [dice, sides]
119
+ return dice
120
+ end
121
+
122
+ # モックで上書きする用
123
+ # @param sides [Integer]
124
+ # @return [Integer] 1以上sides以下の整数
125
+ def random(sides)
126
+ Kernel.rand(sides) + 1
127
+ end
128
+
129
+ # @param [Symbol] kind
130
+ # @param [Integer] sides
131
+ # @param [Integer] value
132
+ def push_to_detail(kind, sides, value)
133
+ detail = DetailedRandResult.new(kind, sides, value)
134
+ @detailed_rand_results.push(detail)
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,155 @@
1
+ require "bcdice"
2
+ require "readline"
3
+
4
+ module BCDice
5
+ # Read-Eval-Print Loopクラス
6
+ class REPL
7
+ def initialize()
8
+ @game_system = GameSystem::DiceBot
9
+ @hisoty_file = nil
10
+ @debug = false
11
+ end
12
+
13
+ # @param value [Boolean]
14
+ # @return [Boolean]
15
+ attr_writer :debug
16
+
17
+ # コマンド履歴を保存するファイルのパスを指定する
18
+ #
19
+ # @param path [String]
20
+ # @return [void]
21
+ def history_file=(path)
22
+ @hisoty_file = path
23
+
24
+ if File.exist?(@hisoty_file)
25
+ File.open(@hisoty_file) do |f|
26
+ history = f.readlines.map(&:chomp)
27
+ Readline::HISTORY.push(*history)
28
+ end
29
+ end
30
+ end
31
+
32
+ # ゲームシステムを切り替える
33
+ # @param game_system [Game]
34
+ def load_game_system(game_system)
35
+ klass = BCDice.dynamic_load(game_system)
36
+ if klass
37
+ @game_system = klass
38
+ else
39
+ puts "#{game_system.inspect} not found"
40
+ end
41
+ end
42
+
43
+ alias game_system= load_game_system
44
+
45
+ # コマンドの履歴ファイルを保存してREPLを終了する
46
+ # @return [void]
47
+ def quit
48
+ if @hisoty_file
49
+ last_100_comamnds = Readline::HISTORY.to_a.reverse[0, 100].reverse
50
+ File.write(@hisoty_file, last_100_comamnds.join("\n"))
51
+ end
52
+
53
+ exit
54
+ end
55
+
56
+ # REPLを開始する
57
+ # @return [void]
58
+ def run
59
+ puts "BCDice REPL"
60
+ puts '>> "help" shows help messages.'
61
+ loop do
62
+ run_once()
63
+ end
64
+ end
65
+
66
+ private
67
+
68
+ def run_once
69
+ input = Readline.readline(header())&.strip
70
+ unless input
71
+ puts
72
+ return
73
+ end
74
+
75
+ if input.empty?
76
+ return
77
+ end
78
+
79
+ Readline::HISTORY.push(input)
80
+ eval_command(input)
81
+ rescue Interrupt
82
+ quit()
83
+ end
84
+
85
+ def header()
86
+ debug_mode = "(Debug) " if @debug
87
+ "[#{debug_mode}#{@game_system::ID}]> "
88
+ end
89
+
90
+ def eval_command(input)
91
+ args = input.split(" ")
92
+ if args.empty?
93
+ return
94
+ end
95
+
96
+ command = args.shift
97
+
98
+ block = REPL.commands[command]
99
+ if block
100
+ instance_exec(*args, &block)
101
+ else
102
+ eval_game_system(command)
103
+ end
104
+ end
105
+
106
+ class << self
107
+ attr_reader :commands
108
+
109
+ def command(*name, &block)
110
+ @commands ||= {}
111
+ name.each do |key|
112
+ @commands[key] = block
113
+ end
114
+ end
115
+ end
116
+
117
+ command "use", "set" do |game_system|
118
+ load_game_system(game_system)
119
+ end
120
+
121
+ command "debug" do |mode|
122
+ self.debug = !["off", "false"].include?(mode&.downcase)
123
+ end
124
+
125
+ command "history" do
126
+ puts Readline::HISTORY.to_a
127
+ end
128
+
129
+ command "help" do
130
+ puts <<~HELP
131
+ BCDice REPL commands:
132
+ use GAME_SYSTEM # 使うゲームシステムを指定する
133
+ set GAME_SYSTEM # 同上
134
+ debug [on, off] # Debugモードの切替
135
+ debug [true, false] # 同上
136
+ history # コマンド履歴を表示
137
+ help # このメッセージを表示する
138
+ exit, quit, q # REPLを終了する
139
+ HELP
140
+ end
141
+
142
+ command "exit", "quit", "q" do
143
+ quit()
144
+ end
145
+
146
+ def eval_game_system(command)
147
+ gs = @game_system.new(command)
148
+ gs.enable_debug if @debug
149
+ puts gs.eval()
150
+ rescue StandardError => e
151
+ puts e
152
+ puts e.backtrace
153
+ end
154
+ end
155
+ end