これは2023年10月に部内向けに書いたブログを外部公開向けに書き直したものです。
はじめに
こんにちは。koukawa_ppです。
さて、今回はヤケクソなタイピングゲームを作るというタイトルで、ブログを書きます。
開発言語はPythonです。
ここでは、以下のものを作ります。
- ゲーム本体
- タイピングゲームのTASツール
また、コードは こちらの GitHub リポジトリ にて公開しております。
開発環境
- Windows 10 Home 64bit
- Python 3.11.4
- Visual Studio Code
作ることになったいきさつ
まずそもそもタイピングゲームとは、皆さんご存じの通り、ある文章を出され、それをいかに早く正確に打ち込めるかを楽しむゲームです。
まあでもタイピングゲームが得意な方なら、この手のシンプルなタイピングゲームはまあ瞬殺でしょう。
退屈していらっしゃるのではないでしょうか。
そうするとシンプルなタイピングゲームを作成するのは野暮というもの。
そのような中で、このタイピングゲームが得意な方でもタイプが遅くなるようなチャレンジングなタイピングゲームを作れないだろうか。
このような考えのもと、この企画を考えました。
ぶっちゃけて言うと、正道では対抗できそうにありません。
そこで、何か普通のタイピングゲームより難しい何か、を作ることを考えました。
ここで、以下のような工夫点を導入したタイピングゲームを作りました。
- 文字列をランダムにする
- 特殊文字を入れるようにする
- シーザー暗号を導入する
まず最初の要素によって、「このような組み合わせはよく出てくるな」や、打ちなれているキーだけでできるタイピングゲームを排除します。
次に、特殊文字を入れることにより、あたかも複雑なパスワードを入力しているように感じさせます。
これら二つの要素は、ひょっとするとどこかのタイピングゲームにあるかもしれませんが、最後の要素を導入することで、多分他にはないタイピングゲームを完成させました。
最後の「シーザー暗号を導入する」とは、以下のようなものです。
eznoafowe (2)
とあったら、これら各々の文字を2つ後ろにずらして入力する必要があるということです。
つまりこの場合は、
gbpqchqyg
と入力する必要があるわけです。
つまりこのタイピングゲームは、タイピング速度もそこそこに、アルファベットの順番を即座にずらせることも求めたものなのです。
ゲームで遊ぶ
venv を作成する
まず、今回のプログラムでは pyyaml というサードパーティ製ライブラリが必要ですので、それをインストールする仮想環境 (venv) を用意します。
今回は typing_env という名称の仮想環境を作ります。
python -m venv typing_env
そしてこれを起動します。
./typing_env/Scripts/activate
もし Linux や、または macOS もそうだったと思うのですがその場合は、
source typing_env/bin/activate
とする必要があります。
そうすると、このような感じになります。
(typing_env) PS [directory name]
環境をアクティベートしたら、pip でライブラリをインストールします。
pip install pyyaml
これでいったん仮想環境は完成です。
configファイルを作成する
では次に、conffigファイルを作成します。
configファイルはyamlファイルで提供しており、この内容を変えることでゲームの設定を変えることができます。
game_config.yamlnum_problems: 10
min_chars_length: 20
max_chars_length: 30
contain_capital_char: true
contain_number: false
# If you want problems to contain special char, you have to set.
# Otherwise, set null
contain_special_char:
- null
caesar: 0
random_caesar: false
not_negative: true
初期設定としてはこんな感じだと思います。
各々について説明します。
| 名前 | 初期値 | 説明 |
|---|---|---|
| num_problems | 10 | 問題数を表します。 |
| min_chars_length | 20 | 問題の最小文字数を表します。 |
| max_chars_length | 30 | 問題の最大文字数を表します。 |
| contain_capital_char | true | 問題にアルファベット大文字を含むかを表します。 |
| contain_number | false | 問題に算用数字を含むかを表します。 |
| contain_special_char | null | 問題に含む特殊文字を、リスト形式で表してください。 |
| caesar | 0 | シーザー暗号において、何文字ずらすかの最大値を表します。0の場合はシーザー暗号形式の問題を出題しません。特殊文字を入れたい場合は0に設定してください。 |
| random_caesar | false | この値がtrueのとき、not_negativeの値によって何文字ずらすかの値の範囲を決定します。not_negativeがtrueなら、0以上caesar以下の値にして、not_negativeがfalseなら、-caesar以上caesar以下の値で文字をずらします。 |
| not_negative | true | random_caesarの説明の通りです。 |
この部分を変更して、遊んでみてください。
実際に動かす
では、以下のようにしてプログラムを実行してください。
python yakekuso_typing.py
そうすると、始まります。
(typing_env) PS [directory name]> python .\yakekuso_typing.py
press Enter to start.
1 onEhBqIsdDbxGLcskUThOiK
>>> onEhBqIsdDbxGLcskUThOiK
2 DqxMHGXdneoacvZBmqQuUkuKmw
>>> DqxMHGXdneoacvZBmqQuUkuKmw
3 GnlJjOpBsiHxAdYsrObjLCxVFUpc
>>> GnlJjOpBsiHxAdYsrObjLCxVFUpc
4 cLXctVjCSZPehUEPBmPmGeUiXH
>>> cLXctVjCSZPehUEPBmPmGeUiXH
5 RXnkbMTSGvuDVoyyZLZqilL
>>> RXnkbMTSGvuDVoyyZLZqilL
6 FKuUavxxRPTRhKybsdtmJ
>>> FKuUavxxRPTRhKybsdtmJ
7 RrGVvVbYLgBrveHnIStyzuILto
>>> RrGVvVbYLgBrveHnIStyzuILto
8 YwMhVThewpHiJxZigwsJG
>>> YwMhVThewpHiJxZigwsJG
9 kRdaNZRnmMyRaXaQVIQINaf
>>> kRdaNZRnmMyRaXaQVIQINaf
10 faBdlXTMBGFJzicJWOLP
>>> faBdlXTMBGFJzicJWOLP
Spent time: 91.1295325756073
2.601 types per second.
(typing_env) PS [directory name]>
プレイにかかった時間はEnterを押してからカウントされるので、
準備ができたらEnterを押すという形でOKです。
シーザー暗号のパターンもできます。
game_config.yaml# omitted
caesar: 2
random_caesar: true
not_negative: true
このようにconfigファイルを変更して、実行してみてください。
(typing_env) PS [directory_name]> python .\yakekuso_typing.py
press Enter to start.
1 QXXORCCWKlKtThBSQOquYSQAfZYW (1)
>>> RYYPSDDXLmLuUiCTRPrvZTRBgAZX
2 TmSKfJbZUCxpvJlBnFMPdJTrkm (2)
>>> VoUMhLdBWEzrxLnDpHORfLVtmo
3 NtrQMpnVTwmgoGZADRPWddC (0)
>>> NtrQMpnVTwmgoGZADRPWddC
4 DeyxfmYDWTWPherccZKvfYsLm (2)
>>> FgazhoAFYVYRjgteeBMxhAuNo
5 TuwjoLtzqhRtvbdQCRfolDUl (2)
>>> VwylqNvbsjTvxdfSEThqnFWn
6 cwZdDkVSbCJvNWfNbFEaiqxoS (2)
>>> eyBfFmXUdELxPYhPdHGckszqU
7 YllpIgYwwCoNXFNItGmIcx (1)
>>> ZmmqJhZxxDpOYGOJuHnJdy
8 dVPCvUpIvNYTuJhAUewG (1)
>>> eWQDwVqJwOZUvKiBVfxH
9 qmCwtKihENzegpBomAWrQzykzBhkLH (1)
>>> rnDxuLjiFOafhqCpnBXsRazlaCilMI
10 YIWRSszClsfPoeZYDpremakA (0)
>>> YIWRSszClsfPoeZYDpremakA
Spent time: 372.90026021003723
0.662 types per second.
(typing_env) PS [directory_name]>
なぜタイピングの問題10問で6分も掛けなければならないのか、という話ですが、これ相当難しいです。
日ごろから任意の英文について文字ずらしをしていれば出来たかもしれませんが、そんな毎日毎日暗号化したい英文なんて扱うわけがないですから。
(というか今シーザー暗号してもすぐバレる)
ただとりあえず、うまくシーザー暗号のように文字ずらしができていることが分かります。
ぜひいろいろなconfigにして、試してみてください。
TASツールを作る
さて、タイピングゲームとなれば、よく使われるのはTASツールです。
しかもオープンソースのタイピングゲームみたいなものですから、アルゴリズムも丸わかりです。
そうなると、最速でクリアしたいという感想が出てくるのは当たりまえです。
無論人力で最速を目指せればそれもすごいですが、TASツールを作るのもまた一つの手だと思います。
次のようなコードを作成しました。
tas_typing_game.py# Reference:
# https://qiita.com/HidKamiya/items/e192a55371a2961ca8a4#subprocesspopen%E3%81%AB%E3%82%88%E3%82%8B%E8%87%AA%E7%94%B1%E5%BA%A6%E3%81%AE%E9%AB%98%E3%81%84%E5%87%A6%E7%90%86
import re
import subprocess
from yakekuso_typing import caesar_encrypt
if __name__ == '__main__':
p = subprocess.Popen(['typing_env/Scripts/python.exe', 'yakekuso_typing.py'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
encoding='utf8')
p.stdin.write('\n')
p.stdin.flush()
while p.poll() is None:
line = p.stdout.readline().strip()
if re.search('press Enter to', line):
p.stdin.write('\n')
p.stdin.flush()
elif re.search('Spent time', line) or re.search('types per second', line):
print(line, flush=True)
p.stdin.write('print()\n')
p.stdin.flush()
elif re.search('[0-9][0-9\s][0-9\s] (\S+) \([\-0-9]+\)', line):
print(line, flush=True)
m = re.search('([0-9][0-9\s][0-9\s]) (\S+) \(([\-0-9]+)\)', line)
p.stdin.write(f'{caesar_encrypt(m.group(2), int(m.group(3)))}\n')
p.stdin.flush()
elif re.search('[0-9][0-9\s][0-9\s] (\S+)', line):
print(line, flush=True)
m = re.search('([0-9][0-9\s][0-9\s]) (\S+)', line)
p.stdin.write(f'{m.group(2)}\n')
p.stdin.flush()
今回は subprocess という標準ライブラリを使っています。
これを使うことで、このPythonプログラムを実行しながら、他のプログラムを別プロセスで実行できます。
また、reは、正規表現を扱うためのライブラリです。
Regular Expression の略です。
また、yakekuso_typing.pyからシーザー暗号で暗号化する関数をインポートしています。
ソースコードをそのまま保存しているので、簡単に再利用できます。
さて、実行においては yaml が必要なので、これまでと同様 typing_env 内で実行してください。
(typing_env) PS [directory name]> python .\tas_typing_game.py
>>> 1 vYfBBhgPBIrHEApzddZJlWO (2)
>>> 2 nycYSUdOjGrVYhNqKyzULNNQILz (1)
>>> 3 YwezVOGnscquhFrbFKFukvydOZgpVa (0)
>>> 4 DCVqjKxsgaVdDggsfxcPtYu (1)
>>> 5 CdKVamkVelTcJqYfBtOAUItzLEoAO (0)
>>> 6 dhAVcJTEbKLCChYDTvOGemH (0)
>>> 7 juIZbrkwWrZvBNBSagdYDvMI (2)
>>> 8 vCiGCzAVWGBASuJSQLWnGOiM (0)
>>> 9 DvUsENKbVrZdsoczGaVagEQIv (1)
>>> 10 BSJcmfjmvoEIuIygfmyaAnYkLZqdD (1)
Spent time: 0.00768733024597168
33431.633 types per second.
(typing_env) PS [directory_name]>
こんな感じで出てきます。
平均して一秒あたり33431回ほどタイプしていることになっていることが分かります。
ちなみに config で caesar を0にしたとき、
tas_typing_game.pyは以下のような感じで実行できます。
(typing_env) PS [directory name]> python .\tas_typing_game.py
>>> 1 SgzxWXQVOAyJYDOJXXAWxh
>>> 2 tDevbinTnlfxSvSKmkptYYZ
>>> 3 dnWLvBhusCwsmeBSXalSjVpircjoO
>>> 4 EdFNZcrsVoDZuxbKmltS
>>> 5 zFTmkzrpIWeRFwzMgtRsaAZi
>>> 6 IRvROZVmKRyFhPMrlRqkuTmKwCFW
>>> 7 VToRbXqNYizmRHMpomehdrTnhlH
>>> 8 OHMSWCVhGPGqZsnPBuHtBU
>>> 9 fXWJrPUMJECsvRlbxajwL
>>> 10 lYgJSVgSOwCUKoVjSJCgV
Spent time: 0.0046956539154052734
50472.204 types per second.
(typing_env) PS [directory name]>
ここでは caesar_encrypt などを動かす必要が無くなるので、
実行速度がまた速くなります。
平均して一秒あたり50472回ほどタイプしていることになっていることが分かります。
体験版
以下に今回のタイピングゲームで、文字がズレるバージョンを実装いたしました。
このバージョンのコードも GitHub に上げておりますので、よろしければご覧ください。
時間などは測定しておりません。
下の入力欄には0以上3以下の数字を入力できます。最大この文字数分だけずれます。
入力欄において数字を入力したら、「変更」ボタンを押すことでその範囲内で出題されます。
おわりに
本日はタイピングゲームを作り、紹介してきました。
ぜひプレイして楽しんでください。
最後までお読みいただき、ありがとうございました。