質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.47%

  • C#

    7442questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

【C#】回数指定のじゃんけんゲーム

受付中

回答 4

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,726

k.h

score 2

前提・実現したいこと

観覧してくださってありがとうございます
高卒SE0年生として現在会社で勉強していて簡単なじゃんけんゲームを作成しました
そこで応用で回数指定の限定じゃんけんを作ろうとしているのですがどこを改善すれば良いかで悩んでいます
ソースコードは私が作ったじゃんけんゲームのソースコードになります
若輩者ですがアドバイスをよろしくお願いします
【追記説明】
説明不足で申し訳ないです…
(ルール)
・プレイヤーは2人(プレイヤー1・CPU1)
・9回勝負
・グー、チョキ、パー各3回までしか出せない
(手順)
・じゃんけん→勝敗判定を9回繰り返し
・勝敗をカウント
(現在の仕様)
手を決めてじゃんけんするだけの勝敗などがまだカウントできてない状況です

なるべく詳細は書いていくつもりですが説明足りないかと思いますがそのつど言って頂ければと思います
よろしくお願いします

該当のソースコード

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
class ゲーム//
{
static void Main(string[] args)
{
int player = 1;
int cpu = 1;
int a = 1;

string player1 = "";
string cpu1 = "";

Random rand = new Random();//乱数を設定

Console.WriteLine("数字を入力");//文字を表示
Console.WriteLine("じゃんけん\n数字を入力\n1グー、2チョキ、3パー");//文字を表示

while (a != 0)//条件が正しい場合反復処理    
{
try//実行
{
player = int.Parse(Console.ReadLine());

cpu = rand.Next(1, 4);

if (cpu == player)
{
Console.WriteLine("あいこ もう一度入力");
continue;
}
else if (player == 1 && cpu == 2)
{
Console.WriteLine("プレイヤー、グー");
Console.WriteLine("CPU、チョキ");
Console.WriteLine("勝ち");
}
else if (player == 2 && cpu == 3)
{
Console.WriteLine("プレイヤー、チョキ");
Console.WriteLine("CPU、パー");
Console.WriteLine("勝ち");
}
else if (player == 3 && cpu == 1)
{
Console.WriteLine("プレイヤー、パー");
Console.WriteLine("CPU、グー");
Console.WriteLine("勝ち");
}
else if (player < 1 || player > 3)
{
Console.WriteLine("1か2か3を入力してね");
continue;
}
else
{
if (player == 1) player1 = player.ToString("グー");
if (player == 2) player1 = player.ToString("チョキ");
if (player == 3) player1 = player.ToString("パー");
if (cpu == 1) cpu1 = cpu.ToString("グー");
if (cpu == 2) cpu1 = cpu.ToString("チョキ");
if (cpu == 3) cpu1 = cpu.ToString("パー");

Console.WriteLine("プレイヤー、{0}\nCPU、{1}", player1, cpu1);
Console.WriteLine("負け");
}

//終了分岐の呼び出し
bunki(ref player, ref cpu, ref a);

if (a == 0)
{
Console.Clear();
Console.Write("終了します");//文字を表示
}
}
catch (FormatException)
{

Console.Clear();

Console.WriteLine("数字を入力");//文字を表示
Console.WriteLine("じゃんけん\n数字を入力\n1グー、2チョキ、3パー");//文字を表示
continue;
}
}
}

//終了分岐のメソッド
static void bunki(ref int player, ref int cpu, ref int a)
{
if (player != cpu)
{
Console.WriteLine("\n終了なら0\n続行は0以外を入力");
a = int.Parse(Console.ReadLine());
Console.Clear();
Console.WriteLine("数字を入力");//文字を表示
Console.WriteLine("じゃんけん\n数字を入力\n1グー、2チョキ、3パー");//文字を表示
}
}
}
}

補足情報(言語/FW/ツール等のバージョンなど)

