Giter VIP home page Giter VIP logo

bcdice's Issues

巨大なダイスボットファイルの分割

ログ・ホライズン(v2.04.00時点で3551行)に代表される、巨大なダイスボットファイルを分割して、処理を探しやすくしたい。

背景

一般に、表が多いダイスボットのファイルは大きくなり、変更時に対象の処理を探しにくい。
対策として、v2.02.73以前のダイスボットについては、extratables ディレクトリを利用して、表のみ別ファイルにされている場合があった。
しかし、「起動時に必ずテーブルを読み出すから処理が重い」などと(処理時間測定なしの)苦情が来たため、v2.02.74(2017年8月)でダイスボット本体にマージせざるを得なくなった。
1ダイスボットにつき1つの(場合によっては巨大な)ファイルとなったことには、このような事情があった。

現在は、以下の理由のため、高速化を目的として無理に「1ダイスボットにつき1ファイル」とする必要性は薄れている。

  • 開発終了に伴い、どどんとふの個別サーバ設置が減っている → どどんとふの起動時間が問題となることが少ない。
  • 表のクラスが作られたため、Rubyのコードで(=追加の構文解析処理なしで)ある程度分かりやすく表を記述できる。
  • そもそも、処理時間測定なしでの苦情だったため、本当に別ファイルの表が原因で遅くなっていたのかが怪しい。

したがって、現在は、大きなダイスボットファイルの分割によって処理が探しやすくなる利点の方が、処理速度低下という欠点より大きいと思われる。

方針案

