Go
golang

???「これぐらいの奇蹟…安いもの!!」1種2種混合機の 80% ループで大連荘を生み出せ!


:rice::rice: 回想シーン


あずき (このあいだ見かけたの みたく AA 使って何か作りたいな~)

あずき (そうだ!シ◯フォギアラッシュのシミュレーターとか面白そうじゃない?)

ザッ...(足音)

あずき「し、師匠ッ!」

???「(バズる)勝算はあるのかッ!?」

あずき「思い付きを数字で語れるものかよッ!」



:musical_score: TL;DR

『CRF戦姫絶唱シ◯フォギア 1 』をご存知でしょうか?

増大に次ぐ増大、噂の機種の継続率体験シミュレーターを作ってみました!

不承不承ながら左打ちしましょう.gif

こんな感じ!


???「安い…安さが爆発しすぎてる!!」


下の方にソースコード(GitHub)も公開していますが、辿り着くまでがまあまあ長いので読むのめんどくさい人は、


???「最速で最短でまっすぐに…一直線に!!」


こちら へどーぞ!


:rocket::full_moon_with_face: はじめに

回想シーンの主人公(?)も言ってましたが、やってみたいことがいくつかありました。


  • AA を使って何か作りたい

  • パチンコ遊技機(以降、遊技台と記載 2 )の複雑な仕様を一部でも実装してみたい

  • シ◯フォギアで事故りたい(リアルでも


???「胸の歌を信じなさい…」


ってことで作ってみました!


:slot_machine: 仕様について

遊技台、ひいては1種2種混合機 3 の仕様はいささか難しいので少し説明します。

(わかりやすいように数値はシ◯フォギアのもので記載しています)


  1. 通常時 1/199 の確率で大当りに当選


  2. 大当り後、電サポ 1 回+保留 4 個の計 5 回転の間に 1 / 7.4 の確率に当選することでラッシュ突入(ラッシュ突入期待値は約 52 %


  3. 以降ラッシュ中は電サポ 7 回 + 保留 4 個の計 11 回転の間に 1 / 7.4 の確率でラッシュ継続(継続期待値は約 80 %


(保留玉を先読み抽選して連荘を確定させる V-STOCK という機能がありますが、この仕様の有無で継続率的に変化がないことと、抽選とは並行に電チューへの入賞をリアルタイムで行う(抽選数を上限まで一定時間ごとに増やしていく)実装はしんどいからパスw)

どうですか?けっこー複雑ですよねw


???「言ってること 全然分かりません」



:microphone: どんなシミュレーターにするの?


実装範囲は

仕様が複雑なのは説明しました。

じゃあどの部分をシミュレーターとして実装するのか?

仕様の 1. は実装してしまうとダレてしまいますwパス。

(シミュレーターでまでハマり体験したくないでしょう? :sob:

仕様の 2. を含めるかどうか...が悩んだところなんですが、個人的に最終決戦( 52 % )を乗り越えてこそ熱くなれるものです!

そんな謎の持論を振りかざし仕様 2. + 仕様 3. でシミュレーターを作ってみます!


どんなUIなのか

上の方に動画載せちゃってますけど、CLIツールですね。

UIというかコマンドラインでぽちぽちしてればシミュレーション出来る感じです。


:musical_note: サクッと機能説明

シミュレーターと言いつつゲーム感覚で楽しめるものにしています。

ラッシュを継続させて「継続数」と「ポイント数」を競う感じです。


1. シミュレーターを起動するデース!

_人人人人人人人人人人_

> 最 終 決 戦 開 幕 <
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^ ̄

というタイトルと共にゲームがスタートします。

もうゲームって言っちゃってるよ


2. 強い意志を持って [ Enter ] キーを押すデース!

勝 機 を 零 す な !  掴 み 取 れ !

とセリフが出るので、


???「推して参る!」


って感じで押してください!

抽選がスタートし図柄が揃えば「シ◯フォギアチャンス」突入です。

// 当たるときの図柄例

7 7 7

// 外れたときの図柄例(ランダム)
1 7 1

抽選のチャンスは5回あるので、それまでに当選できない場合はゲーム終了です。


3. シ◯フォギアチャンス突入デース!

_人人人人人人人人人人人人人人人人人人人_

> シ ◯ フ ォ ギ ア チ ャ ン ス 突 入 <
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^ ̄

というタイトルと共にラッシュスタートです!

以降は「最終決戦」の時同様に [ Enter ] キーをポチポチしながら抽選を繰り返し、当選したらラッシュ継続、規定ゲーム数で当選できなかったらラッシュ終了(ゲーム終了)です。


4. スコアを確認するデース!

ラッシュが終了したら次のようなスコアが表示されます。

// FEVER ・・・ 継続数

// TOTAL ・・・ ポイント数
┌ーーーーーーーーーーーーーーーーーー┐
│                  │
│  F E V E R ✕ 10    │
│                  │
│  T O T A L         │
│      1 0 7 8 0 p t  │
│                  │
└ーーーーーーーーーーーーーーーーーー┘

目指せ大連チャン!

リアルで50 連とかさせる豪運の持ち主もいるそうなので、ぜひ目指してみてください!(リアルで


:pencil::zzz: やっとこさ実装のはなし

全部紹介しても仕方がないので、何点かピックアップして説明しようと思います。

(あずき 4 の GO言語のスキルは十数時間の学習程度...あしからず...)


抽選のはなし

仕様的にメインになる部分です。

色々と調べていたら抽選用のライブラリーを作られている方がいて利用させていただきました。

:link: Goでlotteryという抽選ライブラリを作った


インポートして

import "github.com/kyokomi/lottery"


初期化して

lot := lottery.New(rand.New(rand.NewSource(time.Now().UnixNano())))


こう書けば

lot.Lot(20) 

20% の確率の抽選が行われます。


さらに、こう書けば

lot.LotOf(1, 10)

1 / 10 の確率の抽選が行われます。


さらに、さらに、こう書けば

// 大当りの種類(15R, 9R, 4R, みたいなの)

type feverKind struct {
// 獲得 pt (期待値)
Point int32
// 図柄(7とか1とか)
DispDesign string
// 当選割合(’15R は 40%’とかの "40" 部分を設定)
DropProb int
}

// lottery 使用のために必要な抽選用のメソッド
func (f feverKind) Prob() int {
return f.DropProb
}

func main {
// 大当りの種類を設定する
ferverkinds := []lottery.Interface{
feverKind{Point: 1470, DispDesign: "7", DropProb: 40},
feverKind{Point: 1176, DispDesign: "3", DropProb: 3},
feverKind{Point: 784, DispDesign: "5", DropProb: 7},
feverKind{Point: 392, DispDesign: "1", DropProb: 50},
}

// 抽選
lotIdx := lot.Lots(ferverkinds...)
ferver := ferverkinds[lotIdx].(feverKind)

// 当選した ferverKind の図柄が表示される
fmt.Println(ferver.DispDesign)
}

ちょっと複雑ですが、インターフェースとして必須の Prob メソッドが返す feverKind#DropProb の値が当選確率(%)になります。

例えば、DispDesign: "7" のデータが当選する確率が 40% ってことですね!


すごく便利!

自分で実装するのも考えてましたが、作り始めたタイミングでインターフェースを理解できていませんでしたし、これほどのものが作れるとは思えませんでしたので、ありがたく利用させていただきました :yum:


???「ちきしょう...かなわないわけだ。」



ハマりポイント

ハマったと言うほどではないのですが、lot.LotOf(1, 10) この書き方をしたときに調子に乗って分母に 65532 を設定したんですね。

そうしたら型が int だったので永遠に当たらないボッタ台が出来上がったのでしたw :smiling_imp:


CLI ツールのはなし

正直、作ってて Web にすれば良かったなーなんて思ったりもしましたw

でも、まあ、乗りかかった船でしたので、コマンドラインツール立ち上げて完結させたいなぁと、この形になったわけです。

CLI ツール化するにあたり、ここでもライブラリーを使用させていただきました。

:link: urfave/cli


インポートして

import "github.com/urfave/cli"


初期化して

app := cli.NewApp()


関数を登録して

app.Action = func(c *cli.Context) error {

// シ◯フォギアを遊戯する
playSymphogear()
return nil
}

app.Run(os.Args)


実行する

app.Run(os.Args)

ただ動かしたいだけなら簡単です。


他にも

app.Name = "greet"

app.Usage = "fight the loneliness!"

とか登録できて、help 付けて叩くと

$ greet help

NAME:
greet - fight the loneliness!

USAGE:
greet [global options] command [command options] [arguments...]

VERSION:
0.0.0

COMMANDS:
help, h Shows a list of commands or help for one command

GLOBAL OPTIONS
--version Shows version information

みたいに実行されます。


とにかく便利!

自分で作るなんて現時点で無謀だし、助かりました。

シンプルな使い方しかできてないので、もう少し触ってみようと思います!


???「ちきしょう...かなわないわけだ。」



ファイルの読み込みのはなし

AA を出力するのに fmt だとすごく大変だなーと考えていたので、ファイルを読み込んで1行ずつ出力する方法をとりました。


開いて

// ファイルオープン

file, err := os.Open(filePath)
// エラーチェック
if err != nil {
panic(err)
}
// ファイルを閉じる関数を defer で最後に遅延実行
defer file.Close()


読み込んで

scanner := bufio.NewScanner(file)


1行ずつ出力

for scanner.Scan() {

line := scanner.Text()
fmt.Println(line)
}


文章とか複数行に渡る文字列を出力するときには便利!

AA ってフォントによっては見づらいものがあるんですよね :disappointed_relieved:

色々な種類を出力させて試すんですが、そんなときに fmt#Println とかで1行ずつ出力してたら絶望します...

ファイルなら中身を貼り替えるだけなので、この方法を選んで正解でしたね!


ビルドのはなし

ビルドして実行してみました。

> go build -o tmp/test.exe

> tmp/test
panic: open ./AA/challenge-start.txt: The system cannot find the path specified.

あら?エラー。

どうやら読み込むファイルが無いと駄目みたい... :tired_face:


rakyll/statik というライブラリー

を見つけまして、読み込みファイルをバイナリー化して一緒にビルドしてしまおうという代物。

さっそく使ってみました。

:link: https://github.com/rakyll/statik


ダウンロードしてきて

go get github.com/rakyll/statik


ファイルのあるフォルダを指定して実行

> statik -src=/path/to/your/project/public

# Windows 環境だとビルドして実行ファイル作らないと駄目だよー

次のようにファイルが出来上がります。

.

├── statik
│ └── statik.go
└── main.go


コード側で利用する

import (

"github.com/rakyll/statik/fs"

_ "./statik" // TODO: Replace with the absolute import path
)

// ...

statikFS, err := fs.New()
if err != nil {
log.Fatal(err)
}

TODO: の部分は一度 GitHub に push してから自分のパッケージをインポートしましょう。


ファイル読み込みのときのように扱える

file, err := statikFS.Open(filePath)

if err != nil {
panic(err)
}
defer file.Close()

ファイル読み込みのときに os.Open(filePath) としていた部分を statikFS.Open(filePath) としています。

ちなみにファイルパスは /fileName.txt のようにカレント直下にあるかのように指定します。


これもまた便利!

このライブラリーを見つけるまでは「実行ファイルと読み込みファイルセットでいいかw」みたいに考えていましたけど、やっぱりまとまっている方がいいですよね!

作ってくださった方に感謝です! :yum:


???「ちきしょう...かなわないわけだ。」



ハマりポイント

普通の人は無いと思うんですけど、

> go get github.com/rakyll/statik

# github.com/rakyll/statik
..\..\rakyll\statik\statik.go:163: fHeader.Modified undefined (type *zip.FileHeader has no field or method Modified)

みたいに出たわけです。

:link: https://golang.org/pkg/archive/zip/#FileHeader

ときて、

> go version

go version go1.8.3 windows/amd64

はい、バージョン古かったです :innocent:


???「『どんくさい』なんて名前じゃない!!私は(ry」



:syringe: やり残したこと

他にも実装してみたいことがあったのですが、時間の関係上できてないです。 :sleepy:

ちょっとずつバージョンアップさせていこうかな?


機能面


  • 文字色を変えて期待度をもたせる


  • V-STOCK をどうにか表現する

  • 各キャラの AA カットインしてプレミア感だす

  • スコアに応じて AA を切り替える

  • スロット版を...


???「これで僕も英雄になれる…この星のラストアクションヒーローだ!!」



実装面


  • テストコードを書く、テストする(書き方覚えるところから)

  • GitHub での資産の管理方法を覚える(オープンなとこで管理したことないから)


  • かっこいい READ ME つける(他の人のかっこいい...) (ちょっと作ってみた)

  • そもそももっと GO言語 の知識付けないと...


???「飯食って、映画観て、寝る!男の鍛錬はそいつで十分よ!」


師匠!なるほど!


:milky_way: おわりに

ネタのつもりで作り始めましたがなんとか作りきりました!

GO言語のスキルが乏しいため、コードにまずい点などありましたらアドバイスもらえると嬉しいです!

(コメント大歓迎です!)

:link: https://github.com/azukisiromochi/ikirunowo-akiramenaide

最後まで見てくださった方はきっとシ◯フォギア好きですよね?(違うかw)

最後はこの言葉で締めくくりましょう!

では、ご一緒に...


???「コードを書くのを諦めないで!」






  1. 導入当時は同時期に導入された「魔法少女まど◯☆マギカ」に人気が流れたこともありバラエティーコーナーに数台設置という店が多かった。だが、バランスの良い演出、熱い「最終決戦」モード、高い連チャン性能などから人気が出ていき、バラエティーコーナーの台の取り合いという状況が起こった。人気の上昇に伴い店舗側も増大を重ね、現在(2018/11)では導入率は 75% を超えている。また、通常 時 1/99 のライトバージョンも 12 月に発売をい控えている。 



  2. 「以降、遊技台と記載」と記載した割に、それ以降で1度しか出てこなかったのは書いた本人も草。 



  3. 1種は「デジパチ」、2種は「デジ羽根(羽根モノ)」を意味しそれぞれで当選してラッシュに突入する仕様の遊技台(ここで出てきたw)のこと。新基準により確変継続率が 65% を超えることができなくなってしまったため、それらを複合することで高い継続率(と感じさせるがそれぞれ単独では 65% 未満)を体験することが出来る。  



  4. この記事の筆者。やけに詳しい感じで書いていますが現役はとう退いています。待ち時間に低貸しを打つことはありますが退いています。(念押し!)ちなみに遊戯中は技術介入に夢中で演出をよく見逃します。技術介入で思い出しましたがシ◯フォギアは右が甘いので技術介入すればかなりの確率でオーバー入賞が可能です(ただし切ちゃんには注意)。お試しください。