今回はこれまでの学習を活かして「じゃんけんゲーム」を作りましょう。
僕が学生の頃は課題として提出しろって言われました。今は知りません。
じゃんけんゲームの仕様
最低限の仕様は以下です。
ランダムな値を発生させる方法
CPU側の手を決めるためにランダムな値が必要になります。ちなみにプログラムではランダムな値を乱数と呼びます。
この乱数ですが、若干クラスの知識を必要とするため、今回は記述だけ伝えます。深く考えず、このまま使ってください。
Random random = new System.Random();
int v = random.Next(0, 3); // 0から2の乱数を作る
0以上で3未満の乱数を作る部分に注意してください。
この記述で0, 1, 2の乱数が得られます。これでグー、チョキ、パーが表現できますよ。
実践練習
という事で、早速作ってください。Let's try!
時間が掛かってもいいから完成させよう!
解答例
数学と同じで答えに辿り着くプログラムは無限にあります。なので、これは一例です。
クリックして解答例を見る。
namespace Sample
{
internal class Program
{
// じゃんけんの手を表現するenum型
enum RockPaperScissors
{
Rock,
Scissors,
Paper,
}
static void Main(string[] args)
{
// じゃんけんの勝敗テーブル
// p1がp2に対して勝ったか負けたかを表す
// [p1, p2] = 1(勝) or 0(分) or -1(負)
//
// RockPaperScissors型と連動する。
// [p1, p2] = [p1のRockPaperScissors型, p2のRockPaperScissors型]
//
// ※ グー、チョキ、パーの組み合わせを多次元配列で表現
//
int[,] winLoseTable = new int[,]
{
{ 0, 1, -1 },
{ -1, 0, 1 },
{ 1, -1, 0 },
};
// 勝利数
int playerWin = 0;
int cpuWin = 0;
// ゲームループ
while (true)
{
Console.WriteLine("");
Console.WriteLine("============================================================");
Console.WriteLine($"[成績] Player: {playerWin}勝 vs CPU: {cpuWin}勝");
Console.WriteLine("じゃんけん! ('G':グー | 'C':チョキ | 'P':パー | 'E':終了)");
// 入力受付
string input = Console.ReadLine();
// 1文字以外はやり直し
if (input.Length != 1)
{
Console.WriteLine("ちゃんと入力して!");
continue;
}
// プレイヤー側の手をRockPaperScissors型にする。
RockPaperScissors playerInput;
switch (input[0])
{
// グー
case 'G': // 大文字
case 'g': // 小文字
playerInput = RockPaperScissors.Rock;
break;
// チョキ
case 'C': // 大文字
case 'c': // 小文字
playerInput = RockPaperScissors.Scissors;
break;
// パー
case 'P': // 大文字
case 'p': // 小文字
playerInput = RockPaperScissors.Paper;
break;
// 終了
case 'E': // 大文字
case 'e': // 小文字
goto GAME_END;
// 上記以外はNG
default:
Console.WriteLine("ちゃんと入力して!");
continue;
}
// 乱数でCPUの手を決定
Random random = new System.Random();
RockPaperScissors cpuInput = (RockPaperScissors)random.Next(0, 3);
switch (cpuInput)
{
case RockPaperScissors.Rock:
Console.WriteLine("ぽん! グー!");
break;
case RockPaperScissors.Scissors:
Console.WriteLine("ぽん! チョキ!");
break;
case RockPaperScissors.Paper:
Console.WriteLine("ぽん! パー!");
break;
}
// 勝敗の判定
int judgement = winLoseTable[(int)playerInput, (int)cpuInput];
if (judgement > 0)
{
playerWin++;
Console.WriteLine("あたなの勝ち!");
}
else if (judgement < 0)
{
cpuWin++;
Console.WriteLine("あたなの負け!");
}
else
{
Console.WriteLine("あいこ!");
}
}
GAME_END: ;
// 終了表示
Console.WriteLine("============================================================");
Console.WriteLine($"ゲームを終了しました。対戦結果は以下です。");
Console.WriteLine($"Player: {playerWin}勝");
Console.WriteLine($"CPU : {cpuWin}勝");
// 入力待ち
Console.WriteLine($"ゲームを終了しました。何か入力すると画面を閉じます。");
Console.ReadLine();
}
}
}
そんなに長くないと思いませんか? 実処理だけなら100行くらいかな。
これで解説が終わってしまうとキレられそうなので、僕ならどうやって作るかを話しますか。
普通の人は簡単にキレませんよ。
全体の設計
まず最初にやるのは全体の設計です。
僕は勝手にコメントプログラミングとか呼んでますが、コメントで大枠を作ります。
namespace Sample
{
internal class Program
{
static void Main(string[] args)
{
// ゲームループ
while (true)
{
// 入力受付
// どうやってループを脱出するか考える
// プレイヤー側の手
// 乱数でCPUの手
// 勝敗の判定
}
// 終了表示
}
}
}
これ凄く大切です。ジグソーパズルを外枠から作る人、きっとプログラミング向いてますよ。
最初は各種機能なんてどうでもいいので全体を考えましょう。
必要そうな変数や型を用意する
ここで独自型が必要なら作ります。今回はグー、チョキ、パーを表現するenum型を作りました。
後は分かってる限りの変数を記述しておきます。この時に変数のスコープが意識できるとベストです。
namespace Sample
{
internal class Program
{
// じゃんけんの手を表現するenum型
enum RockPaperScissors
{
Rock,
Scissors,
Paper,
}
static void Main(string[] args)
{
// 勝利数
int playerWin = 0;
int cpuWin = 0;
// ゲームループ
while (true)
{
// 入力受付
string input = Console.ReadLine();
// プレイヤー側の手
RockPaperScissors playerInput;
// 乱数でCPUの手を決定
Random random = new System.Random();
RockPaperScissors cpuInput = (RockPaperScissors)random.Next(0, 3);
// 勝敗の判定
}
}
}
}
英語でじゃんけんはRockPaperScissorsって言うんだって。でも、日本語の順番だとグーチョキパーじゃん。
最初はenum型をRock, Paper, Scissorsの順番にしたんだけど、使いずれぇぇぇって感じにキレた。
長年染み付いた癖は簡単に抜けない。
可能な限り実装する
お互いの入力処理とか、実装できる部分は全部実装します。
ループを抜ける処理は考えてないので、ループを継続するように変えておきます。
namespace Sample
{
internal class Program
{
// じゃんけんの手を表現するenum型
enum RockPaperScissors
{
Rock,
Scissors,
Paper,
}
static void Main(string[] args)
{
// 勝利数
int playerWin = 0;
int cpuWin = 0;
// ゲームループ
while (true)
{
// 入力受付
string input = Console.ReadLine();
// 1文字以外はやり直し
if (input.Length != 1)
{
Console.WriteLine("ちゃんと入力して!");
continue;
}
// プレイヤー側の手をRockPaperScissors型にする。
RockPaperScissors playerInput;
switch (input[0])
{
// グー
case 'G': // 大文字
case 'g': // 小文字
playerInput = RockPaperScissors.Rock;
break;
// チョキ
case 'C': // 大文字
case 'c': // 小文字
playerInput = RockPaperScissors.Scissors;
break;
// パー
case 'P': // 大文字
case 'p': // 小文字
playerInput = RockPaperScissors.Paper;
break;
// 終了
case 'E': // 大文字
case 'e': // 小文字
continue; // 暫定処置
// 上記以外はNG
default:
Console.WriteLine("ちゃんと入力して!");
continue;
}
// 乱数でCPUの手を決定
Random random = new System.Random();
RockPaperScissors cpuInput = (RockPaperScissors)random.Next(0, 3);
switch (cpuInput)
{
case RockPaperScissors.Rock:
Console.WriteLine("ぽん! グー!");
break;
case RockPaperScissors.Scissors:
Console.WriteLine("ぽん! チョキ!");
break;
case RockPaperScissors.Paper:
Console.WriteLine("ぽん! パー!");
break;
}
// 勝敗の判定
}
}
}
}
無限ループを抜ける方法を考える
次はどうやったら無限ループを抜けてゲームを終了できるか考えます。
一般的にはゲームフラグを使って真偽値で判定することもありますが、それだと変数が増えるからgoto文を使いました。
namespace Sample
{
internal class Program
{
// じゃんけんの手を表現するenum型
enum RockPaperScissors
{
Rock,
Scissors,
Paper,
}
static void Main(string[] args)
{
// 勝利数
int playerWin = 0;
int cpuWin = 0;
// ゲームループ
while (true)
{
// 入力受付
string input = Console.ReadLine();
// 1文字以外はやり直し
if (input.Length != 1)
{
Console.WriteLine("ちゃんと入力して!");
continue;
}
// プレイヤー側の手をRockPaperScissors型にする。
RockPaperScissors playerInput;
switch (input[0])
{
// グー
case 'G': // 大文字
case 'g': // 小文字
playerInput = RockPaperScissors.Rock;
break;
// チョキ
case 'C': // 大文字
case 'c': // 小文字
playerInput = RockPaperScissors.Scissors;
break;
// パー
case 'P': // 大文字
case 'p': // 小文字
playerInput = RockPaperScissors.Paper;
break;
// 終了
case 'E': // 大文字
case 'e': // 小文字
goto GAME_END;
// 上記以外はNG
default:
Console.WriteLine("ちゃんと入力して!");
continue;
}
// 乱数でCPUの手を決定
Random random = new System.Random();
RockPaperScissors cpuInput = (RockPaperScissors)random.Next(0, 3);
switch (cpuInput)
{
case RockPaperScissors.Rock:
Console.WriteLine("ぽん! グー!");
break;
case RockPaperScissors.Scissors:
Console.WriteLine("ぽん! チョキ!");
break;
case RockPaperScissors.Paper:
Console.WriteLine("ぽん! パー!");
break;
}
// 勝敗の判定
}
GAME_END:;
// 入力待ち
Console.WriteLine($"ゲームを終了しました。何か入力すると画面を閉じます。");
Console.ReadLine();
}
}
}
こういう感じに利用するgoto文は全く問題ないと思います。もし文句つけるやつ居たらアンチなので中指立ててください。
やめて!
ここでは繰り返し処理で利用するテクニックの無限ループを学習します。無限ループはC#に限った話じゃなく、よくある系ロジックなので全言語で使えます。 無限ループ 名前の通りループ内の処理を無限に繰り返します。for文かwhile文を利用して記述するので、実際のコードを見てみましょう。これを実行すると処理が完了せず、色々めんどうなことになるので実行はしないでください。 for文で無限ループ 終了条件を記述しないことで無限ループにします。なので、初期化と反復式は記述しても...
ここでは最後のJump statementのgoto文について学びましょう。 goto statement (ステートメント) このgoto文とは、全ての制約を無視して指定したラベルまでジャンプ(移動)できるヤバい構文です。恐らく否定的な意見のほうが多く、僕もそうでしたが学校の授業なら100%使うなって教わります。 何故でしょうか? それはプログラムの基本構造を無視して動作するからです。では、実際にサンプルコードで動きを見てみましょう。 namespace Sam...
勝敗の判定をどうするか考える
このプログラムで1番考えるところですね。正直、気合のif文で全パターンを書いてもいいです。
僕が勝敗を配列でまとめたのは、よくあるパターンで仕組みを知ってたから。
namespace Sample
{
internal class Program
{
// じゃんけんの手を表現するenum型
enum RockPaperScissors
{
Rock,
Scissors,
Paper,
}
static void Main(string[] args)
{
// じゃんけんの勝敗テーブル
// p1がp2に対して勝ったか負けたかを表す
// [p1, p2] = 1(勝) or 0(分) or -1(負)
//
// RockPaperScissors型と連動する。
// [p1, p2] = [p1のRockPaperScissors型, p2のRockPaperScissors型]
//
// ※ グー、チョキ、パーの組み合わせを多次元配列で表現
//
int[,] winLoseTable = new int[,]
{
{ 0, 1, -1 },
{ -1, 0, 1 },
{ 1, -1, 0 },
};
// 勝利数
int playerWin = 0;
int cpuWin = 0;
// ゲームループ
while (true)
{
// 入力受付
string input = Console.ReadLine();
// 1文字以外はやり直し
if (input.Length != 1)
{
Console.WriteLine("ちゃんと入力して!");
continue;
}
// プレイヤー側の手をRockPaperScissors型にする。
RockPaperScissors playerInput;
switch (input[0])
{
// グー
case 'G': // 大文字
case 'g': // 小文字
playerInput = RockPaperScissors.Rock;
break;
// チョキ
case 'C': // 大文字
case 'c': // 小文字
playerInput = RockPaperScissors.Scissors;
break;
// パー
case 'P': // 大文字
case 'p': // 小文字
playerInput = RockPaperScissors.Paper;
break;
// 終了
case 'E': // 大文字
case 'e': // 小文字
goto GAME_END;
// 上記以外はNG
default:
Console.WriteLine("ちゃんと入力して!");
continue;
}
// 乱数でCPUの手を決定
Random random = new System.Random();
RockPaperScissors cpuInput = (RockPaperScissors)random.Next(0, 3);
switch (cpuInput)
{
case RockPaperScissors.Rock:
Console.WriteLine("ぽん! グー!");
break;
case RockPaperScissors.Scissors:
Console.WriteLine("ぽん! チョキ!");
break;
case RockPaperScissors.Paper:
Console.WriteLine("ぽん! パー!");
break;
}
// 勝敗の判定
int judgement = winLoseTable[(int)playerInput, (int)cpuInput];
if (judgement > 0)
{
playerWin++;
Console.WriteLine("あたなの勝ち!");
}
else if (judgement < 0)
{
cpuWin++;
Console.WriteLine("あたなの負け!");
}
else
{
Console.WriteLine("あいこ!");
}
}
GAME_END:;
// 入力待ち
Console.WriteLine($"ゲームを終了しました。何か入力すると画面を閉じます。");
Console.ReadLine();
}
}
}
プログラミングって結構覚えゲーです。たくさん経験すると、その時に使いたいコードが浮かびます。
たぶん、大抵の仕事やスポーツもそうでしょう。知識は財産。頑張りましょう。
表示を整える
最後は表示を整えて完成です。内容は最初と同じですが載せておきます。
namespace Sample
{
internal class Program
{
// じゃんけんの手を表現するenum型
enum RockPaperScissors
{
Rock,
Scissors,
Paper,
}
static void Main(string[] args)
{
// じゃんけんの勝敗テーブル
// p1がp2に対して勝ったか負けたかを表す
// [p1, p2] = 1(勝) or 0(分) or -1(負)
//
// RockPaperScissors型と連動する。
// [p1, p2] = [p1のRockPaperScissors型, p2のRockPaperScissors型]
//
// ※ グー、チョキ、パーの組み合わせを多次元配列で表現
//
int[,] winLoseTable = new int[,]
{
{ 0, 1, -1 },
{ -1, 0, 1 },
{ 1, -1, 0 },
};
// 勝利数
int playerWin = 0;
int cpuWin = 0;
// ゲームループ
while (true)
{
Console.WriteLine("");
Console.WriteLine("============================================================");
Console.WriteLine($"[成績] Player: {playerWin}勝 vs CPU: {cpuWin}勝");
Console.WriteLine("じゃんけん! ('G':グー | 'C':チョキ | 'P':パー | 'E':終了)");
// 入力受付
string input = Console.ReadLine();
// 1文字以外はやり直し
if (input.Length != 1)
{
Console.WriteLine("ちゃんと入力して!");
continue;
}
// プレイヤー側の手をRockPaperScissors型にする。
RockPaperScissors playerInput;
switch (input[0])
{
// グー
case 'G': // 大文字
case 'g': // 小文字
playerInput = RockPaperScissors.Rock;
break;
// チョキ
case 'C': // 大文字
case 'c': // 小文字
playerInput = RockPaperScissors.Scissors;
break;
// パー
case 'P': // 大文字
case 'p': // 小文字
playerInput = RockPaperScissors.Paper;
break;
// 終了
case 'E': // 大文字
case 'e': // 小文字
goto GAME_END;
// 上記以外はNG
default:
Console.WriteLine("ちゃんと入力して!");
continue;
}
// 乱数でCPUの手を決定
Random random = new System.Random();
RockPaperScissors cpuInput = (RockPaperScissors)random.Next(0, 3);
switch (cpuInput)
{
case RockPaperScissors.Rock:
Console.WriteLine("ぽん! グー!");
break;
case RockPaperScissors.Scissors:
Console.WriteLine("ぽん! チョキ!");
break;
case RockPaperScissors.Paper:
Console.WriteLine("ぽん! パー!");
break;
}
// 勝敗の判定
int judgement = winLoseTable[(int)playerInput, (int)cpuInput];
if (judgement > 0)
{
playerWin++;
Console.WriteLine("あたなの勝ち!");
}
else if (judgement < 0)
{
cpuWin++;
Console.WriteLine("あたなの負け!");
}
else
{
Console.WriteLine("あいこ!");
}
}
GAME_END:;
// 終了表示
Console.WriteLine("============================================================");
Console.WriteLine($"ゲームを終了しました。対戦結果は以下です。");
Console.WriteLine($"Player: {playerWin}勝");
Console.WriteLine($"CPU : {cpuWin}勝");
// 入力待ち
Console.WriteLine($"ゲームを終了しました。何か入力すると画面を閉じます。");
Console.ReadLine();
}
}
}
あとがき
どうでしたか? 実はここまでの知識で簡単なプログラムは作れます。
しかし、本当の意味でC#を扱うにはオブジェクト指向とクラスの理解が必要になります。
これまでの知識に加えてクラスを学べば概ね終わりですが、C#は歴史が長いため色々と覚えることがあります。
簡易記述や便利機能など、それらは実務レベルだと実質的に必須とも言えますが、最悪なくても戦えますよ。
ここではC#のクラスについて学びます。クラスはC#において最も大切な機能だと思ってます。それもあって最低限の内容を書いたつもりが、何かめっちゃ長くなりました。疲れたら数回に分けて読んでください。 クラス(class) クラスとは特定の機能を1つにまとめたものです。正直、説明が難しいのでコードを使って話します。最初に以下の記述方法とサンプルコードを見てください。これは車という機能をクラス化したコードです。 // クラス public class Car { ...
◆ C#に関する学習コンテンツ
この記事は参考になりましたか?
コメント