各項目ともに、採否は未決定。

  • 特殊処理が入るコマンドは今まで通りのファイルに書いて、extratables相当の処理を外だしできるテーブルだけ別ファイルに書く。(@ysakasin 案)
  • 長いテーブルとクラス内クラスを別ファイルに書く。その際、厳密に1個ずつ別ファイルでなくてもよい。各ファイル200〜300行以内を目標にする。(@ochaochaocha3 案)
  • 分割したファイルのパス:diceBot/ゲームシステム名/*.rb@ochaochaocha3 案)
    • 例:diceBot/LogHorizon/MGR.rb
  • テーブルをDSLで書けるようにする(@ysakasin 案)
    • prefixes への登録も自動的に行う。
    • 表がいくつかある程度の普通のダイスボットを、簡潔に書けるようにする。

要決定項目

  • 上の方針案のうち、どれを採用するか?
  • どのダイスボットを分割の対象とするか?
    • ファイル分割によって処理を探しやすくなる具体例がほしい。
  • どのくらいの行数をファイル分割の目安とするか?
    • あまり細かく分けすぎると、逆に処理を見つけにくくなる。

choiceコマンドの機能拡張

半角スペース終端を撤廃することでchoiceコマンドの記述自由度を高める?

空白許容

choice[The Call of Cthulhu, The Shadow Over Innsmouth, The Shadow Out of Time]
#=> "(省略) > The Shadow Out of Time"

空白区切り

choice The Call of Cthulhu
#=> "(省略) > Cthulhu"

n個とる

choice2[A,B,C,D]
#=> "(choice2[A,B,C,D]) > A, C

GUI版を起動できない(gemのwxruby-ruby19の利用不可)

2017年5月の時点では、比較的最近のものと思われる以下の環境のすべてにおいて開発時にGUI版を起動できなくなっています。

  • Windows 10 (x64)
  • macOS Sierra
  • Linux:Ubuntu 16.04

原因はgemのwxruby-ruby19がインストールできなくなっていることです。各環境における現象は以下のとおりです。

  • Windows(x64)・macOS:wxruby-ruby19の利用可能なバージョンが存在しない。
    • Windowsはx86版のみのため、x64環境では gem install 時に「x64版が見つからない」というエラーが出る。
  • Linux:libwxのバージョン違いによりインストールできない。gemが要求するのは2.8だが、最近のディストリビューションが提供するパッケージでは3.0になっている。
    • 一般に古いバージョンのパッケージは用意されない。
    • 例:wxwidgets2.8はUbuntu 15.04 Vivid Vervetまで。

したがって、現時点でGUI版を起動するbcdice.exeの生成ができるのは古くから開発環境を作っていた開発者のみとなっています。今後のことを考えると、開発環境の変化に伴いいずれGUI版は起動できなくなるものと思われます。

対策としては、CUI版をメインにし、GUIのフロントエンドを別のアプリとして(このリポジトリからも独立させて)作るのが良いと考えたのですが、いかがでしょうか? この場合、一般の利用者はBCDiceが同梱されたGUIフロントエンドをダウンロード・インストールすれば現在と同様に使えるという形が望ましいと思われます。CUI版をメインとする場合は、現在の引数解析のあたりを中心に挙動を修正することでGUI版と完全に分離するという方針で変更を進めていくことになりそうです。

メッセージの最大文字数制限の撤廃

IRCボット機能がなくなったため、メッセージの最大文字数制限($SEND_STR_MAX)は必要なくなった(※)。この設定項目を削除するとともに、各ダイスボットにおけるメッセージ短縮処理を削除する。

※ BCDice IRCでも、IRCボットライブラリが長いメッセージを自動的に分割するため、メッセージの長さを考慮する必要はない。

ダブルクロス 疾風怒涛式達成値ロールのC値と固定値の両方に四則演算を含めると不正な挙動

ダブルクロスの達成値ロールにて、C値を固定値の前に置く記法についてです。
固定値の四則演算は正しく機能します。例えば
10dx8+(5+5)
はC値8、固定値+10として認識されます。
また、C値の四則演算も正しく機能します。例えば
10dx(8-1)+5
はC値7、固定値+5として認識されます。
しかし、これらを同時に行おうとすると正しく機能しないようです。例えば
10dx(8-1)+(5+5)
はdx以降がすべてC値として認識され、C値17、固定値0として扱われるようです。
これはおそらく意図された動作ではないため、報告させて頂きます。
なお、CCFOLIAとSaipageの両方でこの動作を確認しました。
また、@の後にC値を記述する記法では正しく動作するようです。

終了コマンドを削除する

終了コマンド($quitCommand)をIRCボットに移動することで、 ボット終了処理 BCDice#quit を取り除く。BCDice IRCでは画面のボタンで安定して接続切断できるようになった(その後の再接続にも影響しない)ので、終了コマンドが不要になった。

git grep -n -i quit の結果

src/bcdice.rb:9:  def quit; end
src/bcdiceCore.rb:32:# 終了時はボットにTalkで「お疲れ様」と発言します。($quitCommandで変更出来ます。)
src/bcdiceCore.rb:72:    @quitFunction = nil
src/bcdiceCore.rb:76:  attr_accessor :quitFunction
src/bcdiceCore.rb:213:    when $quitCommand
src/bcdiceCore.rb:214:      quit
src/bcdiceCore.rb:230:  def quit
src/bcdiceCore.rb:231:    @ircClient.quit
src/bcdiceCore.rb:233:    if @parent.quitFunction.nil?
src/bcdiceCore.rb:237:      @parent.quitFunction.call()
src/bcdiceCore.rb:241:  def setQuitFuction(func)
src/bcdiceCore.rb:242:    @parent.quitFunction = func
src/bcdiceGui.rb:438:    @ircBot.setQuitFuction(proc { destroy })
src/bcdiceGui.rb:477:    @ircBot.quit
src/configBcDice.rb:16:$quitCommand = 'お疲れ様';           # 終了用のTalkコマンド
src/configBcDice.rb:17:$quitMessage = 'さようなら'; # 終了時のメッセージ
src/irc/ircBot.rb:227:  def quit
src/irc/ircBot.rb:228:    debug('quitCommand')
src/irc/ircBot.rb:233:    post(QUIT, encode($ircCode, $quitMessage))
src/irc/ircBot.rb:236:  def setQuitFuction(func)
src/irc/ircBot.rb:238:    bcdice.setQuitFuction(func)
src/irc/torgtaitaiIRC.rb:70:  def quitCommand(arg); end

AddDice: 加算ロールの項なしでも実行できるようになった

加算ロールの処理の変更に伴い、数字だけ、数値の四則演算だけでも実行できるようになりました。
これはこれで便利ですが(IRCボット OD TOOL for TRPGSW2_DLL」などで実装例あり)、意図していない動作だと思われます。
少なくとも、C コマンドと除算 / の端数処理が異なる(C では、ダイスボットごとに変化するが、加算ロールでは切り捨て固定)ことは、利用者側からは分かりにくい点です。

$ ruby cgiDiceBot.rb '42' DiceBot

DiceBot : (42) > 42 > 42
$ ruby cgiDiceBot.rb '1+2' DiceBot

DiceBot : (1+2) > 1+2 > 3
$ ruby cgiDiceBot.rb 'C(10/3)' Warhammer

Warhammer : 計算結果 > 4

$ ruby cgiDiceBot.rb '10/3' Warhammer

Warhammer : (10/3) > 10/3 > 3

BCDice@isMessagePrinted の削除

BCDiceクラスのインスタンス変数 @isMessagePrinted は、外部に公開されておらず、かつ処理に影響しない。そのため、安全に削除できる。

使われている箇所

  • bcdiceCore.rb:110:コンストラクタ、代入。
  • bcdiceCore.rb:626-628recievePublicMessageCatched()、チェックしているが分岐後の処理がコメントアウトされている。
    unless @isMessagePrinted # ダイスロール以外の発言では捨てダイス処理を
      # rand 100 if($isRollVoidDiceAtAnyRecive)
    end
  • bcdiceCore.rb:1309addToSecretDiceResult()、代入。
  • bcdiceCore.rb:1544sendMessage()、代入。
  • bcdiceCore.rb:1551sendMessageToOnlySender()、代入。
  • bcdiceCore.rb:1556sendMessageToChannels()、代入。

新クトゥルフのボーナス・ペナルティダイスで Tens d10 を区別したい

新クトゥルフでcc2cc-2などのダイスを振った際に、十の位のダイスが3個と1の位のダイスが1個振られる。この時dicesの内容がd10が3回振られた扱いになるため、ツールの表示上でどれが十の位と一の位のダイスが区別できなくなってしまう。この処理自体は妥当なものだが、何かしらの手段で区別できるようになると嬉しい。

スクリーンショット 2020-03-12 14 40 21

As-is

// result
{
  ...
  dices: [{faces: 10, value: 4}, {faces: 10, value: 2}, {faces: 10, value: 3}, {faces: 10, value: 6}]
  ...
}

互換性を考えるとオプションで制御できるようにすべき...?

四則演算:除算の結果が負となった場合の端数処理が正しくない

計算コマンド C(...) において、除算 / の結果が負となった場合の端数処理に問題があります。

環境

BCDice v2.02.80

症状

除算 / の結果が負となった場合、絶対値が大きくなる方向に結果が丸められます。BCDiceでは、演算子 / は端数を切り捨てる除算であるため、絶対値が小さくなる方向に結果が丸められなければならないはずです。なお、結果が正となった場合は問題ありません。

以下の図に、問題の発生例を示します。

bcdice_bug_div_rounding

図:どどんとふv1.49.04.01(BCDice v2.02.80が動作)における除算の実行結果

テストデータのTOML化

Ver2ではテストデータは独自フォーマットで記述されているが、bcdice-jsなどの他言語のプロジェクトから利用する観点から好ましくないので、普及しているファイルフォーマットで記述したい。

Ver3からはTOMLを作用する

ShinobiGami.toml

[[ShinobiGami]]
input = "s2d6"
output = "5"
secret = true
rands = [[1,6],[4,6]]

[[ShinobiGami]]
input = "2d6"
output = "5"
rands = [[1,6],[4,6]]

上記をJSONで表すと以下のようになる

{
  "ShinobiGami" : [
    {
      "input" : "s2d6",
      "output" : "5",
      "secret" : true,
      "rands" : [[1,6],[4,6]]
    },
    {
      "input" : "2d6",
      "output" : "5",
      "rands" : [[1,6],[4,6]]
    }
  ]
}

懸念点や検討された他の案

Ref.

計算処理の演算順序が不正

問題

C(1+2-3*4/5) の計算結果が期待と異なる値となる。

  • 現在の結果:0
  • 期待される結果:1

原因

以下のstring.scan(/[\+\-]?[^\+\-]+/)が原因で、正しい順序にならない。

$ irb
irb(main):001:0> "1+2-3*4/5".scan(/[\+\-]?[^\+\-]+/)
=> ["1", "+2", "-3*4/5"]

BCDice/src/bcdiceCore.rb

Lines 1622 to 1638 in 65e7dae

def split_plus_minus(string)
list = string.scan(/[\+\-]?[^\+\-]+/)
debug('split_plus_minus list', list)
result = []
list.length.times do |i|
unless result.empty?
if /(\*|\/)$/ === result.last
result[result.length - 1] += list[i]
next
end
end
result << list[i]
end

対策案

  • 構文解析をする(有望)
  • 正規表現でがんばる(困難)

Ref.

README の wiki への転載、分割

現在 README.txt が約 1,800 行と非常に長く、必要な情報を探すのが大変ではないかと感じました。そこで、

  1. README.txt の内容を Markdown 形式で書く。
  2. このリポジトリの wiki(右部)に分割してまとめ、参照しやすくする。バージョンアップ時にリポジトリに含まれるファイルと wiki の内容をできるだけ同期させる。

ということを提案したいと思います。いかがでしょうか。

ソードワールドシリーズのレーティング処理時の修正適用時に1ゾロでもダイス目修正を行ってしまう

報告

imgsurvivor今日 19:29
こんばんは。twitter側でも報告させていただきましたが、こちらでも改めてご報告させていただきます。
ソード・ワールド2.5の威力表ロールにおいてダイス修正値($+n)を付けてロールした際、
出目が[1,1]であっても自動的失敗扱いになりませんでした。


マスターコマンドをBCDice IRCに移す

関連: bcdice/bcdice-irc#30

BCDiceのボットにプライベートメッセージとして送る、マスターコマンド(set *)、mode(マスター用のモード確認コマンド)、helpc-help コマンドを削除して、BCDice IRCで再実装する。

マスターコマンドの一部や mode には BCDice#isMaster でマスターか確認する処理があるが、これもマスターコマンドと mode 以外では使っていないので、削除できる。

作業リスト

以下を削除する。

  • Set Master
  • Set Game
  • Set Viewmode
  • Set Upper
  • Set Reroll
  • Set Sort
  • Set CardPlace
  • Set ShortSpell(機能していないので完全に削除する)
  • Set Tap
  • Set CardSet(テストデータがなくテストできないので、一旦削除する)
  • Mode(移植時は #179 も考慮すること)
  • help
  • c-help(移植時は CardTrader#printCardHelp を使わないようにして、これも削除する)

以下を追加する。

  • BCDice#diceBot:ゲームシステム変更後に、BCDiceインスタンスから変更後のシステムを知る手段がないため。

マスターコマンド:modeを実行できない

マスターコマンド mode を実行できない。

原因

型の不一致。@diceBot.sendMode@diceBot.sortTypeInteger なので、文字列に足せない。

def checkMode()
  return unless isMaster()

  output = "GameType = " + @diceBot.id + ", ViewMode = " + @diceBot.sendMode + ", Sort = " + @diceBot.sortType
  sendMessageToOnlySender(output)
end

対策

文字列の式展開で書く。

def checkMode()
  return unless isMaster()

  items = [
    "GameType = #{@diceBot.id}",
    "ViewMode = #{@diceBot.sendMode}",
    "Sort = #{@diceBot.sortType}",
  ]

  sendMessageToOnlySender(items.join(', '))
end

ソード・ワールド:超越判定の特殊コマンド化

現在、ソード・ワールド2.0/2.5の超越判定(例:2D6@10)の振り足しはAddDiceの機能の一部として実装されている。これをソード・ワールド2.0/2.5の特殊コマンドに変えて、diceRollCommand で処理するようにしたい。

理由

ソード・ワールド2.0/2.5のためだけにAddDiceおよびDiceBotに特殊な処理が入ってしまっていること。これによって処理が追いにくくなっているため、AddDiceのリファクタリング時に関連するバグも生じた。具体的には以下が影響されている。

解決策

  • 2D6@c±m をソード・ワールド2.0の固有コマンドに変える。
    • 2.5では、2.0の継承によって自動的に使えるようになる。
    • ソード・ワールドでは2D6しか振らないため、ダイス数および面数はそれぞれ2、6に固定してよい。
    • 6を省略して 2D@c±m とする場合にも対応する。ダイスロールログにこの書式のコマンドもあった。
  • 加算ロールの文法から @c を取り除く。
    • dice/add_dice/parser.rb
    • dice/add_dice/node.rb
    • dice/add_dice/randomizer.rb
    • #175 のクリティカル値の統一書式の候補として @c が挙がっているが、これにはまた別issueで対応する。
  • DiceBot#check2dCritical を削除する。
    • diceBot/DiceBot.rb
    • diceBot/SwordWorld2_0.rb
  • DiceBot#is2dCritical を削除する。
    • diceBot/DiceBot.rb
    • diceBot/SwordWorld2_0.rb

BCDiceからガーデンオーダーが使えない

bcdice.rbやOnset!などからガーデンオーダーが使えません。
以下のコードをbcdiceCore.rbの2056行目に追加してテストしたところ、期待通りに動作しました。

when /(^|\s)(GardenOrder)$/i
  require 'diceBot/GardenOrder'
  diceBot = GardenOrder.new

上記のコードをそのまま使って下さっても構いませんし、別の方法でも問題ありませんが、なんらかの対応をお願いします

一部のシステムで目標値に?を使うと落ちる

問題点

目標値が定まらない判定のために加算ダイスでは 2D6>=? というような目標値に?を入力することを許している。

check_2D6 等を加算ダイスから呼び出すが、これを実装している多くのクラスで目標値に?がくることを想定しておらず、エラー落ちする。

報告者

くずもちさん

解決案

  • 地道に全てのcheck_2D6 を返す
  • 目標値の?を許容するか、システムごとにインスタンスメソッドに持っておいて、BCDiceクラスの方で cehck_2D6?を渡すか判別する

所感

辛い。加算ダイスで目標値に ? を許容したくないなぁ……

SwordWorld2.0の2d6でエラー

SwordWorld2.0のテストパターンに以下を追加で再現

============================
input:
2D6
output:
SwordWorld2.0 : (2d6) > 9[6,3] > 9
rand:6/6,3/6
============================

rakeの出力(抜粋)

ruby 2.7.1

[Failures]
Game type: SwordWorld2_0
Index: 13
Input:
  2D6
Expected:
  SwordWorld2.0 : (2d6) > 9[6,3] > 9
Result:
  SwordWorld2.0 error undefined method `<=' for nil:NilClass/BCDice/src/diceBot/SwordWorld2_0.rb:146:in `check2dCritical'
  /BCDice/src/dice/add_dice/randomizer.rb:39:in `roll'
  /BCDice/src/dice/add_dice/node.rb:302:in `eval'
  /BCDice/src/dice/AddDice.rb:27:in `rollDice'
  /BCDice/src/bcdiceCore.rb:773:in `checkAddRoll'
  /BCDice/src/bcdiceCore.rb:746:in `dice_command'
  /BCDice/src/bcdiceCore.rb:694:in `executeDiceRoll'
  /BCDice/src/bcdiceCore.rb:600:in `recievePublicMessageCatched'
  /BCDice/src/bcdiceCore.rb:569:in `recievePublicMessage'
  /BCDice/src/cgiDiceBot.rb:122:in `executeDiceBot'
  /BCDice/src/cgiDiceBot.rb:74:in `roll'
  /BCDice/src/test/DiceBotTest.rb:143:in `block in executeCommand'
  /BCDice/src/test/DiceBotTest.rb:142:in `each'
  /BCDice/src/test/DiceBotTest.rb:142:in `executeCommand'
  /BCDice/src/test/DiceBotTest.rb:111:in `block in doTests'
  /BCDice/src/test/DiceBotTest.rb:109:in `each'
  /BCDice/src/test/DiceBotTest.rb:109:in `doTests'
  /BCDice/src/test/DiceBotTest.rb:37:in `execute'
  /BCDice/src/test/testDiceBots.rb:6:in `<top (required)>'
  /ruby/2.7.1/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in `require'
  /ruby/2.7.1/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in `require'
  /ruby/2.7.1/lib/ruby/gems/2.7.0/gems/rake-13.0.1/lib/rake/rake_test_loader.rb:17:in `block in <main>'
  /ruby/2.7.1/lib/ruby/gems/2.7.0/gems/rake-13.0.1/lib/rake/rake_test_loader.rb:5:in `select'
  /ruby/2.7.1/lib/ruby/gems/2.7.0/gems/rake-13.0.1/lib/rake/rake_test_loader.rb:5:in `<main>'
Rands: 6/6, 3/6

その他

  • 2d6@10 のようにクリティカル値を設定すると正常に動きます。
  • ver 2.04.00では発生せず、ver2.05.00とmasterでは発生
  • 他のシステムをいくつか試してみた限りではSwordWorld2.0と2.50のみ発生

原因

check2dCriticalの地点でcriticalがnilになっているためエラーとなります。多分共通のパーサ処理を変更したときにクリティカル値未指定の処理が抜けたのではないでしょうか。

RerollDiceの未定義動作

RerollDiceに未定義動作およびREADMEの説明と反する挙動があるため修正が必要。

READMEでの説明

  ・個数振り足しロール (xRn)
   ダイスをバラバラにロールして、その成功数の個数分さらにロールして成功度を
   加算するロール(天羅万象など)にも対応しました。
   振り足し回数はゲーム設定で対応になっています。(デフォルトは無限)
   BのかわりにRを使うことで使用できます。
   条件式は必須で、ダイスの括弧内前処理も使えます。

説明にそぐわない例

2R3+3R6>=3 : (2R3+3R6[3]>=3) > 3,1,5,1,2 + 4,5 + 1,1 > 成功数4

振り直しがR3で振り直し条件を満たしても、R6で振り直される

2R6[3] : (2R6[3]) > 4,3 + 2,2 > 成功数0

[]を使うと振り直しが発生しても成功数にカウントされない

3R6+2R4<2 : (3R6+2R4[2]<2) > 3,5,4,1,1 + 2,2,4 + 2,1,2 + 3,1 + 4 + 1 > 成功数5

振り直し条件は必ず >= になってしまう

再定義

READMEの記述と直感的に期待される挙動から、仕様を再定義する。

  • ダイスの指定はnRxのようにし、+で複数繋げられる
  • ダイス指定の直後に成功条件式を >=6<2 のように記述する
  • 指定された条件式を用いて各ダイスの成否判定が行われる
  • 成功したダイスは振り直される
  • 成功した回数をカウントし、成功数とする
  • []をつかった2R3+4R5[6]のような式は2R3+4R5>=6 の糖衣構文とする
  • 式中の数値は、0以上のみ受け付ける

テーブルのクラス:インターフェースの統一

refs #132

テーブルのクラス(Table、D66Table、RangeTableなど)について、以下のようにインターフェースを統一したい。これにより、どのクラスを用いても処理を同様に書けるようになると期待できる。

  • #roll で、表を振った結果の文字列を返すようにする。
  • #roll_in_detail で、表を振った結果の詳細(出目の配列、取り出した項目など)を返すようにする。結果はできるだけ同じ名前のメンバを持つ構造体で返す。
  • (可能ならば)RangeTableのように、結果の文字列の整形処理を変更できるようにする。

複数ダイスを振って大きいもの/小さいものから任意個を取る処理がしたい

#87 とも関連するが、複数ダイスを振って大きいもの/小さいものから任意個を取るケースは多そう(MAGIUS、フォーリナー、D&D5th、etc)なので、個々のゲーム用に実装よりも標準にあるとよいのではないか。

ダイスコードの提案としてはnDx記法に、(K|D)(H|L)\d+を追記した場合、結果のダイスから大きいもの/小さいものを任意個を取るまたは除く(Keep Highest、Keep Lowest、Drop Highest、Drop Lowest)。

例)

  • 3d6KH2+3
    MAGIUSの技能あり判定、3つのD6から大きいもの二つを取り合計し、能力値を足す。

  • 4d6DL1
    D&D3版以降の能力値決定ダイス、4つのD6を振り、最小1個を取り除く。

  • 2d20KL1+1d4+4
    2つのD20の小さい方から1つ取り、1d4+4を足す。D&Dthの不利の判定にブレスがかかり、ボーナスが+4の場合。

Unable to join channels

"start!"
D, [2016-03-30T15:48:02.400845 #5836] DEBUG -- : start begin
D, [2016-03-30T15:48:02.434478 #5836] DEBUG -- : on_connected calling..
D, [2016-03-30T15:48:02.435473 #5836] DEBUG -- : call...
-> IRC server is connected.
login to channels(#test), so wait a moment...
D, [2016-03-30T15:48:02.436475 #5836] DEBUG -- : on_connected passed
D, [2016-03-30T15:48:02.436475 #5836] DEBUG -- : post PASS
D, [2016-03-30T15:48:02.436475 #5836] DEBUG -- : post NICK
D, [2016-03-30T15:48:02.436475 #5836] DEBUG -- : SEND: NICK bcDICE
D, [2016-03-30T15:48:02.437476 #5836] DEBUG -- : post USER
D, [2016-03-30T15:48:02.437476 #5836] DEBUG -- : SEND: USER v2.02.29 0 * rubydice
D, [2016-03-30T15:48:02.437476 #5836] DEBUG -- : while loop begin
D, [2016-03-30T15:48:02.507467 #5836] DEBUG -- : RECEIVE: :ircfire.linuxfire.com.cn NOTICE AUTH :* Looking up your hostname...
D, [2016-03-30T15:48:02.507467 #5836] DEBUG -- : calling... on_xxx : on_notice
D, [2016-03-30T15:48:02.508464 #5836] DEBUG -- : RECEIVE: :ircfire.linuxfire.com.cn NOTICE AUTH :
* Couldn't resolve your hostname; using your IP address instead
D, [2016-03-30T15:48:02.508464 #5836] DEBUG -- : calling... on_xxx : on_notice
D, [2016-03-30T15:48:02.508464 #5836] DEBUG -- : RECEIVE: PING :5FEBC0B3
D, [2016-03-30T15:48:02.509467 #5836] DEBUG -- : calling... on_xxx : on_ping
D, [2016-03-30T15:48:02.509467 #5836] DEBUG -- : SEND: PONG :
D, [2016-03-30T15:48:02.616520 #5836] DEBUG -- : RECEIVE: :5FEBC0B3![email protected] PRIVMSG bcDICE :�VERSION�
D, [2016-03-30T15:48:02.618524 #5836] DEBUG -- : calling... on_xxx : on_privmsg
D, [2016-03-30T15:48:36.416696 #5836] DEBUG -- : RECEIVE: ERROR :Closing Link: bcDICE[My ip address](Ping timeout: 34 seconds)
D, [2016-03-30T15:48:36.416696 #5836] DEBUG -- : calling... on_xxx : on_error

I am using your dicebot on a unrealircd IRC and it seems to be unable to join the channel,can you tell me how to solve the problem?
PS:This IRC uses UTF-8

新クトゥルフのCCコマンドが先頭一致で振れる

CCコマンドの直後に関係のない文字を(スペースを開けずに)記入してもロールできてしまう。

v3のREPLで確認。

[Cthulhu7th]> CCなにか
1D100 > 63
[Cthulhu7th]> CC1<=50なにか
(1D100<=50) ボーナス・ペナルティダイス[1] > 75, 35 > 35 > レギュラー成功

カード機能をBCDice IRCに移す

関連:bcdice/bcdice-irc#34

CardTraderをBCDice IRCに移す。

CardTraderはBCDice本体からはクラスとして分離されているので、作業はしやすい。基本的にはCardTraderのファイルの移動と関連コマンドの削除で大丈夫なはず。

ダイスボットのうちカオスフレアとバルナ・クロニカは、トランプのデッキの準備を DiceBot#postSet で行っているので、そこを削除する。デッキの準備以外のCardTrader依存部分はなかったので、この修正だけでよい。

システム別ドキュメント構造化の提案

各ゲームシステムに紐づくドキュメントは
現在、GameSystem派生の各クラスの下に、プレーンテキストの形で記述されています。
(ただし標準ダイスボットを除く)

これをJSON等で構造化することで
公式ドキュメント作成やオンセツール側での様々な活用が可能になると考えます。

現状のHELP_MESSAGEを見て検討したところ、以下のような構造であればうまく整理できそうです。


  • gameSystem {object} - ゲームシステムのメタデータ。
    • id {string} - ゲームシステム識別子。クラス内にデータを置く場合は定数 ID から自動取得。
    • name {string} - ゲームシステム名。定数 NAME から自動取得。
    • sortKey {string} - ゲームシステム名の読み方。定数 SORT_KEY から自動取得。
  • functions {object[]} - 個々の機能。
    • type {string} - 機能の分類。"dice" "table" "misc" のいずれか1つ。
    • name {string} - 機能名称。ドキュメントでは小見出しになる想定。
    • description {string} - 当該機能の概要。
    • formats {string[]} - 機能呼び出しフォーマット。"nDm" "*T" "Foo{目標値}" など形式は制限しない。
    • vars {object[]} - 機能呼び出しフォーマットの文中にある変数。
      • name {string} - 変数名。
      • description {string} - 変数の概要。
      • detail {string} - 変数の詳細説明。取りうる値など。
    • notices {string[]} - 機能の注釈。を使用する上で注意事項などがあれば。
    • examples {object[]} - 機能の使用例。
      • request {string} - リクエスト文字列の例。
      • response {string} - レスポンス文字列の例。
  • enabledD66 {boolean} - D66ダイスの可否。変数 @enabled_d66 から自動取得。

自動取得とあるものは、ソースコードから取得ないし実行時に動的取得が望ましい要素です。
逆に、JSON側データを主として、クラス内でこれを読み取るという形も考えられます。

とりあえずの懸念点は

  • とにかく作業量が多い
  • オンセツール側にも作業が発生する(従来に近いプレーンテキストを出力しても良い)
  • データを別ファイルにする場合は管理の手間が増える
  • データをクラス内に置く場合はRuby以外からの利用がしにくくなる

camelCaseとsnake_caseの混在

問題点

Rubyの慣習ではメソッド/変数名にはsnake_caseを用いることになっている。しかし、現状のコードでは、camelCaseとsnake_caseが混在し、大変見辛いことになっている。

Rubyの慣習に全て合わせるのが最もメンテナンス性が上がるが、主要なメソッドの大部分がcamelCaseで命名されているため、全て変更するわけにもいけない。そこで、議論して折衷案的な命名の統一ルールを設けたい

個人的な考え

確定

  • メソッド名を変更するのは無理なので、camelCaseを維持する
    • 公開されている部分は camelCase にする
  • ローカル変数はRubyに合わせて 全て snake_caseにした方が良い

🤔

  • privateなメソッドはどうするか?
    • publicメソッドとの整合性のために camelCaseにする
    • privateなのだからローカル変数と同様に snake_caseにする

要調査

  • atterは現状どうなっている?
  • 実際はcamelCaseとsnake_caseどっちが多い?

メタリックガーディアン:ダイスボット改修案

従来機能ではクリティカル、ファンブルの変動に対応するためには
2d6+m>=t[c,f]と目標値を必ず設定する必要があったが
目標値の存在しない判定(対決を行う場合の能動側)が存在するため
使いにくかった。

ここで以下の機能を実装。

MG+m[c,f]が与えられた場合、目標値なしの判定を行うことができる。
MG=2d6であるが、この時にクリティカル値cを出目が上回った場合に自動成功、

ファンブル値fを出目が下回った場合に自動失敗を自動で検知する。
デフォルトは従来通りc=12,f=2とする。

by @RKcolonel

Ref. #113

マスターコマンド:ソード・ワールドのレーティング表を設定できない

IRCボットから実行できるマスターコマンドのうち、ソード・ワールドのレーティング表の設定が不可能になっています。

原因

diceBot/DiceBot.rb では、レーティング表を設定するメソッドは以下のように定義されています。

# SW専用
def setRatingTable(_nick_e, _tnick, _channel_to_list)
  '1'
end

一方で、bcdiceCore.rbでは、これを以下のように呼び出しています。引数が3個必要なメソッドを引数1個で呼び出そうとするため、ArgumentErrorが発生します。

def setRatingTable()
  return unless isMaster()

  output = @diceBot.setRatingTable(@tnick)
  return if output == '1'

  sendMessageToChannels(output)
end

なお、DiceBot.rbの当該メソッドでは #SW専用 とコメントされていますが、オーバーライドしているdiceBot/SwordWorld.rbでも引数が一致していません😢

# tnickはレーティング表のモードを表す数字("0", "1", "2")
def setRatingTable(tnick)
  # ...
end

対策案

もともと動いていなかったうえ、現在はダイスボットの指定(SwordWorldSwordWorld2_0SwordWorld2_5)でレーティング表を変更できるため、マスターコマンドから set ratingtable を削除し、関連する処理も削除するのが望ましいです。

メッセージ送信処理を別クラスに分離する

メッセージ送信処理について、BCDiceクラスがハブになっており(BCDice#sendMessage など。CardTraderもそれらを使用する)、手を加えにくい。
また、BCDice#sendMessageToOnlySender にはIRCのニックネーム(@nick_e)を含める処理が含まれており、このメソッドはIRCに依存する。
さらに、これらの委譲先は @ircClient であり、IRCボットの分離後は不適切な名前である。

そこで、BCDice#sendMessageを中心とするメッセージ送信処理を担当するオブジェクトを @ircClient 以外に改名して、BCDiceおよびCardTraderの各クラスに所持させる。
また、最終的に @nick_e をBCDiceから取り除き、IRCボットに移動する。

インターフェース案

インターフェース名を「MessageSink」 とする。
各クラスは、メッセージ生成時に message_sink という引数でこのインターフェースを持つオブジェクトを渡し、使う(インスタンス変数にしない)。
MessageSinkは、受信したメッセージごとに割り当てられ、以下の情報を持つものとする。

  • room [String](部屋):メッセージを受信した部屋。IRCのチャンネルなど。
  • sender [String](送信者):誰からのメッセージを受信したか。
  • bot [Object](ボット):IRCボット、CgiDiceBotなど。全部屋にメッセージを送信できるように、broadcast(message) メソッドを持つ。

MessageSinkインターフェースを持つオブジェクトは、以下に示すメソッドを持つ。

# @return [String] メッセージを受信した部屋。
attr_reader :room

# @return [String] 送信者。
attr_reader :sender

# 部屋にメッセージを送信する
# @param [String] message 送信するメッセージ
# @return [void]
def to_room(message); end
 
# 送信者にメッセージを返信する
# @param [String] message 送信するメッセージ
# @return [void]
def to_sender(message); end

# 全部屋にメッセージを送信する
# @param [String] message 送信するメッセージ
# @return [void]
def broadcast(message)
  @bot.broadcast(message)
end

BCDice@nick_e の除去について

BCDiceやCardTraderで sendMessage 系を使用している部分については、上記のMessageSinkで sender にニックネームを設定することで、@nick_e を除去できる。

一方で、各システムのダイスボットにも @nick_e を使用している部分 dice_command_xRn(string, nick_e) がある。
これについては、出力がすべて "#{nick_e}: (#{string}) > #{output}" の形になることから、dice_command_xRn(string) と定義を変えて、nick_e の付加を(結果が空でない場合に)BCDice側で行うのが良い。
最近の新規ダイスボット(改版分を除く)ではdice_command_xRn が導入されることはまずないので、このメソッドのインターフェースを変更することは問題ない(変更したことを周知するのみでよい)と思われる。

エンドユーザーマニュアル

BCDiceがどどんとふから離れたことで、choiseなどの基本コマンドのヘルプメッセージがエンドユーザーに対して届かなくなっているため、エンドユーザーマニュアルを作る必要性が高い。

作るのは確定として、どの媒体を用いるかという問題がある。
思いつく限りの候補は以下。

  • bcdice.org の小ページ
  • gitbook
  • リポジトリの /docs/ にMarkdownファイル直置き
  • リポジトリのWiki
  • 何かしらのWikiサービス

作ったドキュメントを読む人

エンドユーザー:ココフォリアやユドナリウムなど、オンセツール上でBCDiceのコマンドを使う人々

ドキュメントをメンテナンスする人

BCDiceコミッタ:必須
有志:オプション

考えたいこと

どのサービスを使うのがいいか。各サービスの利点と欠点

BCDice: ロール結果のインスタンス変数の未初期化

/src/test/test_d66_table.rb に実装されているテストの実行時に、ロール結果のインスタンス変数の未初期化が原因の警告が出ます。

/src/bcdiceCore.rb:1018: warning: instance variable @rand_results not initialized
/src/bcdiceCore.rb:1074: warning: instance variable @detailed_rand_results not initialized

このテストのように、コマンドを呼ぶ前に BCDice#setCollectRandResult を呼ぶのは忘れやすいです。例えば、BCDiceクラスのコンストラクタで setCollectRandResult(true) を呼ぶのが対策となります。

コマンドの複数回実行

#276 で考えられているように半角スペースの末尾処理をしないなら、どどんとふでいう 5 2D6 の機能を実現しても良い気がする

repeat5 2D6
rep5 2D6

リポジトリのデータサイズが大きい

過去のコミットにバイナリファイル bcdice.exe が含まれるため、リポジトリサイズが400MBほどになっている。Cloneやsubmoduleの解決時に毎回このサイズのダウンロードが行われるのは困るので、ダイエットさせたい。

コミットログを改変し、 bcdice.exe を除去することでリポジトリダイエットする。コミットログの改変をすると、コミットハッシュが変わるため、BCDiceをsubmoduleにリポジトリに考慮してVer3で入れ替える。

スケジュール

2020年9月

  • Ver2の主だった開発凍結
  • Ver2を v2 ブランチに
  • master ブランチで bcdice.exe を削除する過去改変
  • 改変した master ブランチでVer3開発

2021年M月

  • Ver3リリース
  • v2 ブランチ削除
  • ブランチ削除に伴い、 bcdice.exe のobjectは消滅

※ Ver3まで今までのコミットハッシュを残しておく
※ Ver3のリリースと同時に改変前のコミットを削除し、リポジトリサイズを削減する

ダイスボットのIDの変更

以下の理由のため、一部のゲームシステムについてIDを変更したい。

  • 一部のゲームシステムのIDに空白や記号が入っているため、BCDiceを使用するツール側で特別な配慮が必要になり、扱いにくい。
    例:
  • スペルミスが散見される。
    • MetallicGuadian(正:MetallicGua r dian)など。

変更により、IDを正規表現 /^[A-Z][\w.]*$/ で表せるようにしたい。

  • . を許容するのは、SwordWorld2.0 にマッチするようにするため。

先日のモノトーンミュージアムのID修正(#144)で問題が報告されていないため、他のゲームシステムについても行えるはず。

シャドウラン第5版 グリッチ判定の誤り

Discordに以下の報告があった

お願い:シャドウラン第5版のダイスボットの改修をお願いしたいです。
理由:シャドウラン第5版からグリッチの判定が変わっているため。
理由(詳細):シャドウラン第4版から第5版で、グリッチの判定が以下に変わっています。
シャドウラン第4版:振ったダイスの半分以上の出目が"1"の場合、グリッチ。
シャドウラン第5版:振ったダイスの半分を超える出目が"1"の場合、グリッチ。
(ダイスが奇数の場合は、半数の算出は切り捨て。(例:ダイス3個だと、"1"が2個でグリッチ)
改修:
・グリッチ処理は、BCDice/src/diceBot/ShadowRun4.rb 43行目に記載。
(シャドウラン5版用は、クラスを継承して処理利用)
unless numberSpot1 >= dice_cnt_total_half

unless numberSpot1 > dice_cnt_total_half
・BCDice/src/diceBot/ShadowRun5.rbは、ShadowRun4.rbを継承しているので、
ShadowRun5.rbに# シャドウラン5版用グリッチ判定として、
def getGrichText(numberSpot1, dice_cnt_total, successCount)
を新規に記述する?(私にRuby知識が無い為に想像)
・補足:上記の改修が合っていれば、自分で改修を書いてみて
提案チャレンジしてみたいですが。。。(GitHubアカウント作る所からですが)

シャドウラン第4版:「nS6」が使い方に記載されていない

シャドウラン第4版のダイスボットでは、以下の changeText により、「nS6」でバラバラロールができるようになっています。

  def changeText(string)
    if string =~ /(\d+)S6/i
      string = string.gsub(/(\d+)S6/i) { "#{Regexp.last_match(1)}B6" }
    end

    return string
  end

しかし、以下に示すように、使い方の説明文には記載されていませんでした。

個数振り足しロール(xRn)の境界値を6にセット、バラバラロール(xBn)の目標値を5以上にセットします。
BコマンドとRコマンド時に、グリッチの表示を行います。

説明文に「nS6」を追加すべきでしょうか? それとも、「nS6」を削除すべきでしょうか?

prefixesの挙動が名前と解離している

ゲームシステム固有のコマンドを使えるようにするためにDiceBot.setPrefixesを用いるが、接頭辞として見るのではなく文字列全体がマッチするかチェックしている。

# 接頭辞(反応するコマンド)を設定する
# @param [Array<String>] prefixes 接頭辞のパターンの配列
# @return [self]
def setPrefixes(prefixes)
@prefixes = prefixes.
# 最適化が効くように内容の文字列を変更不可にする
map(&:freeze).
# 配列全体を変更不可にする
freeze
@prefixesPattern = /(^|\s)(S)?(#{prefixes.join('|')})(\s|$)/i.freeze
self
end

そのため、CC<=10というコマンドを作りたい場合 setPrefixes("CC") だと認識しない。setPrefixes("CC.*")setPrefixes("CC<=\d+")のようにする必要がある。

これは名前に実態が促しているとは言えないので、修正する必要がある。上記例でsetPrefixes("CC") が認識されるように挙動を変更することで対応する。

i18n

現状

ソースコード上の文字列リテラルをそのまま置き換えて別ファイルにすることで対応

問題点

元の日本語ファイルにロジックのミス等があった時に、多言語対応したファイルに反映させるのが困難

特定システム用の処理を行った後、標準ダイスに処理を委譲したい

例えばD&D5thの判定では、有利/不利が付き(D20を2つ振り、有利なら大きい方、不利なら小さい方を取る)、さらにそれに呪文の効果などで任意のダイスを増減する(ブレスの効果で+1d4など)。

D&D5thの有利/不利をDAx、DDx(xは数値)等と実装して、D20を複数振って大きい/小さい方を取ったのち、後の処理(任意のダイスの結果を増減、プラス、マイナス修正)を標準ダイスボットに委譲するようなことがしたい。

例 DA2+1d4+3 D20を2つ振って大きい方を取り、その値に1d4の結果と3を足す

一部のシステムで「2d>=」のように目標値無しにすると落ちる

現象

特定システムで 2d>= のように目標値無しのコマンドで例外が発生する。

============================
input:
2d6>= 目標値無し
output:
Insane : (2D6>=) > 7[3,4] > 7 > 失敗
rand:3/6,4/6
============================
上記テストケースの結果
[Failures]
Game type: Insane
Index: 61
Exception: comparison of Integer with String failed
Backtrace:
  C:/Users/blhsr/workspace/BCDice/lib/bcdice/game_system/Insane.rb:72:in `>='
  C:/Users/blhsr/workspace/BCDice/lib/bcdice/game_system/Insane.rb:72:in `check_2D6'
  C:/Users/blhsr/workspace/BCDice/lib/bcdice/base.rb:306:in `check_result'
  C:/Users/blhsr/workspace/BCDice/lib/bcdice/common_command/add_dice.rb:49:in `eval'
  C:/Users/blhsr/workspace/BCDice/lib/bcdice/common_command.rb:16:in `block in eval'
  C:/Users/blhsr/workspace/BCDice/lib/bcdice/common_command.rb:14:in `each'
  C:/Users/blhsr/workspace/BCDice/lib/bcdice/common_command.rb:14:in `eval'
  C:/Users/blhsr/workspace/BCDice/lib/bcdice/base.rb:140:in `eval'
  C:/Users/blhsr/workspace/BCDice/test/DiceBotTest.rb:124:in `block in executeCommand'
  C:/Users/blhsr/workspace/BCDice/test/DiceBotTest.rb:123:in `each'
  C:/Users/blhsr/workspace/BCDice/test/DiceBotTest.rb:123:in `executeCommand'
  C:/Users/blhsr/workspace/BCDice/test/DiceBotTest.rb:90:in `block in doTests'
  C:/Users/blhsr/workspace/BCDice/test/DiceBotTest.rb:88:in `each'
  C:/Users/blhsr/workspace/BCDice/test/DiceBotTest.rb:88:in `doTests'
  C:/Users/blhsr/workspace/BCDice/test/DiceBotTest.rb:29:in `execute'
  C:/Users/blhsr/workspace/BCDice/test/testDiceBots.rb:2:in `<top (required)>'
  C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/rake-13.0.1/lib/rake/rake_test_loader.rb:17:in `require'
  C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/rake-13.0.1/lib/rake/rake_test_loader.rb:17:in `block in <main>'
  C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/rake-13.0.1/lib/rake/rake_test_loader.rb:5:in `select'
  C:/Ruby26-x64/lib/ruby/gems/2.6.0/gems/rake-13.0.1/lib/rake/rake_test_loader.rb:5:in `<main>'
Input:
  2d6>= 目標値無し
Expected:
  Insane : (2D6>=) > 7[3,4] > 7 > 失敗
Rands: 3/6, 4/6
SimpleCov failed with exit 1rake aborted!
Command failed with status (1)
ココフォリアでの表示

image

ユドナリウムでの表示

image

原因

インセインなどの特定システムだけ発生するので、 check_nDx 系メソッドを
実装しているシステムだけ発生するんだと思います。
インセインでは total >= target の箇所で例外が発生しています。

# ゲーム別成功度判定(2D6)
def check_2D6(total, dice_total, _dice_list, cmp_op, target)
return '' unless cmp_op == :>=
if dice_total <= 2
" > ファンブル(判定失敗。山札から【狂気】を1枚獲得)"
elsif dice_total >= 12
" > スペシャル(判定成功。【生命力】1点か【正気度】1点回復)"
elsif target == "?"
""
elsif total >= target
" > 成功"
else
" > 失敗"
end
end

関連issue) #243

目標値を"?"と比較している箇所で、機械的に""(空文字)とも比較するようにすれば
スタックトレースを抑制することができると思います。
もしくは不完全なコマンドを check_nDx 系メソッドに流さないようにするか

クリティカル値やファンブル値を変動させる汎用書式

シノビガミやインセインをプレイしていてふと思ったのですが、2d6で2や12を出した時以外でもファンブル、スペシャルの表示をさせることって可能なのでしょうか?
ファンブル値やスペシャル値がよく増減するので、反映できれば視認性は上がるなあって思ったのですが。
可能だとして操作が増えるのでやはり厳しいですかね。

加算ロールを負の数で割ることができない

加算ロール nDx を負の数で割ることができません。これは構文解析上の問題のようです。

環境

コミットID 2b3d853

症状

加算ロールに対して乗数が負数の乗算、除数が負数の除算を行おうとした場合(例:2d6*(-1)2d6/(-1))、*/ が無視され、減算として処理されます。

