Pythonで音ゲー(ボルテ)のツール作ってみた

タイトルを何にするか迷いましたが、一般的な感じにしました。

背景

僕はSOUND VOLTEX(以下ボルテ)というゲームが好きでよく遊んでいます。

このゲームはゲームセンターで遊べる音楽ゲーム音ゲー)です。音ゲーがどのようなものかは省略します。ボルテは以下のような特徴を持った音ゲーです。

  • レベルが20段階
    • 特に16~19あたりが多く遊ばれる
  • 譜面数が非常に多い
    • レベル16・17は300以上の譜面ある
  • スコアが1000万点満点
    • ほとんどの譜面は900万点以上獲得できる
  • 各譜面のハイスコアをCSVファイルで入手できる(→後述)

僕自身のボルテに対するスタンスはというと、

  • プレー歴5年以上
  • 5000クレは投入?
  • その割に上手くない
  • 成長が鈍い(伸びてないわけではない)
  • 現在はレベル15~20の譜面を遊んでいる

つまり、マンネリとなってモチベーションが低下してしまう可能性が常にあるというわけです。

また、ボルテには様々な非公式なツールが存在しています。

nearnoah.sakura.ne.jp

myamyasdvx.herokuapp.com

今は使えませんが昔はこのようなツールがありました。

SDVX IIIのスコアツール

スコアツールによって、何が可視化されてうれしいかというと、代表的なものに各レベルのスコア平均値があります。

f:id:alek3:20180616234341p:plain

これを見ながら、「レベル15の平均99いった!」とか「今月はレベル18の平均957目指そう~」とかそういう使い方をします。計測可能な目標を増やすというわけです。

現状のツールの不満点に、参照できるデータが最新のもののみであるという点があります。昔のツールは、過去のスコアや、ひとつ前の記録との差分を見ることができました。

以上の背景から、「各レベルのスコアの平均値の推移表を作成する」ツールを作成することにしました。

Input/Output

プログラムを作成する前に用意するもの、すなわちインプットは、ボルテのスコアが記録されたCSVファイルです。これは最新版がKONAMI提供のe-amusement gateから取得できます。

これを定期的に取得して保管しておきます。

f:id:alek3:20180617002456p:plain

ファイル名は自分でリネームしています。

プログラムは下記を参照してください。

github.com

scoresheetディレクトリにいくつかのCSVファイルを入れて、プログラムを実行すると、以下のようなxlsxファイルが得られます。これがアウトプットになります。

f:id:alek3:20180617002807p:plain

これによって僕は、「6月10日から13日までで、レベル18の平均スコアが2700点も伸びてる!!よっしゃ!!!!」という達成感を得ることができるようになりました。ボルテをやってない人にはさっぱりでしょうが、僕にとっては有用な代物です。*1

終わりに

エクセルファイルをアウトプットにしようと思ったのは最近読んだ以下の書籍の影響があります。今回Pythonで書いたのにも少し影響しています。

改善ポイントとしては、以下があるかなと思います。

  • コードが汚い
  • 平均スコアが上がったセルは、赤色とかで塗りつぶしがあるといいな
  • スコアのCSVを定期的に手動でダウンロードするのが面倒

アウトプットがExcelファイルというのは見やすくていいなと思いました。

*1:ちなみに、R3からR4にかけて平均値が16000も上がっています。これは一見すると異常なのですが、上昇の理由はΩ Dimensionでクラッシュしたまま放置していた曲があったためです。Ω Dimensionで解禁できない曲がある19は、平均値が大きく上下します。

レビュー『改訂新版 Swift実践入門』

こちらの書籍のレビューです。

対象読者

本書の「はじめに」にあるように

  • 他の言語の経験はあるがSwiftの経験はない方
  • Swiftの知識をより深めたい方

です。歯ごたえあると思います。実践入門は入門に非ず。

感想

また「はじめに」から引用ですが

どんな(what)言語仕様があり、それらをどのように(how)使うかに関しては豊富な情報源があります。それらがなぜ(why)存在し、いつ(when)使うべきかについてまとまった情報があるとは言えません。本書は、読者の皆さんの「なぜ」や「いつ」を解消することにも主眼をおいています。

とあるように、類似する機能の使い分けについて、いくつか書かれていました。例を挙げると以下の2つです。

  • クラスと構造体の使い分け
  • 継承とプロトコルの使い分け

特にクラスと構造体の違いは、この本に触れる前から気になっていたので勉強になりました。

ただ全般的に僕にとっては少し難しすぎたようです。特に11章あたりから……

14・15章はスキップしました。

