概要
pythonからOpenCVのテンプレートマッチ及びGUI操作モジュールを使うことで、
webブラウザ上の麻雀牌をBOTに認識・クリック操作させることができ、プレイの自動化ができました。
また、どの麻雀牌をクリックするかのロジック部分には機械学習を用いました。
テンプレートマッチの探索用画像を差し替えれば雀魂に限らず他の麻雀ゲーム全般で利用可能であり、機械学習の部分を変えれば、特定条件下で合理的選択を繰り返し求められるようなゲーム全般で応用が可能です。
※内容理解の一助とするために記事内随所に雀魂のゲーム内画像を利用していますが、著作権保護等の観点から強いボカシを入れています。
対象読者
(麻雀が好きで)機械学習を触ってみたい人
WindowsやGUI操作の自動化に興味があるけどOpenCVって何だろうって人
雀魂は好きだけど試練イベント走るのがマジ試練すぎて心が折れた人
過去に大学で画像処理系の研究室にいた私の書く暇つぶしスクリプトに興味がある人
私の不純なモチベーション
先日、雀魂にハマりました。最近、飽きました。
デイリーで何局か対戦したり、イベントに参加するとガチャ報酬までたどり着けるようになっているので、ゲームのプレイは続けて可愛い娘をピックアップしたい
でもルールを知ってるかすら怪しいネットの知らん人と、これ以上作業のような麻雀に付き合えない。
(特にイベントは実力に関係なく他プレイヤーとマッチングするし、プレイ後の順位と報酬が一致しないので真面目にプレイするのが辛すぎる)
かといって簡単なツモ切りBOTを動かしただけでは、離席判定をされてしまって最悪アカウントがBANされます。(これには驚いた。やるな運営。)
ということで、
- マウスのクリック操作をシミュレートすることによってブラウザ操作する
- 牌を選んで捨てる&アガリができる
BOTを作ろうとなった次第です。
構成要素
手牌+ツモ牌情報の取得
概要
OpenCVのテンプレートマッチングと呼ばれる仕組みを使いました。
OpenCV(Open Source Computer Vision Library)...インテルが開発・公開したオープンソースのコンピュータビジョン向けライブラリ。コンピューターで画像や動画を処理するのに必要となるさまざま機能がこれ1つで実現できる夢のようなライブラリ。
テンプレートマッチング(Template matching)...入力画像中からテンプレート画像(部分画像)と最も類似する箇所を探索する夢のような処理。
C#でWindowsアプリケーションとして作ってもよかったのですが、そんなに労力をかけるくらいなら雀魂に直接課金した方が早いので今回はOpenCVにさくっとアクセスできるpythonを採用しました。
pythonをインストールした後
$ pip install opencv-python
だけでOpenCVが使えるようになります。昔はチュートリアルするのも一苦労だったのに…
環境構築はここを参考にするとよいかと思います
pipでOpenCVのインストール
https://qiita.com/fiftystorm36/items/1a285b5fbf99f8ac82eb
全パターン牌画像をあらかじめ用意しておいて、実際のプレイ画面のキャプチャから13牌を切り出し、それぞれ一致する牌画像を探すことで牌情報を取得させます。
画面キャプチャの注意
ブラウザサイズ=アプリ画面サイズとならないことに注意してください。
雀魂はブラウザをみょんみょん変形させるとわかりますが、どの解像度でも縦横比が一致するように作られたwebアプリケーションです。1
つまり、ブラウザ変形してゲーム本来の縦横比と一致しない描画エリアは漆黒地帯として表示されます。
ここでテンプレートマッチはサイズ伸縮した検出対象に弱いので、処理の最初に画面(キャプチャ)サイズを取得したうえで、用意しておいた牌テンプレート画像のサイズに合わせるように調整処理を入れるのが大切です。
(毎回決まったディスプレイ環境+ブラウザサイズでゲームをプレイするということであれば、毎回キャプチャ画像とテンプレート画像のサイズが一致するのでこの処理は不要です)
※ブラウザのキャプチャをとるpython用モジュールも多種配布されてますが、私の手法では単純に全画面キャプチャを撮ったのち、アプリ画面の端あたりをテンプレートマッチングによって位置検出することで純粋なアプリ画面の切り出しをすることにしました。
縮尺の計算時に誤差が少なくなるよう、なるべく遠い2点に位置する画像要素をテンプレート用画像として事前に抽出します。
局面によって変化せず、画面上に類似する特徴量をもたない(≒識別しやすい特徴的な)画像を選ぶとよいでしょう。
また、このときテンプレート画像はサイズ種類のものを3-5種類ほど用意して(あるいは処理中に縮尺変形させて)最も一致度が高くなるテンプレート画像とその尺度を採用するなどの処理が必要です。2(テンプレートとして用意する画像と、実際のキャプチャ画像のサイズが異なった結果、画面領域の検出に失敗すると処理全体が不安定になるため)
テンプレート画像として抽出した画像のサイズとその時点の2点間距離をあらかじめ計ってデータとして持たせておくことで、ディスプレイ環境が変わっても手牌が並ぶ場所の相対位置を求めることができるようになります。
テンプレートのどちらかを基準に手牌を1つずつ切り出し(cv2.crop)すると下記のように画像が抽出できました。
(テンプレート元となる手牌画像データを手作業で収集したせいか、すこしガタつきがあります。認識精度に大きな影響がでなかったのでよしとしました)
ドラ牌は常にピカピカ光っている画面上の演出があるのですが、画像処理的にはすごーーーく嫌な予感がしますね(笑)
手牌の認識
さて、牌そのものを認識するためには、さらに抽出した牌画像それぞれを下記のような「牌一覧画像」からテンプレートマッチさせます。
(※入力した九萬画像が牌一覧画像の一部にテンプレートマッチしている様子)
横1列にずらーっと牌を並べたデータを作っておいて、検出した画像のx座標によって牌の正体が分かるという具合です。
(この全麻雀牌横並びデータを作るのが一苦労でした…)
処理は問題なさそうですが、ここまでで2.7秒かかってしまっている。。。
雀魂は持ち時間が5秒なので、1処理あたりにかけられる時間は5秒まで。
もうちょっと言えば、ループ処理の始まり=ツモした瞬間というわけにはいかない訳ですから、少なくとも2.5秒間隔の監視ループ(手番スタート→処理開始(Max2.5s経過後)→処理完了(2.5s)→手番終了)とする必要があるので、あかん感じですね(;'∀')機械学習部分も処理時間かかるのに…ま、後からリファクタリングしましょ!3
「何切る」問題
概要と先行事例
13手牌とツモ牌を入力することで、捨てるべき牌を出力するプログラムを探しました。ないですね。
というか麻雀ゲーム+AI界隈はまさにこのあたりについてしのぎを削っている最中でした。ごめん諸先輩。
さらに私の目的は「ぼくのかんがえた最強のまーじゃんAI」ではなく、雀魂運営がロボットと断定できない程度にぬらぬらプレイし続けるBOTということなので、この辺は適当につくります。
かの有名なgithubという名のアマゾンに「mahjong」キーワードで分け入ってみましたところ
HTML5 + JavaScript で動作する麻雀アプリ「電脳麻将」より「何切る」判定部分
https://github.com/kobalab/Majiang
[動作デモ]http://kobalab.net/majiang/dapai.html
これはかなりよさそうに見えました。
著者はご自身のブログで「何切る」判定ロジックに係る四苦八苦をログとして残されているので、最強AIを目指す方にはかなり参考になると思います。
とはいえこれjavascriptなのでpythonからデータ入出力の接続をするのが若干面倒。。。
pythonでそのまま使えるのはないかな~と探していたら、ありました。
機械学習の採用
ディープラーニングによる麻雀の何切るAI
https://github.com/hogeki/dlmahjong
これは機械学習に触れたことがない方にはreadmeだけだと、少しとっつきにくいので下記にgit cloneした後、動作するまでの手順を記します。
まずTensorFlow4をpipで導入しますが、ここではバージョンはきっちり合わせた方が幸せになれるでしょう。マジで。人柱の話は聞いといた方がいいです(真顔)
pip install tensorflow==1.7.0 (2020.8.5現在の当該gitレポジトリの内容に従う)
ありがたいことに天鳳の牌譜データ(.txt)もついているので、そのまま学習してパラメータとして保存できます。
python mahjong_ai.py --train --save
これで学習結果のパラメータが外部データ(学習モデル/学習済みモデル)として保存されるはずです。
今後はこのモデルを引数として使うことで何切る判定処理ができるようになります。
該当gitのスクリプトでは「13+1の牌データを情報として渡して、何を切るべきか教えてくれる」という機能は実装されていないので(あくまで後述する連続したテストとその性能評価しかない)その部分は自作する必要があります。コードは下記の通りです。
引数として手牌+ツモ牌の情報を天鳳仕様の文字列で入力すれば、何を切るべきか教えてくれる仕様となりました。(前述の学習モデルはデフォルト引数となっています)
実装スクリプト
#calc_dahai関数は外部ファイルから呼び出すことを想定しているので
#付随するファイルをmahjong_ai.pyに付随するファイルをimportで参照
import mahjong_common as mjc
import mahjong_loader as mjl
#機能追加に伴うimportの追加
import unicodedata
import re
def init_sess():
#calc_dahai関数は外部ファイルから呼び出すことを想定しているので
#sessを設定する部分を関数化し、globalで保存させる。
# (sessが何かということについてはmahjong_common.pyから読めます)
global sess
make_model()
saver = tf.train.Saver()
sess = tf.Session()
sess.run(tf.global_variables_initializer())
sess.run(tf.local_variables_initializer())
saver.restore(sess, "ckpt/my_model")
def calc_dahai(hands_str,tsumo_str):
#第1引数 入力例
#hands_str="6p6p7p8p3s4s5s5s7s8s東東東"
#第2引数 入力例
#tsumo_str="6s"
#実行前にinit_sess()しないと動かない
global sess
#手牌文字列を手牌1つごとの文字列の配列に変換
tehai_tmp=[]
#1バイト文字と2バイト文字が混在していて処理しづらいので、2バイト文字→1バイト文字に変換
#(クソのような仕様だが、天鳳からの入力データがそうなっているのだからしょうがない)
hands_str = hands_str.replace('東', 'HI')
hands_str = hands_str.replace('南', 'MI')
hands_str = hands_str.replace('西', 'NI')
hands_str = hands_str.replace('北', 'KI')
hands_str = hands_str.replace('白', 'SI')
hands_str = hands_str.replace('発', 'HA')
hands_str = hands_str.replace('中', 'NA')
#2文字ごとに配列に格納
tehai_str_list_by_2char = re.split('(..)',hands_str)[1::2]
#文字を元に戻す
tehai_str_list_by_2char = [s.replace('HI', '東') for s in tehai_str_list_by_2char]
tehai_str_list_by_2char = [s.replace('MI', '南') for s in tehai_str_list_by_2char]
tehai_str_list_by_2char = [s.replace('NI', '西') for s in tehai_str_list_by_2char]
tehai_str_list_by_2char = [s.replace('KI', '北') for s in tehai_str_list_by_2char]
tehai_str_list_by_2char = [s.replace('SI', '白') for s in tehai_str_list_by_2char]
tehai_str_list_by_2char = [s.replace('HA', '発') for s in tehai_str_list_by_2char]
tehai_str_list_by_2char = [s.replace('NA', '中') for s in tehai_str_list_by_2char]
#手牌文字列の配列をmahjong_common.pyで決められた数値の配列に変換
for tehai_one in tehai_str_list_by_2char:#tehai_tmp:
h = mjc.get_hai_number(tehai_one)
tehai_num_array[h] += 1
print("--------麻雀AIの判定結果--------")
tstr = mjc.get_string_from_tehai(tehai_num_array)
print("手牌:" + tstr)
tsumo = mjc.get_hai_number(tsumo_str)
print("自摸:" + mjc.get_hai_string(tsumo))
tehai_num_array[tsumo] += 1
#ツモしたかどうかを判定する関数も用意されているので
#成績を収集したり個別になんらかの処理をさせることも可能
#if mjc.is_agari(tehai_num_array):
# print("和了")
#機械学習による判定処理
ai_outs = sess.run(out, feed_dict={x:[tehai_num_array]})
dahai = get_ai_dahai(tehai_num_array, ai_outs[0])
#print("打:" + mjc.get_hai_string(dahai))
return(mjc.get_hai_string(dahai))
また本記事の主目的からすれば余談ですが、そもそもこのgitレポジトリの本来の目的である機能として、学習して出来上がったモデルをつかって、ランダムな麻雀牌ツモシミュレータをループさせて十分な試行回数でのテンパイ率などがテストできるようにしてくれてあります。
python mahjong_ai.py --run
AIの高機能化を目指すのであれば、学習用の牌譜データをもっとたくさん集めたり、プロやうまい人の牌譜データを学習させたりするなどします。
学習データを変えるとテスト結果も変わりますから面白いですよ。
ここでは機械学習についての記述は割愛しますが、機械学習の基本の部分に簡単に触れるようにしてもらってあるので、是非色々遊んでみてください。そしてよさげなAIができたら私にも譲ってください
ちなみに、現在時点で天鳳の牌譜データを大量に収集するのはちょっと難しいようですね。
データ収集できるいいスクリプトがあればそれもコメントで共有していただけると全人類と主に私が助かります。
マウスシミュレート
色々試しましたが、下記のチュートリアルが分かりやすかったです。
必要なモジュールをpipしたらコピペで動きます。
PyAutoGuiで繰り返し作業をPythonにやらせよう
https://qiita.com/hirohiro77/items/78e26a59c2e45a0fe4e3
目の前で電卓アプリが立ち上がって勝手にマウスドラッグされます。
初見では「おおっ」と拍手までしてしまった。
これのマウスクリックに必要な部分だけをコピペでもってきて、前述の動作で割り出した座標位置をクリックさせればOK
ここまでの3要素をこねて混ぜれば完成です。
コード記述はもはや省略。需要あればgitに上げます。
動作の様子(動画)
中々きな臭いプレイングですが、アガリに向かって牌の選択ができているように見えます。
めちゃんこ簡単な牌選択も、人間だとちょっと迷うような牌選択も、どちらも同じ時間で処理できるのは機械の強みですね。
観察すると現在の課題点として以下のようです。
①なんとか持ち時間の20秒を使い切らない程度に18打牌できていますが、状況によっては持ち時間をオーバーします。
この部分についてはリファクタリングの余地がありありですが、別に時間切れで負けても問題ないので、気にしていません。
結局ポンやチーする想定はしていないのだから、対局時は常に「鳴き無し」オプションを選択しておいた方が処理が安定しそうですね。
②学習時のデータに他家の捨て牌やドラの情報を含めていませんから、動画のように他家がリーチしていようと打牌はブレませんし、ドラ牌も気にせず捨てます(笑)
もし機械学習に興味があって、この機能を強化させたいという場合は、次のステップはドラ情報や自風/場風邪の情報を学習させるのがいいと思います。
次元(つまり、データが持つ意味合い)の異なるデータを1つの入力パラメータとして学習させるように機能拡張するのは重要なステップです。(mahjong_common.py側の改修が必要です)
(ただし河情報や他家のリーチの情報を学習に含めると入力パラメータが膨大になってしまって、きちんと工夫しないと安定動作そのものが難しくなると思います)
③ダマテン、聴牌崩し、暗カンには対応していません。
構想そのものから、一直線でツモアガリをひたすら目指すマシーンです。
その後
BANされました(笑)
というのは冗談で、折角なので時間切れを起こさないようにテンプレートマッチングの回数や頻度、処理手順をリファクタリングしてリーグ戦でも使ってみました。
勝ったり負けたり負けたりですが、なんといっても機械は疲れないのでずーーーっとプレイを続けてくれます。(現在進行形、私のパソコンが起動している間に限りますが...)
冒頭で紹介したgitに同梱されている天鳳データを単純に学習させたモデルが、最終的にどのあたりのリーグで安定するのか、その実力を測ってみたいと思います。
後日また追記したいと思いますので、お楽しみに。
◆記事内における雀魂側への権利侵害等の恐れについて
今回は雀魂運営側が意図していないであろうBOTのサービス内利用および記事内で雀魂の動画を掲載しましたが、公式のガイドラインに抵触しない範囲での利用であり、また著作権等を侵害していないとの判断をしております。
ただし本記事を参考にして同様の行為をされる場合は各位の責任において実施下さい。
参考までに下記に抵触する恐れのある雀魂の利用規約等を提示します。ゲーム実況配信及び動画投稿に関するガイドライン (禁止事項抜粋)
・政治、宗教、特定の信条の宣伝
(該当してるw)など、ゲーム実況を見せる以外の目的で利用すること(12)当社が本サービスを通じて提供する各種コンテンツを不正な方法で取得する行為、又はこれを助長する行為。
(ガチャ報酬をBOT運用で獲得するなど)
(16)本サービスの運用・利用を妨げる行為、又はそのおそれのある行為。
(21)前各号に準じる行為その他当社が不適切と判断する行為。
-
後の検証で縦横比が若干変動している可能性があることがわかりましたが、誤差の範囲内かと思われます。私のスクリプトでは縦横のスケールを別で計測して補正することにしました。 ↩
-
この内容については諸説あるかと思うのですが、あくまで私のベストプラクティスです。テンプレートマッチングという手法を採用してしまうと必ず発生する問題なのですが、何か他に(時間がかからなくて)いい方法知りませんか? ↩
-
後からリファクタリングなんてこれまで参入したプロジェクトでちゃんとできた試しがない。主にリソース不足とかモチベの問題で。。。 ↩
-
TensorFlow(テンソルフロー)...Googleが開発しオープンソースで公開している、機械学習に用いるためのソフトウェアライブラリ。 ↩
コメント
@kabaリンクをコピー このコメントを報告 1
@hiro0156リンクをコピー このコメントを報告 1
@netebakariリンクをコピー このコメントを報告 19
@hiro0156リンクをコピー このコメントを報告 10
@Tested(編集済み) リンクをコピー このコメントを報告 0
@sendai0905(編集済み) リンクをコピー このコメントを報告 2
@0910passリンクをコピー このコメントを報告 1
@hiro0156リンクをコピー このコメントを報告 4
@hiro0156(編集済み) リンクをコピー このコメントを報告 1
@Nassuリンクをコピー このコメントを報告 5
@silvia_hacksリンクをコピー このコメントを報告 7
@hiro0156リンクをコピー このコメントを報告 0
@hiro0156(編集済み) リンクをコピー このコメントを報告 0
@GomariNリンクをコピー このコメントを報告 9
@anti_subclassingリンクをコピー このコメントを報告 2
@emnemnリンクをコピー このコメントを報告 2
@hiro0156(編集済み) リンクをコピー このコメントを報告 0
@0910passリンクをコピー このコメントを報告 1
@zissenmahjongリンクをコピー このコメントを報告 1
@butchi_y(編集済み) リンクをコピー このコメントを報告 1
@tsushimahiroリンクをコピー このコメントを報告 1
@plusnanakaリンクをコピー このコメントを報告 1
@mucchyoリンクをコピー このコメントを報告 
4
@hiro0156リンクをコピー このコメントを報告 1
@plusnanakaリンクをコピー このコメントを報告 0
@Mitsubishi333リンクをコピー このコメントを報告 0
@mucchyoリンクをコピー このコメントを報告 0
@ouryouリンクをコピー このコメントを報告 0
面白いなあ
@Kaba さん
読了&コメントありがとうございます!
以前にゼロからRNアプリを作る時にexpoについての記事を大変参考にさせていただきました(*´∀`)この場をお借りして御礼申し上げます
アルゴリズムの強さで勝負しようと言うならまだ分かるんです。
実力のマッチングについての問題は確かにありますが、
人間同士が対局しているところに割り込んできて、
「BANされないように偽装しながら対局数をこなす」ことを主目的とした記事を
嬉々として公開する感性については、
正直申し上げて「恥を知れ」という感想しか持てないのですが
その点については何の躊躇も持たれなかったのでしょうか……?
コメントありがとうございます。
まず麻雀の強さを定量的に測るのは困難ですし、結果的な成果物のプレイングそのものは他者のゲームを大きく阻害するものではないと思っています。
私は記事のゴールを「強いA Iを作る」には設定しませんでしたが、ここから先のプロセスを記事を読んだ方々がトライする余地は十分にあるし、そのプロセスは機械学習的にとても面白い内容だと思っています。
もし私の成果物が牌をランダムに切るだけというようなものであればご指摘は該当するかと思いますが、記事の内容に多少のユーモアを含めただけでその他問題と思える箇所は見当たりません。
以上ご理解賜りますようお願い致します。
見当たらない……?
何が悪いのか根本的にわかってなさそうで失笑もの
やっている事自体は面白いと思うのですが、私も@netebakari さんが仰っている
という印象を受けました。
私は雀魂運営でもなんでもないので、あくまで推測の域を出ないのですが、
ここから「自動的に牌を切る」という行為自体が雀魂利用規約11条(21)の
その他当社が不適切と判断する行為
に該当する(と運営が判断した)のではないか、と私は感じたのですが、その点についてどうお考えなのか伺いたいです。ヤメロォ(建前)ナイスゥ(本音)
コード欲しいです〜gitあげてください!なんでもしますから!(なんでもするとはいってない)
コメントありがとうございます。
問題提起っぽいコメントが続いていますが、あまり議論として本質的でないように感じています。
私としても麻雀ゲームの運営側が想定しているようなサービス利用でないことは自覚していますが、BOTを使うことそのものが問題なのか、低い性能のBOTを使うことそのものが問題なのかは少なくとも分けて議論されるべきです。
BOTそのものの弱さについては、評価をすることが難しく、BOTなのかどうか?という点を判定できるかどうかという目的をそもそも達成していると自負しています。
前提としてまったく「鳴き」をしないという戦略を取っているという上級者あるまじきプレイングではありますが、そこらへんの初心者がやりがちな「(意味も分からず)適当にポンやチーをしてフリテンであがれない」ようなプレイングよりは遥かにマシです。
この他者のゲームを無意識に阻害するような初心者より、今回のBOTは明らかに優秀です。というより無害です。
(親がリーチしてるのにカンしたりするようなこともしませんしね!笑)
この実力に影響するような部分のチューンナップを繰り返したら、「なんかなぁ」と部分や「アルゴリズムの強さで勝負しなさいよ」という部分は解決するのでしょうか?その場合、私はあと何百時間くらい費やせばいいのでしょうか。その部分を定量的に評価する方法は存在するのでしょうか?そもそも私より強いBOTを作るのは(理論上)不可能なのですが、その場合は私がこの麻雀サービスを利用していることそのものが非難されるべき対象になってしまうのではないでしょうか。
「自動的に牌を切る」行為はみなさんもやっている行為です。
というより、人間がやるのかAIがやるのかという点において全く差がありません。
この記事の出発点は不純な動機としてユーモアを交えて記載していますが、あくまで機械学習を用いて完成するBOTの性能評価ができないだけであって(あるいは現在リーグ戦を繰り返して実力評価を行っていますが、、、)議論のときは上記のような本質的な内容に着目いただきたいです。
コードの配布については準備中ですが、性能評価とある程度のデバッグが必要なのでちょっと時間がかかります。
というのもテンプレート用の画像そのものを配布してしまうと、ちょっと倫理上問題があるかなと思っていて、とはいえみなさんが手元で(あらゆる解像度や条件下で)キャプチャした画像を柔軟に吸収できるようなソースコードになっていないので、リファクタリングを進めています。
気長にお待ちください〜。というより機会を見つけて別記事で性能評価とあわせて投下したいと思っています〜。
後日追記:様々ご指摘をいただき、ソースコードの公開は運営の多大な迷惑になる可能性が高いので、いったん凍結します。楽しみにしていただいていた善良なエンジニアの方々に置かれましては、申し訳ありません。
対人対局が好きなので、相手の雀力が初心者さんであろうと雀聖さんや魂天さんであろうと、気にはしないのですが、麻雀AIにはとても興味があります。
なので、とても興味深く読ませて頂きました。
~~閑話~~
ハタから己が正義を以てお小言を述べられるとても潔癖な方が最近多いような気がします。
(よく〇〇警察と揶揄されてますね)
今回はYostarと@hiro0156さんとの間で「規約違反だ」vs「触れてない」だったり、「BANだ」vs「BANされた~~」といったやり取りが発生することはあるかもしれませんが、そのどちらでもない第三者が、まだ何も起きてない状況でどーこーいうものではないと思われます。
まずはやってみる!そういったスタンスでチャレンジされる方を委縮させるだけの外野のヤジは何割か差し引いておいていいと思っています。
~~閑話休題~~
データ検証も含めて続報期待しています。
技術記事としてはなかなか興味深かったのですが、オンラインゲームにおけるBOT問題についてあまりご認識がないようでしたのでコメントさせていただきます。
BOTがなぜいけないのか、と言うのは非常に難しい話で、私も正確には的を得た回答をすることができないのですが、オンラインゲーム運営責任者の方が書いた記事がなかなかわかりやすかったのでリンクを貼っておきます。
ご興味がございましたらご覧ください。
http://netogenow.seesaa.net/article/12196674.html
また、できましたらソースコードの配布もおやめ頂いた方が無難ではないかと思われます。
何故かと言いますと、ゲームがRMT(リアルマネートレード)によって崩壊する可能性があるからです。
どのようにして崩壊するかのか一例をあげますと、まず大量の無料アカウントを用意して、仮想環境などを利用して大量にBOTを稼働させます。
時間はかかりますが、ゲーム運営に一円も落とさずに無課金で、報酬アイテムを大量に持ったアカウントが出来上がります。
そのアカウントをRMTサイトにて販売します。
ガチャでよいキャラを引いた場合、更に価格が上がったりするかもしれません。
ようはゲーム外で錬金術が出来てしまうわけですね。
そして、そのお金は運営には一円も入っていません。
ゲームサーバではBOTだけが中身のない対局を続け、そんな場所に人が集まるかと問われればなかなか疑問があります。
また、運営はその大量の無料アカウントを稼働させるためにサーバ代を払っている訳ではないので、それは面白くない訳です。
これは一つの例ですが、他にも問題は多岐にわたる可能性がありますので、どうか自重をお願いする次第です。
@Nassu さん
思ったよりも批判的なコメントが多くついてしまって、しょげておりました。(笑)
コメントありがとうございます。また懲りずに次の記事のネタを探す気になりました~!(*'▽')
@silvia_hacksさん
コメントありがとうございます。BOTがなぜいけないのか、という点について以下のような論点があるようですね。
・BOTがクライアントソフトウェアへ干渉することで、(サーバーに対して予期せぬ通信データの受送信を行うなどして)、問題引き起こす。
・BOTの行為がゲームのバランス(プレイング/ゲーム内経済)を崩し、顧客離れや課金システム破壊による運営企業の営業的損失。
・BOTかどうか判別できないことによって、ゲーム内サポートに混乱が起こる点。
ただし、やはりこれは令和の世になった今でも下記の通りです。
・サーバーでもダウンさせない限り、BOT使用者に対し、現実の法律によった対処ができない。
個人的にはたまにしか動かないBOTと不眠不休の人間の間にそもそも差はなく、処罰の対象となる方がおかしいと思ってさえいます。(法律に詳しい方のコメントをずっと待っています)
これをどうするべきかといえば、私の記事の内容について公式がソフトウェアでBOT対策するか、このように自重をお願いされるしかない訳です。
(そもそも自重する気持ちがなければ、無料でここに寄稿してないで既にBOTとして売りさばいているところですが…)
.
当該のブログを読んで分かったことなんですが、なぜここに「恥を知れ」とまで語気を荒げて不満をぶつける方がいるのかということです。
私としても気にしているBOTの問題点として「他プレイヤーのゲーム体験を妨げる」可能性がある訳ですけれど、これはBOTが人間心理に引き起こす以下の現象によって「プレイが下手でも上手くても腹立たしい」という点が重要で、私が気にしていた「BOTが人間程度にプレイできてるしいーじゃん!」というところはおそらく問題ではなかったということが分かりました。なんてこった。つまり、コメントに表立ってこない部分として
・人間(判定者の主観でしかないが)より下手であった場合→普通に腹立たしい。
・人間より上手であった場合→人の操作より高度で正確な動作を反復して行うのが腹立たしい。
・そもそもBOTが集めたゲーム内貨幣やアイテムを(あわよくば現金に換金(RMT)して)儲けている奴が許せない。
・そうなってくると自分が操作してプレイするのもバカバカしくなってくる。(麻雀のような知的ゲームでは100%合致しませんが)
ということなんでしょう。気が付かなかったなぁ(白々)
つまり、(技術的な点は)面白いけど(プレイヤー的な心情としては)なんだかなぁ…ということだったんですね。
対戦型ゲームにおいて、相手が生きた人間であることは重要なファクターであり、商品価値です。
上手い下手はあまり関係ありません。
ユーザー心理より重要なのは、ここで提起されている課題は本来課金によって解決されるものであるという点です。Yosterとしては経済的損害を受けることになります。
Yosterが対応すべきことであって第三者が言うことではないという意見もわかりますが、大半の(真っ当な)ユーザーは運営が利益を上げることを望んでいるはずです。
麻雀AIとしては大変興味深く、面白い内容だと思いますが、課金型オンラインゲームでの使用を前提とした内容ですので、批判されて然るべきと思われます。
記事に対する『バールで自販機壊して儲かりました』というご自身の例えはある程度秀逸ですね(『極端な言い方』だとは思いませんが)。
犯罪あるいは犯罪教唆になり得ると分かっておいて(あるいは分かっていると示唆しておいて?)、なお記事を公開したままでいられるとは中々凄い。
また、そこまで分かっておいても、記事のスタンスや真当な指摘に対する返信ではこれというのは、少々おふざけが過ぎるように思いますね。
@GomariN さんのコメントがよく纏まっているので蛇足気味ですが、
この認識が広く同意されるかは疑問です。
人間と対戦すること自体に価値を見出すユーザーは数多く存在します。
BOTを利用したRMTは、運営が作ったコンテンツにタダ乗りして本来運営が得るべき利益を搾取する行為です。
法律による取り締まりを受けない事と倫理的に許容される事はイコールではありません。
というか素人的な感想では、ソースコード配布してBOTが横行した場合なんか普通に訴訟案件なんじゃないかと思いますが…
@GomariN さん
種々ご教授ありがとうございます。
私はここまで明確な迷惑行為の定義について探っていましたが、上記のポイントは的を得ていて、実体的なゲームの構造そのものを(もし実際に裁判が起こった時に)無視し続けることはできいのではないかと感じました。
@emnemnさん
上記のようなことも分かりましたので、そろそろBOTの使用を正当化する主張は取り下げようと思います。
BOTを使用していることを「表明する」ことは、おっしゃるように倫理的に悪のようですね。
この部分については是非有識者の意見を伺いたいものです。
私も素人ですが、現在の私の認識だと、もし私がBOTを販売して利益を挙げたとすれば、構造上、Yosterが得るはずだった利益を横取りしたことになってしまうので民事的に損害を賠償させられる可能性がある、というところでしょうか。(そしてこの記事の公開はあくまで倫理的に悪)
情報理解しました。
コードが面白かったです笑
確かに公開するといろいろ問題起きそうなんで配布しないでください()
発想最高でした!続報待ってます
( ˆoˆ )/
プログラム初心者だけど、すごく感動した。
自分にもできるかわからないけど、参考にさせていただきます。
BOTに対する倫理観や法的解釈以前に、開発元のYostarさんに全く敬意を感じられない書き出しから始まっていて読んでて不快でした。
面白かったです!参考にさせていただきますね。
BOTの問題云々についてですが、ユーザー目線で言うなら、BOTか人か見分けつかない動きをするならあまり問題ないと自分も思います。不快に思う人の意見は相手がBOTだとわかっている前提なので。個人的には萎え落ちしてツモ切りマシンになるユーザーよりよっぽどマシです…
運営が対応してくるか否かについては、単純に対応コスト<放置による損失になるかどうかでしょうね。
対応コスト>損失なら規約違反してても放置するでしょうし、対応コスト<損失になるなら規約変更してでも対応してくるはずです。
ちなみに、機会損失とかユーザーの信頼低下なども損失なので投稿主さんが利益を得てなくても対応される可能性はあります。
有用な記事をありがとうございます。
自分は、切り牌と残り牌から相手の手牌を予測して、安牌や当たる確率
当たった時の放銃点数などを予測するツールをつくってみたいなと
思いました
大変おもしろい記事をありがとうございました。
実は自分も趣味で同じようなプログラムを書いていて、興味深く読ませて頂きました。
牌の認識について、テンプレートマッチングではちょっと時間がかかり過ぎる感じですね。
自分がやった方法だと、
OpenCVのcv2.findContours()を使って牌を検出 → 小規模のCNN+全結合層で構築したモデルで牌を分類
で、全牌の検出+認識まで処理速度はおよそ0.12秒程度です。
ご参考まで。
@tsushimahiro
コメントありがとうございます。運営さんからの指導指摘には真摯に対応する所存です。
@plusnanaka
ぜひぜひ~!私のは牌認識までの導入紹介なので、そこから先の展開にぜひオリジナリティを入れていただいて、また私にも教えてください~('◇')ゞ
@mucchyo
こ、これはすごい、、、大先輩からコメントいただけて嬉しい限りです。
輪郭検出はここまで回転に強いんですね。私は早々に捨牌認識はあきらめてしまいましたが、これはちょっとやってみたいですね。
そういえば、記事中では2.7sの処理時間と書きましたが、4Kディスプレイで処理してました。笑
画像の下準備を工夫すれば1s前後で処理できるようになりました(今更)
とはいえ、当然ディープラーニングさせたほうがよいと思っていますので、モデル構築まで完了されているのは流石です。また勉強させていただきます!
@mucchyo
これは、すごいです! 手配は、cv2.findContours()で全部認識できたものの、切り牌のコーナーは、隣の牌とくっついてしまったり、うまく切り分けできないで、悶々としています。 ソースが見たいです
@mucchyo
牌の識別本当にすごいです。
自分も、もし宜しければソース見せていただきたいです。
@plusnanaka
@Mitsubishi333
申し訳ありませんが、公開はしません。
BOT開発の一助となる可能性がありますからね。
麻雀アプリケーション運営様のご迷惑になることは出来ません。
あくまで個人の趣味でやっていることです。
麻雀のテンプレートのついて、スキャナーで作ったら非常にきれいな画面を得ました。