@blhsrwznrghfzpr (trpg_yoshi)さんが確認した例:

bcdice_sum_roll_mul_div

テストケースを追加した例:

bcdice_testcase

原因

以下、除算で問題が発生する原因のみ示します。

原因は、AddDice#rollDiceAddingUp で負の乗数や除数が無視されることです。

BCDice/src/dice/AddDice.rb

Lines 160 to 164 in f8881ea

if( /([\d]+)D([\d]+)(@(\d+))?(\/\d+[UR]?)?/i =~ mul_line )
dice_count = $1.to_i
dice_max = $2.to_i
critical = $4.to_i
slashMark = $5

負の乗数や除数が正規表現にマッチしないため、slashMarknil になります。

dice_now = getSlashedDice(slashMark, dice_now)

ここで、getSlashedDice の第1引数に nil が渡されます。

BCDice/src/dice/AddDice.rb

Lines 289 to 291 in f8881ea

def getSlashedDice(slashMark, dice)
return dice unless( /^\/(\d+)(.)?$/i === slashMark )

/^\/(\d+)(.)?$/i === nilfalse となるため、除算が行われません。

シノビガミ 行為判定のダイスにファンブル値の指定を追加したい

ソースを読んだところ、2D6の合計が2以下であればファンブルとなっています
ところが、ご存じの通りシノビガミの戦闘中のファンブル値は可変です
キルデスビジネスはファンブル値の指定ができているので、シノビガミでもそのようなコマンドを追加して頂けないでしょうか?

今は大幅改変の時期と聞いています。
大変な時期かとは思いますが、もしよろしければご対応お願いいたします

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.