現状は、完全に理解したいというよりも、なにか課題にぶつかったときにこの本の内容を参照できればよしというスタンスです。例えるなら「心のインデックス*1」ですね。

*1:僕発祥ではない。この概念を説明するの難しい

ネットで調べて出てきたSwiftコードを精読してみた

実装に困ったらstackoverflow先生に頼るのはよくあることですが、そのままコピペするのはいけません。「これってどうしてこういう実装になったの?」「stackoverflowからコピペしました!」だと怒られる気がします。*1そこで、今回は僕が参考にしたソースを精読して理解したいと思います。

想定されるレベル感はSwift書き始めたばかりくらいの人です。

今回の元ネタはこちらです。

ios - How do I resize the UIImage to reduce upload image size - Stack Overflow

画像をサイズ縮小するにはどうしたらいいか?という問いです。 最も+を得ている回答は以下のとおりです。

extension UIImage {
    func resized(withPercentage percentage: CGFloat) -> UIImage? {
        let canvasSize = CGSize(width: size.width * percentage, height: size.height * percentage)
        UIGraphicsBeginImageContextWithOptions(canvasSize, false, scale)
        defer { UIGraphicsEndImageContext() }
        draw(in: CGRect(origin: .zero, size: canvasSize))
        return UIGraphicsGetImageFromCurrentImageContext()
    }
    func resized(toWidth width: CGFloat) -> UIImage? {
        let canvasSize = CGSize(width: width, height: CGFloat(ceil(width/size.width * size.height)))
        UIGraphicsBeginImageContextWithOptions(canvasSize, false, scale)
        defer { UIGraphicsEndImageContext() }
        draw(in: CGRect(origin: .zero, size: canvasSize))
        return UIGraphicsGetImageFromCurrentImageContext()
    }
}

(Xcode 8.2.1 • Swift 3.0.2)

では書いていきます。

1行目

extensionは型を拡張するときに使います。これをするとUIImageのインスタンスimageがあったときに、 imgae.resized(withPersentage: 0.1) で使えるようになります。

2行目

withPercentageは外部引数、percentageは内部引数です。 CGFloat型とFloat型の違いはなんだろう?と思って調べたところ、以下の通りだそうです。

Float型とDouble型はCocoaでも用途によって明確に使い分けられています。たとえば、画面上の座標に使用されるCocoaのCGFloat型は、32ビットのプラットフォームではFloat型、64ビットのプラットフォーム型ではDouble型になります。

どうしてこのような使い分けになっているかはちょっと分かりませんでした。 処理自体は、引数で指定したpercentage分だけ、画像の大きさを小さくするというものです。辺の長さが半分なら0.5を指定します。

3行目

CGSizeは縦横のサイズを指定するクラス。関連したものにCGRect、CGPointがあります。

4行目

UIGraphicsBeginImageContextWithOptionsはbitmap-basedなImageをOptionつきで作成できるクラス。scaleをこのクラスでは定義していないけど何故か動いている。気になってdefinitionにさかのぼったが、どうやらUIImageのopen varらしい。

5行目

deferは遅延実行です。

リソースの解法など、そのあとの実行フローの内容にかかわらず、スコープの退出時に確実に実行されて欲しい処理の記述に利用します。

で、何が実行されているかと言うとUIGraphicsEndImageContext()ですが、要するにUIGraphicsBeginImageContextWithOptionsの対になるもので、画像の描画を終わらせるために活用するものだと思います。開始と終了がワンセットだから、この位置でdeferされているのでしょうか。*2

6行目

draw(in: CGRect)は、元々のUIImageを引数で指定した大きさに変換して再描画する処理です。CGRect()では、座標とサイズの設定が行われています。origin: .zeroの方は、座標を表しているから、元のところから動かさないの意味?

7行目

UIGraphicsGetImageFromCurrentImageContext()は、現在の"Context"にあるImageを取得するというものです。 つまり、4行目~7行目でUIGraphicsBeginImageContextWithOptions→UIGraphicsGetImageFromCurrentImageContext→UIGraphicsEndImageContextの流れが記述されているということになります。

8行目以降

大きさの設定方法以外全部同じなので省略

まとめ

振り返ってみるとそこまで難しい処理をやっているわけではなく、Contextの生成→Imageを作成→Contextの削除という流れがあるとわかりました。一つでもちゃんと読んで理解できると、他の類似のソースを見たときに何が違っているのか理解しやすくなりますね。

参考

石川・西山『改訂新版 Swift実践入門』

https://developer.apple.com/documentation/uikit/1623912-uigraphicsbeginimagecontextwitho?language=objc

https://developer.apple.com/documentation/uikit/1623933-uigraphicsendimagecontext

