技術とか戦略とか

IT技術者が技術や戦略について書くブログです。

ガチではない人向けのゲーム制作の始め方

ゲーム制作の始め方について調べていたのですが、ゲームシステムの話や売り出しの話が検索結果の上位に挙がり、どうも私のような「そこまで考えていない人」向けの記事ではなかったので、この記事を書きます。
 
私が大事だと思うのは、「ゲームを作ろうと思った動機を改めて確認する」「とりあえず作ってみて身内でテストプレイしてみる」の2点です。
 
1.ゲームを作ろうと思った動機を改めて確認する
 これは、ゲームを作る上でのコンセプトになります。
 ゲームを作っていく上で軸がぶれないようにするために、
 改めて意識する必要があります。
 自発的にゲームを作ろうと思ったのであれば、
 動機は必ずあるはずなので、それを改めて意識するのが重要です。
 
 私の場合は、「戦略的思考を伝えるためにゲームを作りたい」
 というのが動機で、ゲームを作りたいと思っています。
 (ちなみに、まずは会社の同僚等の身近な人に伝えたいと思っています)
 そのゲームは、「グリコゲーム」に毛が生えた程度のもので構いません。
 むしろ、簡単なルールで伝えられるなら、それに越したことはありません。
 
2.とりあえず作ってみて身内でテストプレイしてみる
 私が色々調べている中で一番感銘を受けたのはこの記事です。
 
 ボードゲームを自作してテストプレイするまでの過程  takahirosuzuki.com
 https://takahirosuzuki.com/2018/0924175820
 
 この記事では、100均で紙とビーズを買い(合計300円)、
 紙に何かを書き出し、2時間でテストプレイできる状態にしています。
 そして身内で集まりテストプレイを行い、
 色々なフィードバックやアイデアを得られたそうです。
 
 なお、テストプレイ会では、
 ボードゲームとして製品化できそうな出来のゲームもあったそうです。
 
 ゲーム制作を始めるにはその規模からで良いのだと勇気づけられる記事でした。
 
--------------------
 
私も小学生や中学生の時は、何を思ったのかノートを切り取って適当に絵や数字を書き初め、「カードゲームとは言えない何か」を作り、友人と遊んでいました。
ゲーム制作を始めるには、そのノリが大事なのかもしれないと思いました。

戦略を学ぶ上でのゲームの有用性

戦略の考察が私の趣味なのですが、戦略的思考の有用性を他の人に伝えるにはどうすれば良いのか、ということを最近考えています。
座学も既存のゲームから学ぶのも限界がある、戦略的思考を伝えるためのゲームを制作するのが一番良いのではないか、というのが私なりの結論になりつつあります。
 
例えば、ゲーム理論の混合戦略について伝えたいとします。
当ブログでは「ゲーム理論(二人・二択)の混合戦略の確率を求める」という記事を作成しています。
 
当該の記事では
「相手がどのような確率で選択肢を選んだとしても、全ゲームで得られる平均の利得を一定にすることを意図したものです。長期的な目で見て、利得が下がるリスクを最も軽減できる戦略です。」
と前置きをし、結論を
「リスクの高い選択肢(相手が選ぶ選択肢によって利得が大きく変わる選択肢)を選ぶ確率を少なめに、リスクの低い選択肢(相手が選ぶ選択肢によって利得が大きく変わるらない選択肢)を選ぶ確率を多めにすると、混合戦略に近くなる、と書けます。」
としています。
 
応用性の高い理論なのであえて抽象的に書いているのですが、この記事を読んで、具体的なイメージができるか、現実の意思決定の場面で混合戦略を応用できるようになるのか、は甚だ疑問です。
そもそも具体的に何に役に立つのかを書いていないので、何かしらの理由でゲーム理論を勉強している人以外は興味すら持ってもらえないと思います。
 
そこで、座学ではなく、具体的な場面を通して学べるようにする、というのが有効になってくると思います。
ゲームを通してであれば、そのような具体的な場面を疑似的に作り出すことができます。
 
例えば、ポケモン対戦では混合戦略の考え方が有効な場面が出てくるので、教材になり得ます。
しかし、ポケモン対戦を行うためには最低でも151匹のポケモンと、それらのポケモンの特徴を覚えなければならないので、混合戦略の考え方を学ぶ教材としては明らかにハードルが高すぎます。
 
そこで、混合戦略の考え方を学ぶ上で必要最小限の規模を持ったゲームを自作する、というのが良いのではと思いました。
例えば、「グリコゲーム」は、混合戦略の重要性を学べるゲームとしては必要最小限の規模だと思います。
 
