ゲームプログラマーを目指す学生が企業に応募するときは
自作のゲームプログラムを求められることがほとんどだが、
これに加えて筆記試験を受けさせられることがよくある。
最近はWeb試験の一種であるコーディングテストがよく使われていて、
ブラウザ上で直接プログラミングし、
指示された動きをするかをテスト実行した上で提出する。
ただ、このシステム自体に割とクセがあり、
3Dゲームをバリバリ作れる技術があったとしても
コーディングテストで脱落することが多い。
これは普段触っているゲームプログラミングと比べて
あまりに触り心地が違うのが原因と思われ、
その試験で本来問われている内容ではなく
もっと根本的な部分で失敗していたりする。
そこでそういったコーディングテストに挑む前に
準備しておく方がいい基礎知識についてまとめておく。
原始的な入出力処理に慣れておく
ゲームプログラムの出力は画像が原則であり、
タイトルロゴやスコアのような文字も
そういう画像を用意して表示しているだけだ。
また、プレイヤーからの入力はキーボードやマウス、
コントローラーなどを経由して行われるため、
特定のキーが押されているかどうかの判定しかしない。
しかしコーディングテストでは
std::coutとstd::cinあたりの原始的な入出力処理が使われており、
入学当初の授業で扱ったような手法を求められると
使い慣れていないだけにかなり戸惑う。
そこでcinとcoutの基本的な使い方を
しっかり復習しておくことが重要になる。
#include <iostream> void main() { int age; std::cin >> age; if(age >= 18) { std::cout << "大人です" << std::endl; }else{ std::cout << "未成年です" << std::endl; } }
- 「iostream」のインクルードが必要
- 「std::cin >> 変数」でキー入力された情報を変数に代入
- 「std::out << 文字列」「std::out << 変数」で指定した内容を文字表示
- 「std::endl」を出力すると改行
#include <iostream> using namespace std; void main() { int age; cin >> age; if(age >= 18) { cout << "大人です" << endl; }else{ cout << "未成年です" << endl; } }
いちいち「std::」と書かなくていいように
「using namespace std;」が宣言されていることも多い。
データの入出力がうまくできないと
問題の本質部分にまったく挑戦できないので
cinとcoutの使い方をおさらいしておく方がよい。
模擬的なデータが自動でプログラムに渡される
実際にプログラムを実行したときは
数値などのデータを人間が入力する必要があるが、
コーディングテストではそこが自動的に行われるようになっている。
たとえば前述のプログラムは
入力された年齢が成人かどうかを判別するものだが、
この年齢入力の部分が自動で行われるのだ。
また、いろいろな値を入力したパターンが試されるため、
特定の数値のときだけ期待通りの結果になってもダメで、
考えられるいろいろな入力データに対応できている必要がある。
最初に書かれているプログラムを使う必要はない
問題に取り掛かった段階で、ある程度のプログラムが
最初から書かれていることがよくある。
#include <iostream> #include<string> using namespace std; void main() { //ここにプログラムを書きましょう! string str; getline(cin, str); cout << "文字が表示されます" << endl; }
なんとなく、ここに追記するばかりで
もともとのプログラムを書き替えてはいけないような気になるが、
それだと記述できる内容が限定されて逆に苦労する。
#include <iostream> #include<string> using namespace std; void main() { string str; getline(cin, str); cout << atoi(&str[0]) * 10 << endl; }
たとえば数値が入力されるのにstring型で受け取ると
そのままでは数値として利用できなくなる。
そうなると文字列を数値に変換するatoi系の関数や
string型をchar型配列として扱うための
ポインタ表現(またはc_str関数)などを思い出す必要があり、負担が増える。
もともと書かれているのはただのサンプル表記であって
特に気にせず削除してしまって構わないし、
その方が圧倒的に楽に解決することがある。
#include <iostream> using namespace std; void main() { int no; cin >> no; cout << no * 10 << endl; }
入力されるものが数値に限られるなら
そのままint型の変数で受け取った方が楽だ。
余計なことで悩まなくて済むよう、
最初に書いてある内容は自由に削除していいと認識すべきだ。
複数の入力データの扱いに慣れておく
ひとつの数値だけが入力されるのではなく、
複数のデータがスペース区切りで入力されることがある。
その際はcin関数に複数の変数を指定することができる。
#include <iostream> using namespace std; void main() { int math, sci, eng; cin >> math >> sci >> eng; cout << "合計得点は" << ( math + sci + eng ) << endl; }
これだけで3つの値が3つの変数に入ってくれる。
下手にgetline関数などで受け取ってしまうと、
3つの数値を含む連結された文字列を
スペースごとに区切って取り出す必要が出てくるので
それだけでかなり複雑な処理になってしまう。
単にcinを連続して使うだけでいいことは覚えておいた方がよい。
入力データの個数が変化する場合への対応
よくあるのが入力データの個数が変わる場合だ。
たとえば最初に人数を入力させ、
そのあと各自のデータを入力させる場合などは
可変長配列クラスであるstd::vectorなどを利用するとよい。
#include <iostream> #include <vector> using namespace std; void main() { //人数を取得 int num; cin >> num; //人数分のデータを取得 vector<int> income(num); for(int i = 0; i < num; i++) { cin >> income[i]; } //ソート for(int i = 0; i < num - 1; i++) { for(int k = i + 1; k < num; k++) { if(income[i] < income[k]) { int tmp = income[i]; income[i] = income[k]; income[k] = tmp; } } } cout << "高い順に表示" << endl; for(int i = 0; i < num; i++) { cout << income[i] << endl; } }
- 「vector」のインクルードが必要
- 「vector<型> 変数名(個数)」で指定された型の配列を指定された個数分宣言できる
ソート処理が必要になる問題も多いので、
一番簡単なバブルソートの処理を覚えておくと役立つ。
文字列の扱いにも慣れておく
入力データが文字列であることも多いので
std::stringの扱いにも慣れておく方がよい。
#include <iostream> #include <string> using namespace std; void main() { string name; cin >> name; //逆から表示 for(int i = name.size() - 1; i >= 0; i--) { cout << name[i]; } }
- 「string」のインクルードが必要
- 文字数はsize関数で取得
- 末端を示す「¥0」のために1文字使われる
- 入力データは半角文字限定の場合が多い
#include <iostream> #include <string> using namespace std; void main() { int num; cin >> num; string str; str = "入力値は" + to_string(num) + "です"; cout << str; }
- 数値をstring型として扱う場合はto_string関数を使う
#include <iostream> #include<string> using namespace std; void main() { string str; cin >> str; int num; num = atoi(&str[0]); num *= 10; cout << num << endl; }
- string型を数値扱いしたい場合は「&変数名[0]」でchar型ポインタを取り出してatoi関数に渡す
項目別の集計が必要な場合への対応
入力された項目の出現数を数えるなど、
項目別の管理が必要な場合は
連想配列クラスであるstd::mapを利用するとよい。
#include <iostream> #include <map> using namespace std; int main(void){ int num; cin >> num; map<int, int> list; //キーと値の型は自由に設定可能 for(int i = 0; i < num; i++) { int tmpNo; cin >> tmpNo; if(list.find(tmpNo) == list.end()) //キーが存在しない { list[tmpNo] = 1; //新たなキーを追加 }else{ list[tmpNo]++; } } for(auto itr = list.begin(); itr != list.end(); ++itr) { cout << itr->first << "の出現数は" << itr->second << endl; } }
- 「map」のインクルードが必要
- find関数でend()が返されたら該当項目は記録されていない
- 各項目を順に処理していくときはbegin関数でイテレータを取得する
- イテレータのfirstがキー(項目名)、secondが値
Visual Studioにコマンドプロンプトが付属している
実際にこういった原始的なプログラムを試したい場合、
Microsoft Visual Studioをインストールすれば
セットでコマンドプロンプトも付いてくる。
Windowsのスタートメニューの中のVisual Studioフォルダにある
「Developer Command Prompt for VS」を起動。
真っ黒なウィンドウが開くので
cdコマンドで適当なフォルダに移動する。
C:\cpp>cl/EHsc test.cpp Microsoft(R) C/C++ Optimizing Compiler Version 19.34.31933 for x86 Copyright (C) Microsoft Corporation. All rights reserved. test.cpp Microsoft (R) Incremental Linker Version 14.34.31933.0 Copyright (C) Microsoft Corporation. All rights reserved. /out:test.exe test.obj C:\cpp>test 40 大人です C:\cpp>
あとは「cl/EHsc ファイル名」で対象ファイルをコンパイル。
エラーが出なければ実行ファイルが作られるので、
実行した上で適当な値を入力して結果を確認できる。
paizaなら無料で実践トレーニングができる
コーディングテストのシステムに慣れるためにも
実践環境で訓練するのが一番だが、
無料で試せる中ではpaizaが最適だろう。
会員登録は必要だが、大量の問題が用意されており、
さまざまなプログラミング言語に対応している。
Dランク問題は非常に単純なプログラムで済むので
まずはこれでシステムに慣れたあと、
就活生ならとりあえずCランク問題まで解けるようになっておきたい。
まとめ
私自身がpaizaの問題を数十問ほど解いてみて
その中で必要になった知識やポイントをまとめてみた。
問題が問おうとしている本質的な部分がわからないならともかく、
単にコーディングテストに不慣れなせいで
本来の能力が発揮できずに不合格になるのはもったいないので、
ゲームプログラマー志望であっても
上記のような知識を身につけておく方が安全だろう。