https://developer.apple.com/documentation/uikit/uiimage/1624092-draw

https://developer.apple.com/documentation/coregraphics/cgrect/1454856-init

*1:社畜ちゃん』の後輩ちゃんもどっかで怒られていました

*2:他の例を見ると、deferを使わずにreturnの直前に置いているのもあるので、活用は好みの問題なのかなとも思いました。

レビュー『独学プログラマー』

こちらの書籍のレビューです。

独学プログラマー Python言語の基本から仕事のやり方まで

独学プログラマー Python言語の基本から仕事のやり方まで

結構軽い書籍で、僕は秋葉原有隣堂併設のカフェで1時間くらいで一周しました。 その結果、これは手元に置いておきたいと思って購入しました。

対象となる読者層

本文中にははっきり書かれていなかったと思いますが、

  • プログラミングに興味がある人~始めて1~2年以内の人
    • 特に「興味があるけど何したらいいかわからない」人
  • 「独学」と聞いて心躍る人

がいいと思います。

内容

良いところ

「次何したらいいか」がわかる

プログラミングの入門本にありがちなのは、「文法は分かったけどこれで何をすればいいの?」となる場合があることです。 すでにプログラミング関連の職種についている人は別ですが、独学、すなわち自分の意思や興味から始めている人にとっては、次にやれることがたくさん示されているこの本は非常に役に立つと思います。

参考となる書籍やサイトがたくさん挙げられている

前に上げた良いところの続きです。 内容の項を見ると分かりますが、紹介されているトピックは幅広いですが、その分内容は簡単なものにとどまっています。 それの補完として、様々な参考書籍やサイトが数多く挙げられていて参考になります。

それだけでもすごいのですが、さらに良いのは日本語訳者が日本語のサイトや書籍を追加で紹介してくれていることです。 とてもたくさん紹介されているのでそこから選ぶのが悩ましい。

個人的感想

今の僕にとっては、どう学ぶかという方法論ももちろん大事ですが、そろそろ実際にモノを作ろうぜという段階だな~と思います。(今まで何も作ってなかったというわけではないです、たぶん)

レビュー #マンガでわかるDocker

お久しぶりです。アレクです。

『マンガでわかるDocker 』を電子書籍版で購入し、ひと通り試したのでレビューします。

 

良い点

ターゲット層が明確かつ、そのターゲットに見合ったレベル感

レベル感は購入ページに書いてありますが、「・Dockerを初めて使う方」「・かつ、コマンドラインをさわったことがある方」です。

そのような人が持ちやすい、「Dockerってよく聞くけどどんな機能を持っているの?」「使うとどんなメリットがあるの?」という疑問に簡潔に答えています。

イラストかわいい

Daemonちゃんかわいい。俺も悪魔だと思ってました。わかばちゃんの表情も豊かになったような気がするかわいい。

Dockerを動かせる

入門本らしく、本の内容に従って進めていくと、Dockerを動かすことができます。

改善点

コマンドをたたいても期待通りに動作しない

P21のコマンドを実行したところ、本文中と異なる結果となりました。 f:id:alek3:20180506133053p:plain

ちょっと残念…… ちなみに docker run --rm -it alpine すると起動します。

その他

  • ページ数分かんないなあと思って買ったけどもう一度見たら書いてあった。ポンコツ乙。
  • 28ページのマンガなので良くも悪くもすぐ読み終わる。
  • Docker動かないよーと泣きついたら@HKDnetさんが教えてくれました。ありがとう@HKDnet

ボードゲーム会を再び企画してみた

こちらの記事の続編になります。

alek3.hatenablog.com

第2回を開催しました。

構想

もともと継続的にやっていこうという気持ちで始めた企画ですので、第2回は第1回の終了後すぐに計画し始めました。

前回の反省として、女性率が低いというのがありましたが、今回は主要メンバーに女性が加わり、非常に心強い体制となりました。

準備

ほぼ前回と変わらず、興味ありそうな人に声をかけていました。しかし、その人数は増えました。ブログやTwitterなどの発言に反応してくれる方がそれなりにいて、その方たちにアプローチしていたためです。

ゲームに関しては、やはり僕以外の人たちがめっちゃ所有していて、毎度驚かされています。

当日

12名の方がいらっしゃいました。女性は4名いました。

割とキャパギリギリでした。直前のキャンセル・参加があるなかで、今回の人数に落ち着いたのは幸運でした。

今回はゲーム中の写真を撮ろうと思っていましたが、顔が映っているのしかない*1ので今回も画像なしです。

12名の参加者がいるので、途中から2テーブルに分けて進行しました。メンバーは都度シャッフルしていました。