VisualStudio2015

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • Chironian

    2016/07/25 15:29

    SEを目指されているのであれば、現在の仕様、および、それをどのような仕様に変更したいのか、きちんと説明してみると良いですよ。仕様を把握しそれを説明するのはSEの必須スキルの1つですから。意外に難しいですが、ガンバです。

    キャンセル

  • jawa

    2016/07/25 18:35

    ソースコードは前後を```で囲んで投稿することでネストの段組みなどを表示することができます。 それだけで読みやすさがぐっと変わりますので、Teratailで投稿する際のマナーだと思って心掛けて頂きたいです。

    キャンセル

  • mugicya

    2016/07/26 01:05

    まだ言語の基本的な記述など、理解が浅いようですね。 Webで検索すると、疑問の回答がポンと出てきてそれを使いがちですが、 やはり、僕は書籍を購入してチュートリアルを完遂して内容理解に努めるのが早いと思います。 がんばってください。

    キャンセル

回答 4

+3

オブジェクトを使って少し抽象化してみました。
多人数に対応しています。
また、Player を継承することで、コンソール以外の入力に対応できます。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class ゲーム// 
    {
        static void Main(string[] args)
        {
            var you = new ConsolePlayer() { Name = "あなた" };
            var cpu = new RandomPlayer() { Name = "CPU" };
            var players = new Player[] { you, cpu };
            do
            {
                foreach (var player in players)
                {
                    //各プレイヤーが自分の手を決める
                    player.DecideHand();
                }

                // 審判
                var judge = new Judge(players);

                foreach (var player in players)
                {
                    // 各プレイヤーに結果報告
                    player.AnnounceResult(judge);
                }
            // 全員やめたいと言うまで続ける
            } while (players.Any(p => !p.WantToQuit()));
        }
    }

    enum Hand
    {
        グー, チョキ, パー
    }

    // 審判
    class Judge
    {
        public Judge(IEnumerable<Player> players)
        {
            Players = players;
            Winned = new Dictionary<Player, bool>();
            foreach (var player in Players) Winned[player] = false;
            var varietyOfHands = players
                .Select(p => p.Hand)
                .Distinct()
                .ToArray();
            if (varietyOfHands.Count() == 2)
            {
                // 手の種類が 2 種類なら勝者を決める(例: {グー, チョキ}, {チョキ, チョキ, パー})。それ以外なら勝者無し
                Hand winnedHand = JudgeHand(varietyOfHands[0], varietyOfHands[1]);
                foreach (var player in players.Where(p => p.Hand == winnedHand))
                {
                    Winned[player] = true;
                }
            }
        }

        // どちらが勝つかを定めたテーブル
        private Dictionary<Hand, Hand> strongerHand = new Dictionary<Hand,Hand>()
        {
            {Hand.グー, Hand.パー},
            {Hand.パー, Hand.チョキ},
            {Hand.チョキ, Hand.グー}
        };

        // 手を比較して勝った方の手を返す。手の種類が一種類の場合は例外。
        public Hand JudgeHand(Hand a, Hand b)
        {
            if (a == b) throw new InvalidOperationException();
            if (strongerHand[a] == b) return b;
            else return a;
        }

        // プレイヤーリスト
        public IEnumerable<Player> Players { get; private set; }

        // 勝者は true 敗者は false
        public Dictionary<Player, bool> Winned { get; private set; }
    }

    // プレイヤー
    abstract class Player
    {
        // 表示名
        public string Name { get; set; }

        // 手
        public Hand Hand { get; set; }

        // 次にどの手を出すか決める
        public abstract void DecideHand();

        // 終わりたいなら true 続けたいなら false を返す
        public abstract bool WantToQuit();

        // 結果発表
        public abstract void AnnounceResult(Judge judge);
    }

    // コンソールを使って次の手を入力するプレイヤー
    class ConsolePlayer : Player
    {
        public override void DecideHand()
        {
            while (true)
            {
                try
                {
                    Console.WriteLine("じゃんけん\n数字を入力\n1グー、2チョキ、3パー");
                    string s = Console.ReadLine();
                    int h = int.Parse(s) - 1;
                    if (h < 0 || h >= Enum.GetNames(typeof(Hand)).Length)
                    {
                        throw new InvalidOperationException();
                    }
                    Hand = (Hand)h;
                    break;
                }
                catch
                {
                    Console.WriteLine("\n1か2か3を入力してね\n");
                }
            }
        }

        public override bool WantToQuit()
        {
            Console.WriteLine("\n終了なら0\n続行は0以外を入力");
            string s = Console.ReadLine();
            return s == "0";
        }

        public override void AnnounceResult(Judge judge)
        {
            Func<Player, int, string> result = (player, index) =>
            {
                return string.Format(
                    "{0} [{1}]",
                    player.Name,
                    player.Hand.ToString()
                );
            };
            var results = judge
                .Players
                .Select((player, index) => result(player, index));
            results.ToList().ForEach(s => Console.WriteLine(s));
            var winners = judge
                .Players
                .Where(p => judge.Winned[p])
                .Select(p => p.Name)
                .ToArray();
            if (winners.Count() == 0)
            {
                Console.WriteLine("引き分け");
            }
            else
            {
                Console.WriteLine(string.Format("勝者: {0}", string.Join(", ", winners)));
            }
        }
    }

    // 次の手をランダムで決めるプレイヤー
    class RandomPlayer : Player
    {
        public RandomPlayer()
        {
            Random = new Random();
        }

        protected Random Random { get; set; }

        public override void DecideHand()
        {
            Hand = (Hand)Random.Next(Enum.GetNames(typeof(Hand)).Length);
        }

        public override bool WantToQuit()
        {
            // やめたくてやめたくてしょうがない
            return true;
        }

        public override void AnnounceResult(Judge judge)
        {
            // 結果なんてどうでもいい
        }
    }
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/07/25 18:03

    Player クラスに自分が何の手を何回出したか、何回勝ったかの情報を入れておいて、それを使って出せる手を制限すればいいと思います。

    あと、SE を目指しているならこんな重要な情報を言われてから出すようではさすがに必死で頑張らないと厳しいかもしれませんね。

    インデントも早く直しましょう。見直して全く気になりませんか?

    キャンセル

  • 2016/07/25 18:12

    それと、私たちはあなたの部下ではありません。
    「わからないことがあったら聞いてくれ」は上司の言です。
    あなたがわからないことを聞いているのですから、必要な情報を揃えるのはあなたの仕事です。

    キャンセル

  • 2016/07/26 01:01

    別物w

    キャンセル

+1

質問が漠然としすぎているので、まずはそこを整理することからはじめては?
・プログラムの書き方(拡張性を考えた書き方とか、コメントの付け方とか)
・アルゴリズムに関して(判定の仕方とか、出力の仕方とか)
・teratail のマークダウン記法(ソースのソースとしての表現の仕方とか)
等々、聞きたいポイントが有るのではないかと思います。
どれを聞きたいのか、どのような観点で聞きたいか、整理できればほしい回答が手に入れられるかと。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

こんにちは。

(現在の仕様) 
手を決めてじゃんけんするだけの勝敗などがまだカウントできてない状況です

現在の仕様は、何ができていないかではなく、何ができているか書きましょう。
現仕様と目標仕様を見比べて、何が不足しているか判断することになりますが、現仕様がかけないとそれが明確にならないのですよ。

目標仕様も不明点が残っているようです。
「グー、チョキ、パー各3回までしか出せない」について
あいこの時どうする?
4回目出してしまったらどうする?
など

あと、他の人にソースを読んで貰うためには、インデントはちゃんと付けましょう。
インデントのないソースってマジで読めないです。

ごめんなさい。少し厳しい回答をしてると思います。
しかし、仕様を明確に記述することはSEの最重要スキルですから頑張れ。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

追加で改修する部分について、できるところまでは自力で考えた結果を提示していただきたかったです。
今回の質問の仕方では、提示しているソースコードは自作のものとのことですが、改修部分については「丸投げ」とも取れる内容ですので。

アドバイス

苦言だけでは申し訳ないので、自分ならここを作り変える、という観点からアドバイスです。

①勝ち負け判定
⇒特に「勝ち判定」の部分が出した手ごとに個別の処理になってしまっているのが気になります。
「負け判定」ではメッセージ出力を共通化できているので、「勝ち負けフラグ」のようなものを用意すればメッセージ出力は一本化できると思います。

また、出した手ごとに判定処理を記述していると、通算での勝ち数・負け数のカウントアップも手ごとに記述しなくてはならなくなり、管理が煩雑になります。

(宣言)
//出し手の使用回数管理(対戦開始時の初期化処理)
int[] player_te = {0, 3, 3, 3};
//出し手の表示名を配列で管理
string[] disp_te = {"", "グー", "チョキ", "パー"};

//判定結果
int result = 0; 
//勝ち数
int win = 0;
//負け数
int lose = 0;

(判定処理)
if (player < 1 || player > 3) 
  { 
    Console.WriteLine("1か2か3を入力してね"); 
    continue; 
  } 
else if ( player_te[player] < 1) 
  { 
    //使用回数の判定
    Console.WriteLine( "{0}は使用回数を超えています。", disp_te[player]); 
    continue; 
  } 
else if (cpu == player) 
  { 
    Console.WriteLine("あいこ もう一度入力"); 
    continue; 
  } 
else if (player == 1 && cpu == 2) || (player == 2 && cpu == 3) || (player == 3 && cpu == 1) 
  { 
    //勝ち判定
    result = 1;
    win = win + 1;
  } 
else 
  { 
    //負け判定
    result = 0;
    lose = lose + 1;
  }

//今回出した手の使用回数を1つ減らす
player_te[player] = player_te[player] - 1;

//メッセージ表示
Console.WriteLine("プレイヤー、{0}\nCPU、{1}", disp_te[player], disp_te[cpu]); 

if (result == 1) 
  {
    Console.WriteLine("勝ち"); 
  }
else
  {
    Console.WriteLine("負け"); 
  }


※コードは机上で作成したものなので動作の保証はありません。あくまで考え方として参考までに。

②関数化
⇒これも「勝ち負け判定」の部分になりますが、判定の条件文が少し長すぎるため、処理の流れが分かりにくくなっています。
自分なら判定部分は勝ち/負け/あいこの結果を返す関数を用意すると思います。

それ以外の部分では、0が入力されるまでのループを対戦回数でのループに変更するくらいで目的が達せられるのではないでしょうか。
がんばってみてください。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.47%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • C#

    7442questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。