C#ブラックジャックのプロトタイプ

Aug 18 2020

コードに関するフィードバックをお願いします。C#を使用したコーディングは初めてですが、LuaとPythonについてはある程度の知識があります。より単純化するために変更/クリーンアップする必要があるものはありますか?

using System;
using System.Linq;

class MainClass {
  public static void Main () {
    int[] cards = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10};

    Console.WriteLine("Welcome to Blackjack. Here are your draws.");
            
    Random drawCard = new Random();
    int draw1 = drawCard.Next(cards.Min(), cards.Max());
    int draw2 = drawCard.Next(cards.Min(), cards.Max());

    Console.WriteLine("You recieved a " + draw1 + " card!");
    Console.WriteLine("You recieved a " + draw2 + " card!");
            
    int sum1 = draw1 + draw2;

    if (sum1 == 21) //Blackjack Ending
    {
      Console.WriteLine("Congratulations! You got " + sum1 + "!");
    }


    else if (sum1 >= 11) //Choice of 3rd draw 
    {
      Console.WriteLine("Is " + sum1 + " enough?");
      bool cont1 = false;  

      drawChoice(cont1); //Call the draw choice function


      if (cont1 == true)
      {
        int draw3 = drawCard.Next(cards.Min(), cards.Max());
        Console.WriteLine("You drawed a " + draw3 + " card!");
        
        int sum2 = draw3 + sum1;
        Console.WriteLine("You have a total of " + sum2 + ".");

        if (sum2 > 21) Console.WriteLine("Game Over!");
      }


      else //NPC's turn starts
      {

      }
    }


    else //Player has less than 11 cards, auto draw
    {
      Console.WriteLine("You have a total of " + sum1 + ".");
      Console.WriteLine("You will be forced to draw another card.");

      int draw3 = drawCard.Next(cards.Min(), cards.Max());
      Console.WriteLine("You drawed a " + draw3 + " card!");

      int sum2 = draw3 + sum1;
      Console.WriteLine("You have a total of " + sum2 + ".");
    }
  }


  static void drawChoice(bool contChoice) //Function for player to choose whether to draw 
  {
    Console.WriteLine("Would you like to draw another card? Y/N");       
    string choice1 = Console.ReadLine();


    if (choice1 == "Y" || choice1 == "y")
    {
      contChoice = true;
      Console.WriteLine(contChoice);
    }


    else if (choice1 == "N" || choice1 == "n")
    {
      contChoice = false;
      Console.WriteLine(contChoice);
    }
  }
}

回答

6 JansthcirlU Aug 18 2020 at 22:18

私は実際に自分で同じようなプロジェクトを作りました、それは本当に楽しいです!

1.スコアを追跡する

私が最初に気付いたのは、プレーヤーとおそらくディーラーの値の合計を追跡していることですが、実際には、プレー中にハンドのスコアが劇的に変化する可能性があります。

1.1。ブラックジャックのソフト合計

ブラックジャックにはソフトトータルと呼ばれるこの概念があります。つまり、エースがあるかどうかによって、合計の値が異なる可能性があります。たとえば、プレーヤーがエース(1)と7を持っている場合、実際には18(11 + 7)としてカウントされます。しかし、同じプレイヤーがさらに7を引いた場合、それらの合計は15(1 + 7 + 7)になります。より多くのカードを引くとエースの値が変化するので、どういうわけかカードを互いに離しておくと、スコアを維持するのが簡単になります。これは、コレクションを使用して実行できます。

1.2。コレクション

コレクションは、配列(すでに使用している)、リスト、辞書などです。整数のリストは、プレーヤー(またはディーラー)の現在のカードのコレクションを表すのに適した候補です。なぜなら、それらは文句を言わずにサイズを変更できるからです。さらに、リストには、リスト内のすべての数値の合計、リストの最小値と最大値などを取得するための組み込み関数があります。あなたはそれらの組み込み関数あなたの利点だけでなく、誰かの合計がある場合は、常に決定するために、リスト内の番号を知っているという事実のために使用することができるソフトか。

2.ゲームループ

ブラックジャックのゲームは、実際には限られた数のカードでプレイされますが、もちろんコードではそれについて心配する必要はありません。(不)運の良いプレイヤーがエースを引き続けた場合、彼らは最終的に21をヒットし、ラウンドを終了します。ただし、プレーヤー(またはディーラー)がいつ負けるかは予測できないため、ゲームループと呼ばれるものを使用できます。ブラックジャックのゲームループは、プレーヤーまたはディーラーがカードを引くことを確認すると、すべてのゲームロジックの実行を開始し、実行が完了すると、必要に応じて繰り返すように求められます。

2.1。別のカードを選択するための条件

プレイヤーはブラックジャックに多くの自由を持っていることに気付くでしょう。彼らは21を獲得するか、それを超えるまでカードを引き続けることができ、その時点でラウンドは終了します。しかし、ディーラーにはその自由がありません。あなたはそれについてのより多くの情報をオンラインで見つけることができます。

いずれにせよ、あなたがそれについて考えるならば、ある時点でプレイヤーとディーラーの両方が別のカードを引くかどうかを決定します。入力をチェックする"Y""N"、入力が与えられたときに、それは理にかなっています。

2.2。trueまたはへのテキスト入力の翻訳false