No. テーブル① テーブル②
インサイダーゲーム(全体)
ハゲタカのえじき タピオカミルクティー、ムッジーナ
ボブジテン、ドブル タイムボム
ペンギンパーティ、ゴキブリポーカー ダイ公望

テーブル①が僕の参加していたテーブルです。

感想としては、No.②ですね。このタームではテーブル②に全女性が集まっていました。(このことは次の反省にも繋がります。)

女性たちが楽しそうに遊んでいるのを横目に僕達が殺伐*2とした戦いを繰り広げるという、なかなか趣のある時間でした。

また、今回はいろんな方がおかしや飲み物をさしいれていただいて感激しました。ちなみに僕もアルフォートを買っていったのですが、別の方とモロ被りしてしまいました。

反省

①狭い

なんとなく感じていましたが、20㎡という会場で12人は狭いという意見がありました。次回以降、広い会場を探すか、人数を絞るか、非常に悩ましいです。

②僕のインストが下手

インサイダーゲームのインストって意外と難しくないですか?

③チーム分けでのアンチパターン

先に断っておくとここは長いです。

ボドゲのプレー人数は多くても8人くらいが上限なので、今回は2テーブルに分けて進行しました。

チームの分け方は、No.②では「ゲームの候補を二つ(ガチとゆるふわ)挙げてやりたい方を選ぶ」、No.③④は「ランダム」でした。

どちらが良い方法かというと、ランダムベースだと思います。逆に、ゲームの候補を二つ出して、やりたい方を選ぶ、という方法はあまり良くないなと思いました。

なぜか?候補に出した二つのゲームはそれぞれ、カウンティングが重要な「ガチ」枠と、見た目もきれいな「ゆるふわ」枠にわけられます。

このとき、参加者*3にとってのメリットとデメリットは以下のとおりです。

  • メリット
    • 自分のやりたいゲームを遊べる
  • デメリット
    • 「やってみたら意外と面白かった」という体験が減る
    • 遊ぶメンバーが偏る
    • メンバーの固定化を招く
    • ガチ側の人はゆるふわゲームはやりたくないのかなと思われる。(またはその逆)

女性参加者の中にはボドゲ自体初めてという方もいらしたので、最初からガチ枠を選ぶ人はあまりいないと思います。結果上記の通りNo.②ではメンバーが偏りました。

一方、No.③ではタイムボムという人狼と似た思考を要求するゲームを、多くのボドゲ未経験者が遊びました。結果として、タイムボムはその日に一番ウケたゲームとなりました。

これには「やってみたら意外と面白かった」という要素が多少なりとも入ったのかなと思います。

まとめ

次回もよりよい企画にしたいですね。

*1:顔が映っていなければ載せて良いのかというのもある。

*2:6人でのハゲタカのえじきは運の要素が強い

*3:主催者の目的も、参加者により楽しんでもらうことです

UIDatePickerからIntを取り出す、およびその逆(Swift4、初心者向け)

最近、Swiftを書き始めました。主にモバイルアプリを動かすための言語なので、いろいろ分からんところが多かったです。

はまったところもいくつかあり、今回は日付について、書こうと思います。

UIDatePicker←→年月日のInt

直接的にはまったところは、UIDatePickerから年月日の値をそれぞれInt型の変数で取り出す、およびその逆です。 結論としては、コードは以下のようになります。

 // Int → Date Picker

let calendar: Calendar = Calendar(identifier: .gregorian) 
let year = 2018 
let month = 2 
let day = 18 

let dateComponent = DateComponents(year: year, month: month, day: day) 
let date = calendar.date(from: dateComponent)! 
dateComponent .setDate(date, animated: false) 
// Date Picker → Int 

let calendar = Calendar(identifier: .gregorian) 
let pickerDate = datePicker.date 
let dateComponents = calendar.dateComponents([.year, .month, .day], from: pickerDate ) 

let year = dateComponents.year! 
let month = dateComponents.month! 
let day = dateComponents.day! 

DateとNSDate

UIDatePickerの使い方をネットでググると、NSDateをセットしろという内容の記事にあたることがあります。 しかし、上記の通りNSDateは使用していませんし、UIDatePickerのsetDateメソッドでも記載がありません。

それもそのはずで、Swift3からはNS〇〇型はおおむねNSをとった〇〇型に移行している感じです。*1

2014年にSwiftが登場して以降、Objective-C→Swiftという流れがあり、Swiftでも毎年のように1→2→3→4とバージョンが上がっています。3から4はそうでもないですが、それ以外は大きな変更です。 ググるときには、Swift3がリリースされた2016年9月*2以降の記事かどうかのチェックが必要だと改めて思いました。