混合戦略の場合はグリコゲームがあるので良いのですが、グリコゲームに相当するゲームがない場合は、それを自作したいと考えています。

java:javaからのOSコマンド呼び出しと注意点

javaのプログラムからOSのコマンドを実行したい場合は、Runtimeクラスのexecメソッドで実現できます。
 
しかし、OSのコマンドは別プロセスで立ち上がるので注意が必要です。
ProcessクラスのwaitForメソッドでプロセスの終了を待たないと、処理が前後してしまい意図しない挙動となることがあります。
また、destroyメソッドでプロセスを明確に終了させ、資源を回収することも重要です。
 
以下は、プロセスの終了を待たないと意図しない挙動となることを確認するためのテストコードです。
javaのプログラムでは、OSのコマンドを使用して、3秒のスリープ後に hoge.txt を aフォルダ から bフォルダ へ移動させています。
waitForメソッドを使用しなかった場合、javaのプログラムが終了した時点で hoge.txt の bフォルダ への移動が完了していない(javaのプログラムが立ちあげたプロセスが終了していない)ことを確認できます。
逆に、waitForメソッドを使用した場合は、javaのプログラムが終了した時点で hoge.txt の bフォルダ への移動が完了している(javaのプログラムが立ちあげたプロセスが終了している)ことを確認できます。
 