あなたのDrawChoice方法の変更は、boolプレイヤーの入力に応じて、それが受け取るようにします。また、そのメソッドをリファクタリングできstring、リターンbool。そうすれば、ユーザーの入力をtrue(はい、別のカードをください)またはfalse(いいえ、別のカードは必要ありません)に直接翻訳できます。次のようになります。

// One option
public static bool DrawChoice(string input)
{
    if (input == "Y" || input == "y") // You could also use input.ToLower() == "y"
    {
        return true;
    }
    else // If it's not "Y" or "y", it's gonna be "N" or "n"
    {
        return false;
    }

//  else if (input == "N" || input == "n")
//  {
//      return false;
//  }
}

// Alternative one-liner
public static bool DrawChoice2(string input) => input.ToLower() == "y";

ゲームループの概念に戻ると、ゲームループを続行するかどうかを決定する条件があります。考えられる実装の1つは、次のとおりです。

string choice = Console.ReadLine();
while (DrawChoice(choice)) // No need to write "== true" or "== false"
{
    // Stuff that happens if a player or the dealer draws another card
    choice = Console.ReadLine() // Ask again once the game logic has executed
}
// Stuff that happens when the loop ends

2.3。ドローイングカード

ブラックジャックはカードゲームであるため、プレーヤー用であれディーラー用であれ、カードをたくさん引くことになります。ゲームで何かが頻繁に発生する場合は、それをメソッドにすることをお勧めします。そうすれば、同じロジックを別の場所に記述する必要がなくなります。

現在の実装では、カードの配列の最小値と最大値の間でランダムな値が描画されます。ドキュメントから、次のことを学びます。

Next(Int32 minValue, Int32 maxValue)

;minValue以上および以下の32ビット符号付き整数maxValue。つまり、戻り値の範囲にはminValue 含まれますが、は含まれませんmaxValueminValue等しい場合はmaxValueminValueが返されます。

したがって、Next(1, 10)(最小と最大から)書き込むと、最大で9になります。別の問題は、実装をNext(1, 11)に修正しても、1から10までの任意の値を取得する確率が等しいことです。ただし、カードが複数あるためです。値が10のデッキでは、10枚以外のカードよりも頻繁に表示されます。

幸い、配列にはすでに正しいカードの分布があるため、代わりに有効なランダム位置を生成して、配列から対応する値を取得できます。

結局のところ、最終的には次のようになります。

public static int DrawCard()
{
   int[] cards = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10 };
   int card;
   // Implement random draw here
   return card;
}

そして、あなたは繰り返しカードを引くためにこのようなことをすることさえできます:

// You could also use a list, which is more flexible
public static int[] DrawCard(int count)
{
    int[] drawn = new int[count];
    for (int i = 0; i < count; i++)
    {
        drawn[i] = DrawCard();
    }
    return drawn;
}

お役に立てれば!頑張って楽しんでね!

9 Heslacher Aug 18 2020 at 14:33

コードを改善できるように、いくつかの注意事項があります。

int sum1 = draw1 + draw2;

if (sum1 == 21) //Blackjack Ending
{
  Console.WriteLine("Congratulations! You got " + sum1 + "!");
}

これは決して真実ではありません。

  • カードのどこにも、11の可能な値を持つことを意味するエースはありません。
  • maxValue中にはRandom.Next(int minValue, int maxValue)、上側返さ乱数の下限排他的です。

void drawChoice(bool contChoice)メソッド引数contChoice値型です。思ったように変更することはできません。ユーザーがyまたはnを入力したかどうかに関係なく、メソッドを終了した後cont1も、の値はですfalse。メソッドのシグネチャを変更して、引数を持たないが、を返すようにする必要がありますbool

if (cont1 == true)  

cont1すでにブール値であるため、ブール値と比較する必要はありません。のような条件として簡単に使用できます。if (cont1)ブール変数かどうかを確認する必要があるfalse場合は、を使用しますif (!cont1)

3 rball Aug 19 2020 at 00:27

私がここでどれほど役立つかはわかりませんが、私見では、誰かがコードを通してあなたに話しかけることで、本格的なコードレビューを行う必要があります。ここにはたくさんの「間違った」ものがありますが、C#でのあなたの目的は何か疑問に思っています。構文を学ぶために何かをすばやくスクリプト化するだけですか、それともC#で物事を設計する方法をよりよく理解したいですか。

誰かがプロの設定でこれを持って私に来た場合、私は彼らに最初に言うでしょう:「あなたはこれをテストすることができる必要があります」。次に、TDDについて説明し、このコードがどのように構成されているかを指摘します。抽象化はなく、すべてが非常に手続き型です。すべてのクラスは1つのことを行う必要があります。私が確信している人々は、この点について私と議論するでしょう。いずれにせよ、クラスが1つしかないという事実は悪いことです。

それを過ぎて、一般的な「2分間の簡単なC#のヒント」について。カードには列挙型を使用するので、10、10、10の代わりに、10、ジャック、クイーン、エースを使用します。代わりにvarを使用してください。if (cont1 == true)と同じif(cont1)です。より適切な名前の変数を使用する:cont1を見るだけで、それが何を意味するのかわかりません。

JansthcirlUもコレクションを持ち出しました。このコードを見ると、あなたがそれらを理解しているようには見えないので、私はここでも本当に焦点を合わせます。

コーディングを続ける:)