【テストコード】
・RuntimeTest.java
public class RuntimeTest {
    public static void main(String args[]){
        try {
            Runtime runtime = Runtime.getRuntime();
            Process p = runtime.exec
                ("cmd /c timeout /t 3 > nul & move a\\hoge.txt b\\");
            p.waitFor(); // プロセス終了を待つ
            p.destroy(); // プロセスを明確に終了させ、資源を回収
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}
 
【実行用バッチ】
・RuntimeTest.bat
rem javaソースのコンパイル
javac RuntimeTest.java

rem モジュール実行前の確認
dir a
dir b

rem モジュール実行
java RuntimeTest

rem モジュール実行後の確認
dir a
dir b

rem モジュール削除
del RuntimeTest.class

rem 処理終了
pause
exit
 
【「p.waitFor();」と「p.destroy();」をコメントアウトした場合の実行結果】
C:\tmp>rem javaソースのコンパイル

C:\tmp>javac RuntimeTest.java

C:\tmp>rem モジュール実行前の確認

C:\tmp>dir a
 ドライブ C のボリューム ラベルは  です
 ボリューム シリアル番号は  です

 C:\tmp\a のディレクト

2019/03/07  22:37    <DIR>          .
2019/03/07  22:37    <DIR>          ..
2019/03/07  22:23                 6 hoge.txt
               1 個のファイル                   6 バイト
               2 個のディレクトリ  19,641,397,248 バイトの空き領域

C:\tmp>dir b
 ドライブ C のボリューム ラベルは  です
 ボリューム シリアル番号は  です

 C:\tmp\b のディレクト

2019/03/07  22:37    <DIR>          .
2019/03/07  22:37    <DIR>          ..
               0 個のファイル                   0 バイト
               2 個のディレクトリ  19,641,397,248 バイトの空き領域

C:\tmp>rem モジュール実行

C:\tmp>java RuntimeTest

C:\tmp>rem モジュール実行後の確認

C:\tmp>dir a
 ドライブ C のボリューム ラベルは  です
 ボリューム シリアル番号は  です

 C:\tmp\a のディレクト

2019/03/07  22:37    <DIR>          .
2019/03/07  22:37    <DIR>          ..
2019/03/07  22:23                 6 hoge.txt
               1 個のファイル                   6 バイト
               2 個のディレクトリ  19,641,401,344 バイトの空き領域

C:\tmp>dir b
 ドライブ C のボリューム ラベルは  です
 ボリューム シリアル番号は  です

 C:\tmp\b のディレクト

2019/03/07  22:37    <DIR>          .
2019/03/07  22:37    <DIR>          ..
               0 個のファイル                   0 バイト
               2 個のディレクトリ  19,641,401,344 バイトの空き領域

C:\tmp>rem モジュール削除

C:\tmp>del RuntimeTest.class

C:\tmp>rem 処理終了

C:\tmp>pause
続行するには何かキーを押してください . . .
 
【「p.waitFor();」と「p.destroy();」を有効にした場合の実行結果】
C:\tmp>rem javaソースのコンパイル

C:\tmp>javac RuntimeTest.java

C:\tmp>rem モジュール実行前の確認

C:\tmp>dir a
 ドライブ C のボリューム ラベルは  です
 ボリューム シリアル番号は  です

 C:\tmp\a のディレクト

2019/03/07  22:43    <DIR>          .
2019/03/07  22:43    <DIR>          ..
2019/03/07  22:23                 6 hoge.txt
               1 個のファイル                   6 バイト
               2 個のディレクトリ  19,639,898,112 バイトの空き領域

C:\tmp>dir b
 ドライブ C のボリューム ラベルは  です
 ボリューム シリアル番号は  です

 C:\tmp\b のディレクト

2019/03/07  22:43    <DIR>          .
2019/03/07  22:43    <DIR>          ..
               0 個のファイル                   0 バイト
               2 個のディレクトリ  19,639,898,112 バイトの空き領域

C:\tmp>rem モジュール実行

C:\tmp>java RuntimeTest

C:\tmp>rem モジュール実行後の確認

C:\tmp>dir a
 ドライブ C のボリューム ラベルは  です
 ボリューム シリアル番号は  です

 C:\tmp\a のディレクト

2019/03/07  22:43    <DIR>          .
2019/03/07  22:43    <DIR>          ..
               0 個のファイル                   0 バイト
               2 個のディレクトリ  19,639,894,016 バイトの空き領域

C:\tmp>dir b
 ドライブ C のボリューム ラベルは  です
 ボリューム シリアル番号は  です

 C:\tmp\b のディレクト

2019/03/07  22:43    <DIR>          .
2019/03/07  22:43    <DIR>          ..
2019/03/07  22:23                 6 hoge.txt
               1 個のファイル                   6 バイト
               2 個のディレクトリ  19,639,894,016 バイトの空き領域

C:\tmp>rem モジュール削除

C:\tmp>del RuntimeTest.class

C:\tmp>rem 処理終了

C:\tmp>pause
続行するには何かキーを押してください . . .

Windowsバッチのfindstr実行と結果判定は1行でまとめられないので代替案提示

言いたいことをまとめると、
WindowsバッチをExcelから生成するため、findstrの実行と結果判定(ERRORLEVELの判定)を1行でやりたかったができなかった。仕方ないのでfindstrと結果判定の間に特殊な記号を入れ、その記号をまとめて改行コードに置換することで対応した。」
です。
 
これで話が通じるのであれば、以降は読まなくて良いです。
 
--------------------
 
実務で「ファイル中に特定の文字列が存在する場合のみ、そのファイルに対して特定の処理を行う」ということをする必要が出てきました。
これは、findstrとif(変数「ERRORLEVEL」を判定)を組み合わせることで実現できます。
具体的には、以下のように実現できます。
 
--------------------
 
【バッチファイル】
・C:\tmp\testOK.bat
rem if文が真になり、ファイルがリネームされる
findstr "hoge" C:\tmp\hoge.txt > NUL
if "%ERRORLEVEL%" == "0" (move C:\tmp\hoge.txt C:\tmp\hoge2.txt)

rem if文が偽になり、ファイルがリネームされる
findstr "hoge" C:\tmp\fuga.txt > NUL
if "%ERRORLEVEL%" == "0" (move C:\tmp\fuga.txt C:\tmp\fuga2.txt)

pause
 
【対象ファイル】
・C:\tmp\hoge.txt
hoge
 
・C:\tmp\fuga.txt
fuga
 
【実行結果】
C:\tmp>rem if文が真になり、ファイルがリネームされる

C:\tmp>findstr "hoge" C:\tmp\hoge.txt  1>NUL

C:\tmp>if "0" == "0" (move C:\tmp\hoge.txt C:\tmp\hoge2.txt )
        1 個のファイルを移動しました。

C:\tmp>rem if文が偽になり、ファイルがリネームされる

C:\tmp>findstr "hoge" C:\tmp\fuga.txt  1>NUL

C:\tmp>if "1" == "0" (move C:\tmp\fuga.txt C:\tmp\fuga2.txt )

C:\tmp>pause
続行するには何かキーを押してください . . .
 
【実行後のファイル】
C:\tmp\hoge.txt は C:\tmp\hoge2.txt へリネーム。
C:\tmp\fuga.txt はそのまま。
 
--------------------
 
問題はここからです。
このfindstrとifのセットは、1000個ぐらい必要です。
Excelにその1000個の条件はまとめられているのですが、手作業で転記していては日が暮れてしまいます。
 
そこで、以下のようにfindstrとifを1行でまとめることで、Excelから簡単に(自動的に)コマンドを作れるようにしました。
しかし、これだと上手く動きませんでした。
理由は、findstrの結果が返ってくるよりも先に、変数「ERRORLEVEL」の中身が展開されてしまうからです。
(そういえばWindowsバッチはそのような挙動でしたね…)
 
--------------------
 
【バッチファイル】
・C:\tmp\testNG.bat
rem if文が真になり、ファイルがリネームされる
findstr "hoge" C:\tmp\hoge.txt > NUL & if "%ERRORLEVEL%" == "0" (move C:\tmp\hoge.txt C:\tmp\hoge2.txt)

rem if文が偽になり、ファイルがリネームされない
rem →「%ERRORLEVEL%」がfindstr実行前に展開されてしまうためリネームされる
findstr "hoge" C:\tmp\fuga.txt > NUL & if "%ERRORLEVEL%" == "0" (move C:\tmp\fuga.txt C:\tmp\fuga2.txt)

pause
 
【対象ファイル】
・C:\tmp\hoge.txt
hoge
 
・C:\tmp\fuga.txt
fuga
 
【実行結果】
C:\tmp>rem if文が真になり、ファイルがリネームされる

C:\tmp>findstr "hoge" C:\tmp\hoge.txt   1>NUL  & if "0" == "0" (move C:\tmp\hoge
.txt C:\tmp\hoge2.txt )
        1 個のファイルを移動しました。

C:\tmp>rem if文が偽になり、ファイルがリネームされない

C:\tmp>rem →「0」がfindstr実行前に展開されてしまうためリネームされる

C:\tmp>findstr "hoge" C:\tmp\fuga.txt   1>NUL  & if "0" == "0" (move C:\tmp\fuga
.txt C:\tmp\fuga2.txt )
        1 個のファイルを移動しました。

C:\tmp>pause
続行するには何かキーを押してください . . .
 
【実行後のファイル】
C:\tmp\hoge.txt は C:\tmp\hoge2.txt へリネーム。
C:\tmp\fuga.txt は C:\tmp\fuga2.txt へリネーム。
 
--------------------
 
結局、バッチファイルの「&」を「\r\n」へ置換することで対応しました。
サクラエディタで1000個一気に置換したので、手作業は免れました。

情報処理技術者試験対策「httpとhttpsの違い」

普通にWebシステムを使う分には
httpsはhttpを暗号化したプロトコルで、盗聴・なりすまし・中間者攻撃の対策になる。認証等の機密性の高いやりとりをWeb上で行う時に使用する。」
というレベルの認識で十分なのですが、応用情報技術者ではもう少し正確な理解が必要な問題が出題されているので、あえて記事にしてみます。
 
【そもそもhttp・httpsとは】
・http
 クライアントとWebサーバが通信する際のプロトコル
 非暗号化通信であり、情報が平文でやりとりされる。
 
https
 httpを暗号化した通信。
 クライアントとWebサーバの間の通信が暗号化される。
 Webサーバ内で処理される通信内容は平文の状態である。
 →どこが暗号化されるのか理解していないと解けない問題が出題されています。
  (応用情報技術者 平成29年春午前問44)
  
httpsの暗号化方式】
共通鍵暗号方式と公開鍵暗号方式を組み合わせた方式を採用しています。
以下の手続きにより暗号化通信を実現します。
 
①クライアントはWebサーバからクライアント証明書を取得する
②クライアント証明書内にある公開鍵を取り出す
③クライアントは共通鍵を生成し、公開鍵で暗号化する
④クライアントは、暗号化した共通鍵をWebサーバへ送信する
⑤Webサーバでは、秘密鍵で暗号化された共通鍵を複合する
⑥両者で共有された共通鍵を用いて、暗号化通信を行う
 
暗号化方式について多少の知識がないとこの文章では理解できないと思うので、その場合は以下のページを見るのをお勧めします。
 
httpsとは?httpとの違いとSSL暗号化通信の仕組み

https://www.ssl.ph/compare/ssl/datalibrary/contents06.html

  
----------------------
目次

https://1drv.ms/b/s!AivF3bzWXOzuhG1Xk5hscKYqkLkM

再現テストの重要性

これも情報処理技術者試験には出題されないのですが、IT技術者が理解しておくべき大事なテスト手法の一つに「再現テスト」があります。
再現テストとは、バグの発生手順を確認するためのテストです。
バグの発生手順が不明確だと、正しい原因にたどり着くことができませんし、その状態で修正を行っても本当にバグが直ったかわかりません(バグが直ったように見えても、それはたまたまかもしれません)。
 
例えば、「会員登録のWeb画面で必要事項を記入し「次へ」ボタンを押下した所、意図せずエラー画面に遷移してしまった」というバグを報告された場合、どの操作に問題があったのかを確認する必要があります。
ある入力項目で許容されない文字が入力されたのかもしれませんし、途中でブラウザの戻るボタンを押下されていてそれが原因なのかもしれません。
原因を特定するために、各入力項目への入力内容や途中の操作を一つずつ変えていきながら、どの入力内容や操作に問題があったのかを特定します。
ここで、「氏名に半角文字が入力された」ことが原因であると特定された場合、これが再現手順となります。
このバグについて、「氏名に半角文字が入力された状態で「次へ」ボタンが押下された場合、会員登録画面に戻り入力内容訂正を求めるメッセージを表示する」という改修を行った場合、改修前のプログラムで氏名に半角文字を入力しバグの再現手順が正しいことを確認した後、改修後のプログラムでも同じ手順を行い、正しい挙動に変更されたことを確認します。
 
余談ですが、性能系のバグやネットワーク系のバグは、原因が複雑でバグを再現できないことが多々あります。
(というか、バグなのか仕様なのかもよくわからない事象もあります)
一般的な話であれば、「性能問題 切り分け」とか「ネットワーク障害 切り分け」とかでググると色々情報が出てきます。
私も性能系のバグやネットワーク系のバグの調査の現場に居合わせ、そこで上位者の判断の過程を聞いて担当者として調査したことが何度かあるので、その経験を活かせる機会があれば活かしたいと思っています。

現新比較~無影響確認の手法~

情報処理技術者試験では出題されないのですが、IT技術者として当然知っておくべきテスト手法として「現新比較」というものがあります。
これは、システムを改修した際に思わぬ箇所に影響が出ていないことを確認する(無影響確認)ための手法であり、改修前の出力と改修後の出力を比較し、改修の影響を受けるべき箇所以外は差異がないことを確認する、というものです。
 
この手法は単体テストからリリース後の確認まで工程を問わず使用される手法です。
例えば、プログラムを製造する場面で、「販売情報管理システムの取引ファイル出力プログラムについて、ポイント払いのレコード(ポイント払いされた場合)にポイントの有効期限を更新するように改修する。それ以外の箇所は変更しない。」という改修を行った場合、単体テストでは「ポイント払いのレコードはポイントの有効期限以外は現新で差異が無いこと」「ポイント払い以外のレコードは現新で差異が無いこと」を検証するべきです。
 
直すべきところだけ直したつもりなのに、知らず知らずの内に他の箇所にも影響していたというのは意外とよくあります。
現新比較をサボると、本来見つかるはずのバグが見つからず、後でバグってめちゃくちゃ怒られます。
システム開発に慣れ始めた頃が危ないです。「この改修で他に影響するわけないだろう」と思わず、現新比較はしっかり行うようにして下さい。
(なぜここまで言うのかというと、私がまさにこのパターンで本番運用でバグを起こしてめちゃくちゃ怒られたからです。。)
 
現新比較の具体的な方法としては、以下のようなものがあります。
 
1.ファイル・テーブル・電文のレコード等、出力が文字列の場合
 ・WindowsのfcコマンドやLinuxのdiffコマンド
  完全一致する場合等、ごく簡単な場合に。
  
 ・WinMerge等の差異比較用のソフトウェア
  1レコードの内の一部が異なっている場合がある等、少し複雑な場合に。
  
 ・Excelサクラエディタ等で作成した独自ツール
  複雑なデータ加工が必要な場合に。
 
2.Windowsで生成した帳票・ハガキ等、出力がPDFファイルの場合
 ・2つのPDFファイルを開き、画面を切り替えて目視
  めちゃくちゃアナログですが、簡単な比較なら結局これが一番早いです。
 
 ・AdobeAcrobatやDiffPDF等のPDF比較用のソフトウェア
  大量のPDFファイルを機械的に比較する必要があるなら必要です。
 
3.Web画面のキャプチャ等、出力が画像の場合
 ・2つの画像を異なるファイルの同じ個所に張り付け、画面を切り替えて目視
  めちゃくちゃアナログですが、簡単な比較なら結局これが一番早いです。
  
 ・ImageMagick等の画像比較用のソフトウェア
  流行りの自動化をするなら必要です。
   参考ページ(Webページの画面キャプチャ比較 - unokun’s blog)
   http://unokun.hatenablog.jp/entry/2015/09/20/191425

 
4.メインフレームで生成した帳票やハガキ等、出力が紙媒体の場合
 ・出力された紙を重ねて透かして目視
  めちゃくちゃアナログですが、これしか手段がない気がします。
  (私が知らないだけかもしれませんが…)