First, my apologies if this is posted twice. I think the site may have burped.
I have an apparently impossible requirement for a clinical trials pharma application in my C# course. Please, someone tell me if I'm interpreting this part of the assignment incorrectly (copied verbatim from handout):
"MONTHS NUMBER OF TREATMENTS (use a Switch command)
1 -19 10 -30
20 - 39 31 -60
40 - 59 61 - 100
60 - 79 101 - 130
80 - 99 131 - 180
For Example:
If the randomly chosen # of months is from 20 through 39 - the number of treatments will be a random number from 31 through 60. If the # of months is 82 - the number of treatments is from 131 through 180."
The number of months the patient is available for the trial is input directly into a text box; my code supplies the random ACTUAL months the patient is participating in the clinical trial. I already know that ranges CANNOT be used in switch commands. Since this instructor also teaches Visual Basic, which apparently does support ranges in a switch command, she may have gotten the two confused (which, sadly, happens with alarming frequency). At any rate, everything I have read said this is flatly impossible with a switch case.
I have no idea how to accomplish this without an if/else tree instead of a switch. Can anyone give me any ideas? PLEASE, no regex or LINQ. We are not covering either one.
Here's all of my code. What is here works; file read/write isn't implemented yet, but I already understand that part.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
namespace NallyKProgram3ClinicalTrials
{
public partial class NallyKClinicalTrialsForm : Form
{
public NallyKClinicalTrialsForm()
{ InitializeComponent(); }
private StreamWriter outputFile;
private StreamReader inputFile;
int numberOfMonthsInTrialRangeInteger;
int numberAssignedToPatientInteger;
int numberOfMonthsInTrialInteger;
int numberOfTreatmentPlanInteger;
int numberOfTreatmentsInteger;
// const string CASE_STRING; this attempt didn't work
Random rndNumber = new Random();
Boolean duplicateNameBoolean;
private void NallyKClinicalTrialsForm_Load(object sender, EventArgs e)
{
reportLabel.ResetText();
removePatientButton.Enabled = false;
writeFileButton.Enabled = false;
}
private void addPatientButton_Click(object sender, EventArgs e)
{
if (patientNameTextBox.Text.Trim() != string.Empty)
{
checkForDuplicateNames();
generatePatientNumber(rndNumber);
if (duplicateNameBoolean == false)
{
if (numberOfMonthsTextBox.Text.Trim() != string.Empty)
{
if (int.TryParse(numberOfMonthsTextBox.Text.Trim(), out numberOfMonthsInTrialRangeInteger))
{
if (numberOfMonthsInTrialRangeInteger < 1 || numberOfMonthsInTrialRangeInteger > 99)
{
errorProvider1.SetError(numberOfMonthsTextBox, "The number of months available for participation in this trial must not be less than 1 or greater than 99.");
numberOfMonthsTextBox.Focus();
numberOfMonthsTextBox.SelectAll();
}
else
{
generateNumberOfMonthsInTrial(rndNumber);
generateTreatmentPlan(rndNumber);
// determineCaseString(); NOPE!
// determineNumberOfTreatments(rndNumber); TO DO
addToListBox();
addToNamesListBox();
readFileButton.Enabled = false;
removePatientButton.Enabled = true;
writeFileButton.Enabled = true;
}
}
else
{
errorProvider1.SetError(numberOfMonthsTextBox, "Please enter a number.");
numberOfMonthsTextBox.Focus();
numberOfMonthsTextBox.SelectAll();
}
}
else
{
numberOfMonthsTextBox.Text = " ";
errorProvider1.SetError(numberOfMonthsTextBox, "You must enter a number of months.");
numberOfMonthsTextBox.Focus();
numberOfMonthsTextBox.SelectAll();
}
}
else
{
errorProvider1.SetError(namesListBox, patientNameTextBox.Text + " is a duplicate name. Please enter a different name.");
patientNameTextBox.Focus();
patientNameTextBox.SelectAll();
}
}
else
{
patientNameTextBox.Text = " ";
errorProvider1.SetError(patientNameTextBox, "You must enter a patient name.");
patientNameTextBox.Focus();
patientNameTextBox.SelectAll();
}
}
private void checkForDuplicateNames()
{
int indexInteger = 0;
duplicateNameBoolean = false;
while (indexInteger < namesListBox.Items.Count)
{
if (patientNameTextBox.Text.ToLower().Trim() ==
namesListBox.Items[indexInteger].ToString().ToLower())
{
duplicateNameBoolean = true;
indexInteger = namesListBox.Items.Count;
}
indexInteger++;
}
}
private Random generatePatientNumber(Random rndNumber)
{
numberAssignedToPatientInteger = rndNumber.Next(1000, 9999);
return rndNumber;
}
private Random generateNumberOfMonthsInTrial(Random rndNumber)
{
numberOfMonthsInTrialInteger = rndNumber.Next(1, numberOfMonthsInTrialRangeInteger);
return rndNumber;
}
private Random generateTreatmentPlan(Random rndNumber)
{
numberOfTreatmentPlanInteger = rndNumber.Next(1, 5);
return rndNumber;
}
//private void determineCaseString() NOPE, NOPE, NOPE
//{
// if ((numberOfTreatmentPlanInteger >= 1) && (numberOfTreatmentPlanInteger < 20)) CASE_STRING = "a"; // clever, but error!
// if ((numberOfTreatmentPlanInteger >= 20) && (numberOfTreatmentPlanInteger < 40)) CASE_STRING = "b";
// if ((numberOfTreatmentPlanInteger >= 41) && (numberOfTreatmentPlanInteger < 60)) CASE_STRING = "c";
// if ((numberOfTreatmentPlanInteger >= 60) && (numberOfTreatmentPlanInteger < 80)) CASE_STRING = "d";
// if ((numberOfTreatmentPlanInteger >= 80) && (numberOfTreatmentPlanInteger < 100)) CASE_STRING = "e";
//}
//private Random determineNumberOfTreatments(Random rndNumber)
//{
// numberOfTreatmentsInteger = rndNumber.Next(10, CASE_STRING);
//}
private void addToListBox()
{
patientInformationListBox.Items.Insert(0, numberAssignedToPatientInteger.ToString() + "," + numberOfTreatmentPlanInteger + "," + numberOfMonthsInTrialInteger + "," + Environment.NewLine); // number of treatments goes after the final comma
}
private void addToNamesListBox()
{
namesListBox.Items.Insert(0, patientNameTextBox.Text.Trim());
}
private void exitButton_Click(object sender, EventArgs e)
{
this.Close();
}
private void removePatientButton_Click(object sender, EventArgs e)
{
if (patientInformationListBox.SelectedIndex > -1)
patientInformationListBox.Items.RemoveAt(patientInformationListBox.SelectedIndex);
else MessageBox.Show("You must select an entry you wish to remove from the list.", "SELECT AN ITEM TO REMOVE", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
private void patientNameTextBox_TextChanged(object sender, EventArgs e)
{
errorProvider1.SetError(patientNameTextBox, "");
errorProvider1.SetError(patientInformationListBox, "");
}
private void numberOfMonthsTextBox_TextChanged(object sender, EventArgs e)
{
errorProvider1.SetError(numberOfMonthsTextBox, "");
}
}
}
You're right in that C# does not allow you to use ranges in the switch-statement. In fact, C# only allows you to write a case X: where X is a single constant literal value.
However, C# does allow you to fall through from one case to another, and thus allows you to list all the cases for which you can write one single body of code to execute.
As such, you can write the code like this:
switch (months)
{
case 1:
case 2:
case 3:
...
case 19:
treatments = r.Next(10, 31);
break;
case 20:
case 21:
case 22:
...
case 39:
treatments = r.Next(30, 61);
break;
case 40:
...
Now, is that the best you can do?
No. You can notice a pattern in the ranges here. Each range goes from X to X+19, where X is a number divisible by 20, so you can use the fact that integer division will truncate downwards:
int monthsSection = months / 20; // 0-19 --> 0, 20-39 --> 1, etc.
switch (monthsSection)
{
case 0: // 0-19
treatments = r.Next(10, 31);
break;
case 1: // 20-39
treatments = r.Next(30, 61);
break;
case 2: // 40-59
...
Yes, this will include 0 as well. If that is a problem then I would simply add a specific if-statement in front to filter it out.
If you have to use a switch, you could divide your months by 20, and then do a switch on that. Something like this:
int monthValue = numberOfTreatmentPlanInteger / 20;
switch (monthValue)
{
case 0:
// between 10 and 30 treatments
break;
case 1:
// between 31 and 60 treatments
break;
case 2:
// between 61 and 100 treatments
break;
// and so on
}
Related
My problem is that I want to put a max number limit where the user would put a max question of 2 like an example and my program would show random question only 2 times but it keeps generating numbers I think my problem is with changing the textbox to int and where to place it I'm new to windows forms the first button generate random questions the second button should do the same but minus a number of question every time the user clicks I tried a lot operationbox is for the user to choose his operation(+,-,*,/) and the range box is the range of the random numbers.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication7
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
rangebox1.Items.Add("[1,100]");
rangebox1.Items.Add("[1,500]");
rangebox1.Items.Add("[1,1000]");
Operationbox1.Items.Add("+");
Operationbox1.Items.Add("-");
Operationbox1.Items.Add("*");
Operationbox1.Items.Add("/");
}
int[] Rand(int v)
{
Random r = new Random();
int a = r.Next(1,v);
int b = r.Next(1,v);
int[] N = {Math.Max(a,b) , Math.Min(a,b)};
return N;
}
void generate()
{
int range = 0;
switch (rangebox1.SelectedIndex)
{
case 0:
range = 100;
break;
case 1:
range = 500;
break;
case 2:
range = 1000;
break;
default:
MessageBox.Show("Put a range !");
break;
}
int[] numbers = Rand(range);
switch (Operationbox1.SelectedIndex)
{
case 0:
questionlbl1.Text = string.Format("{0} + {1} =",numbers[0],numbers[1]);
break;
case 1:
questionlbl1.Text = string.Format("{0} - {1} =" , numbers[0], numbers[1]);
break;
case 2:
questionlbl1.Text = string.Format("{0} * {1} =" , numbers[0], numbers[1]);
break;
case 3:
questionlbl1.Text = string.Format("{0} / {1} =" , numbers[0], numbers[1]);
break;
default:
MessageBox.Show("Please insert a operation");
break;
}
}
void numberquest()
{
int numofquestionleft = Convert.ToInt32(numofquest1.Text);
int r = int.Parse(numofquest1.Text);
if (numofquestionleft > 0) generate();
numofquestionleft--;
}
private void genbutton1_Click(object sender, EventArgs e)
{
generate();
}
private void button1_Click(object sender, EventArgs e)
{
numberquest();
}
}
}
As far as I understood your question, you are facing issue with numofquestionleft variable and you want to restrict user to make max two number request. You need to modify your code. The way you are doing will not work. One solution could be,
Declare numofquestionleft as class level.
public partial class Form1 : Form
{
int numofquestionleft = 2; //here
public Form1()
{
And your numberquest() method would look like
void numberquest()
{
if (numofquestionleft > 0)
{
generate();
}
numofquestionleft--;
//You can use the textBox to communicate with user about number of turns left
//as
numofquest1.Text ="Request left " +numofquestionleft;
}
But if you still want to read max request from the textBox then the purpose of restricting users to make only two requests is lost (a user may enter some other number and you need to validate input in that case), moreover, you need to find a way to read data once.
Hope it helps.
I am having problems with putting a max number of question limit I'm new to windows forms so I tried a changing the textbox of the questions number text box to int then putting a loop using (while();) but the program just freezes + how do I tell the user answer if his answer is right or wrong using (if) didn't work for me I don't know where to put it or if my way of changing the text box to int is right here is my code.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication6
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
numrange.Items.Add("1,100");
numrange.Items.Add("1,500");
numrange.Items.Add("1,1000");
operation.Items.Add("+");
operation.Items.Add("-");
operation.Items.Add("*");
operation.Items.Add("/");
}
private void label1_Click(object sender, EventArgs e)
{
}
int[] Rand(int v)
{
Random r = new Random();
int a = r.Next(1,v);
int b = r.Next(1,v);
int[] N = { Math.Max(a,b) , Math.Min(a,b)};
return N;
}
void generate()
{
int range = 0;
switch (numrange.SelectedIndex)
{
case 0:
range = 100;
break;
case 1:
range = 500;
break;
case 2:
range = 1000 ;
break;
default :
MessageBox.Show("Please Insert a range!!");
break;
}
int[] Numbers = Rand(range);
int numofquest = Convert.ToInt32(maxquestion.Text);
int numofquestleft;
numofquestleft = numofquest;
while (numofquest > 0)
{
switch (operation.SelectedIndex)
{
case 0:
questionbox.Text = string.Format("{0} + {1} = ", Numbers[0], Numbers[1]);
break;
case 1:
questionbox.Text = string.Format("{0} - {1} = ", Numbers[0], Numbers[1]);
break;
case 2:
questionbox.Text = string.Format("{0} * {1} = ", Numbers[0], Numbers[1]);
break;
case 3:
questionbox.Text = string.Format("{0} / {1} = ", Numbers[0], Numbers[1]);
break;
default:
MessageBox.Show("Please insert an operation!!");
break;
}
numofquestleft--;
}
}
private void Startbutton1_Click(object sender, EventArgs e)
{
generate();
}
private void Nextbutton_Click(object sender, EventArgs e)
{
generate();
}
}
}
}
}
You did'nt change numofquest in the while loop, therefore numofquest > 0 is always true.
It should be while numofquestleft > 0. Be sure it;s numofquestleft and not numofquest
Aside from that, if you want to generate a different question each time you hit the button, consider putting the generate() with no loop inside the clickfunction, a loop will run all in one go. Something like this:
private int numofquestleft;
private int answer;
private void Start_Click(object sender, EventArgs e)
{
numofquestleft = Convert.ToInt32(maxquestion.Text);
if (numofquestleft > 0) generate();
numofquestleft--;
}
private void Nextbutton_Click(object sender, EventArgs e)
{
if (Convert.ToInt32(userinput.Text) == answer){ MessageBox.Show("Correct");}
else {MessageBox.Show("Incorrect");}
if(numofquestleft > 0) generate();
numofquestleft--;
}
To check user's answer, first calculate the result:
switch(operation.SelectedIndex)
{
case 0:
questionbox.Text = string.Format("{0} + {1} = ",Numbers[0],Numbers[1]);
answer = Numbers[0] + Numbers[1];
break;
case 1:
questionbox.Text = string.Format("{0} - {1} = ",Numbers[0],Numbers[1]);
answer = Numbers[0] - Numbers[1];
break;
case 2:
questionbox.Text = string.Format("{0} * {1} = ",Numbers[0],Numbers[1]);
answer = Numbers[0] * Numbers[1];
break;
case 3:
questionbox.Text = string.Format("{0} / {1} = ",Numbers[0],Numbers[1]);
answer = Numbers[0] / Numbers[1];
break;
}
Then compare it with user input (convert to int), assuming when you hit Next:
private void Nextbutton_Click(object sender, EventArgs e)
{
if (Convert.ToInt32(userinput.Text) == answer){ MessageBox.Show("Correct");}
else {MessageBox.Show("Incorrect");}
if(numofquestleft > 0) generate();
numofquestleft--;
}
This will check the answer of a question, then generate a new question when you click Next.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I am a novice programmer and I am working in visual studio using C#. In a Windows Form Application, Create a form that gets the input from a user from 0-100. You will need to make 3 methods for this application. Your first method must get the users input and validates that the entry is valid. Use logic to ensure the input is accurate, if the user enters an invalid entry throw a message box to the user with the error. The user must have a successful entry to proceed. We will expand on validation and exceptions in Lab 5. Once the score is validated send the score to a second method which assigns a letter grade. Use the following grading schema and use integer values for your scoring. < 60 is a F, >= 60 and < 70
is a D, >= 70 and < 80 is a C, >= 80 and < 90 is a B, >= 90 is an A. Once a grade is assigned pass the score and the letter grade to a Third Method. The third method will handle display and concatenate the results into a single string as displayed in the image below.
This is what I currently have...
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Lab4_Part_1_
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnValidate_Click(object sender, EventArgs e)
{
//Set user input to integer.
int score = Convert.ToInt32(txtScore.Text);
Form1 moto = new Form1();
lblGrade.Text = moto.NumEnter(score);
}
private string NumEnter(int score)
{
string result;
//Set parameters for user input and prompt with textbox if outside parameters.
if (score < 0 | score > 100)
{
MessageBox.Show("Enter a score 0-100.");
this.txtScore.Text = "";
}
//Set parameters for each letter grade
else if (score >= 0 && score <= 100)
{
if (score >= 90)
{
result = lblGrade.Text = "A";
}
else if (score >= 80)
{
result = lblGrade.Text = "B";
}
else if (score >= 70)
{
result = lblGrade.Text = "C";
}
else if (score >= 60)
{
result = lblGrade.Text = "D";
}
else
{
result = lblGrade.Text = "F";
}
return result;
}
//Concatenate the input user score and output a message with the letter grade.
lblGrade.Text = "You entered an " + txtScore.Text + " which is a " +
lblGrade.Text + " letter grade.";
}
}
}
"Use at least X methods" = "Don't do everything in one big method." That is all.
For example, instead of this huge method:
private string NumEnter(int score)
{
string result;
//Set parameters for user input and prompt with textbox if outside parameters.
if (score < 0 | score > 100)
{
MessageBox.Show("Enter a score 0-100.");
this.txtScore.Text = "";
}
//Set parameters for each letter grade
else if (score >= 0 && score <= 100)
{
if (score >= 90)
{
result = lblGrade.Text = "A";
}
else if (score >= 80)
{
result = lblGrade.Text = "B";
}
else if (score >= 70)
{
result = lblGrade.Text = "C";
}
else if (score >= 60)
{
result = lblGrade.Text = "D";
}
else
{
result = lblGrade.Text = "F";
}
return result;
}
//Concatenate the input user score and output a message with the letter grade.
lblGrade.Text = "You entered an " + txtScore.Text + " which is a " +
lblGrade.Text + " letter grade.";
}
You could instead break it down into four short methods:
private string GetLetterGrade(int score)
{
if (score < 0 | score > 100)
{
return null; //not valid score
}
if (score >= 90) return "A";
if (score >= 80) return "B";
if (score >= 70) return "C";
if (score >= 60) return "D";
return "F";
}
private string NumEnter(int score)
{
var grade = GetLetterGrade(score);
if (grade == null)
{
MessageBox.Show("Enter a score 0-100.");
ClearUserInput();
return;
}
DisplayScore(score, grade);
}
public void ClearUserInput()
{
this.txtScore.Text = "";
}
public void DisplayScore(int score, string grade)
{
this.lblGrade.Text = String.Format("You entered an {0} which is a {1}", score, grade);
}
As a rule, programmers should try to break things down into smaller methods. This practice greatly reduces complexity and makes the code easier to read (Some engineers would actually state a hard rule that no method should ever be bigger than a single screen.)
Also, introducing more methods means introducing more method names, which allows a programmer to quickly understand the purpose of the code without needing to read code comments-- from my code snippet, for example, it is very clear what is intended by calling ClearUserInput and DisplayScore, without having to dig into the code inside those functions, and without understanding the purpose of the textboxes on the form. Not a big deal in this exercise but extremely helpful in real-world applications, where there may be dozens of controls on the form.
See also
Functions Should Be Short And Sweet, But Why?
The art of writing small and plain functions
Can a function be too short?
Change:
Form1 moto = new Form1();
lblGrade.Text = moto.NumEnter(score);
to:
lblGrade.Text = NumEnter(score);
There is no need to new up a new Form1 since your code is already running in a Form1.
You should also change your lines like:
result = lblGrade.Text = "A";
to just return the result:
return "A";
And let btnValidate_Click take care of setting lblGrade.Text.
I am beginner , am trying to create a calculator. the way of the code working is there is a method for summing and one for subtraction ETC.
when i call the subtraction method unwanted minus appears before the answer in the textbox ( i know my code could be using harder way to do the same purpose but i am just beginner trying to do some code )
double rat;
byte operations;
public void TheEqualMinus(double earlier) //Substraction Operation Method
{
double _minus;
_minus = Convert.ToDouble(result.Text);
double last = _minus - earlier;
result.Text = last.ToString();
}
private void button15_Click(object sender, EventArgs e)
{
//The Subtract Button
operations = 2;
rat = Convert.ToDouble(result.Text);
label1.Text = rat + " -";
result.Text = "";
}
private void button4_Click(object sender, EventArgs e)
{
// equal button
NewText = true; //boolean to newtext
switch (operations)
{
case (1): //addition
TheEqualSum(rat);
label1.Text = "";
break;
case (2): //substraction
TheEqualMinus(rat);
label1.Text = "";
break;
}
}
and the answer output becomes " - The Correct Answer i want "
ex. 9-6 = -3
so any ideas how to remove this minus ?
As per the comments above, this was fixed by simply changing this:
double last = _minus - earlier;
to this:
double last = earlier - _minus;
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
i'm working on a little black jack game for no apparent reason, and I've run into an issue and i can't figure out where i'm going wrong, the only thing i can imagine is that the 'new card' method is being called twice, too quickly...
The problem is that it's giving the same card to both players :/
Here is my code
Thank you! :)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace BlackJack_Reworked
{
public partial class BlackJack : Form
{
public BlackJack()
{
InitializeComponent();
}
class myVars
{
public static int cardsDrawn = 0;
public static int playerX = 230;
public static int playerY = 160;
public static int cpuX = 230;
public static int cpuY = 60;
public static int playerCardValue = 0;
public static int cpuCardValue = 0;
}
private PictureBox[] card = new PictureBox[100];
private void makeCard(string pickedCard, int x)
{
card[myVars.cardsDrawn] = new PictureBox();
if (x == 0)
{
card[myVars.cardsDrawn].Location = new Point(myVars.playerX, myVars.playerY);
myVars.playerX += 15;
}
if (x == 1)
{
card[myVars.cardsDrawn].Location = new Point(myVars.cpuX, myVars.cpuY);
myVars.cpuX += 15;
}
card[myVars.cardsDrawn].Image = (Image)Properties.Resources.ResourceManager.GetObject(pickedCard);
card[myVars.cardsDrawn].Size = new Size(72, 96);
card[myVars.cardsDrawn].Parent = this;
card[myVars.cardsDrawn].BringToFront();
card[myVars.cardsDrawn].Update();
myVars.cardsDrawn++;
checkScores(false);
}
private void newCard(int x)
{
Random cardPicker = new Random();
int cardChoice = cardPicker.Next(1, 13);
int houseChoice = cardPicker.Next(1, 4);
string house = null;
switch (houseChoice)
{
case 1:
house = "Hearts";
break;
case 2:
house = "Diamonds";
break;
case 3:
house = "Spades";
break;
case 4:
house = "Clubs";
break;
}
if (x == 0)
{
makeCard(house + Convert.ToString(cardChoice), 0);
myVars.playerCardValue += cardChoice;
}
if (x == 1)
{
makeCard(house + Convert.ToString(cardChoice), 1);
myVars.cpuCardValue += cardChoice;
}
}
private bool feelingLucky()
{
Random Dice = new Random();
if (myVars.cpuCardValue >= 20) { return false; }
if (myVars.cpuCardValue <= 16) { return true; }
if (myVars.cpuCardValue >= 17 && myVars.cpuCardValue <= 18) if (Dice.Next(1, 5) == 1) { return true; }
if (myVars.cpuCardValue == 19) if (Dice.Next(1, 10) == 1) { return true; }
return false;
}
private void updateHandValues()
{
lblPlayerHand.Text = "Player: " + myVars.playerCardValue.ToString();
lblCPUhand.Text = "CPU: " + myVars.cpuCardValue.ToString();
}
private void checkScores(bool stand)
{
if (stand == true)
{
if (myVars.playerCardValue <= 21 && myVars.playerCardValue > myVars.cpuCardValue)
{
MessageBox.Show("Win!");
btnNewGame.Visible = true;
}
else if (myVars.cpuCardValue <= 21 && myVars.cpuCardValue > myVars.playerCardValue)
{
btnNewGame.Visible = true;
MessageBox.Show("Lose!");
}
}
else
{
if (myVars.playerCardValue > 21)
{
MessageBox.Show("Bust!");
btnNewGame.Visible = true;
}
if (myVars.cpuCardValue > 21)
{
MessageBox.Show("Win!");
btnNewGame.Visible = true;
}
}
}
private void newGame()
{
for(int x = 0; x < myVars.cardsDrawn; x++) { card[x].Dispose(); }
myVars.cpuCardValue = 0;
myVars.playerCardValue = 0;
myVars.cpuX = 230;
myVars.playerX = 230;
btnNewGame.Visible = false;
newCard(0); newCard(1);
}
private void btnNewGame_Click(object sender, EventArgs e)
{
newGame();
}
private void btnHit_Click(object sender, EventArgs e)
{
newCard(0); newCard(1);
updateHandValues();
}
private void btnStand_Click(object sender, EventArgs e)
{
if (feelingLucky() == true) newCard(1);
else checkScores(true);
}
}
}
EDIT Here's the code to my new and working version with help from these nice guys below, just in case someone finds it useful, thanks everyone!
Here are the card picture files you'll need to add to your project's resources for this code to work.
I know my logic probably isn't great, but i feel like I've learnt from this little project, hopefully someone else might too, now, time to conjure up something new.. thanks stackoverflow.
Playing Card Pictures Download
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Text.RegularExpressions;
namespace BlackJack_Reworked
{
public partial class BlackJack : Form
{
public BlackJack()
{
InitializeComponent();
}
private PictureBox[] Card = new PictureBox[52];
static List<string> Deck = new List<string>();
class myVars
{
public static int playerX = 230;
public static int cpuX = 230;
public static int playerCardValue = 0;
public static int cpuCardValue = 0;
public static int cardsDrawn = 0;
}
private void newDeck()
{
Deck.Clear();
for (int x = 0; x < myVars.cardsDrawn; x++)
{
Card[x].Dispose();
}
for (int x = 0; x < 52; x++)
{
int cardSuite = (x / 13) + 1;
int faceValue = (x % 13) + 1;
string Suite = null;
switch (cardSuite)
{
case 1:
Suite = "Hearts";
break;
case 2:
Suite = "Diamonds";
break;
case 3:
Suite = "Spades";
break;
case 4:
Suite = "Clubs";
break;
}
Deck.Add(Suite + Convert.ToString(faceValue));
}
Extensions.Shuffle(Deck);
myVars.cardsDrawn = myVars.cpuCardValue = myVars.playerCardValue = 0;
myVars.cpuX = myVars.playerX = 230;
}
private void handCard(string recipient)
{
Random Random = new Random(); Extensions.Shuffle(Deck);
string pickedCard = Deck[Random.Next(Deck.Count)];
int cardvalue = Convert.ToInt32(Regex.Replace(pickedCard, "[^0-9]", ""));
Card[myVars.cardsDrawn] = new PictureBox();
if (recipient == "player") {
Card[myVars.cardsDrawn].Location = new Point(myVars.playerX, 160); myVars.playerX += 15;
myVars.playerCardValue += cardvalue;
}
if (recipient == "cpu") {
Card[myVars.cardsDrawn].Location = new Point(myVars.cpuX, 60); myVars.cpuX += 15;
myVars.cpuCardValue += cardvalue;
}
Card[myVars.cardsDrawn].Image = (Image)Properties.Resources.ResourceManager.GetObject(pickedCard);
Card[myVars.cardsDrawn].Size = new Size(72, 96);
Card[myVars.cardsDrawn].Parent = this;
Card[myVars.cardsDrawn].BringToFront();
Card[myVars.cardsDrawn].Update();
Deck.Remove(pickedCard); myVars.cardsDrawn++; updateHandValues();
}
private void updateHandValues()
{
lblPlayerHand.Text = "Player: " + myVars.playerCardValue.ToString();
lblCPUhand.Text = "CPU: " + myVars.cpuCardValue.ToString();
}
private void newGame()
{
lblBlackJack.Text = "♠ Blackjack ♥";
btnNewGame.Visible = false;
newDeck(); handCard("player"); handCard("cpu");
}
private void checkCards()
{
if (playerWins() == true)
{
lblBlackJack.Text = "♠ You Win! ♥";
btnNewGame.Visible = true;
}
else if (playerWins() == false)
{
lblBlackJack.Text = "♠ Dealer Wins! ♥";
btnNewGame.Visible = true;
}
}
private void tieBreak()
{
if (myVars.cpuCardValue == myVars.playerCardValue && myVars.cpuCardValue >= 17)
{
lblBlackJack.Text = "♠ Tie! ♥";
btnNewGame.Visible = true;
}
else { checkCards(); }
}
private bool? playerWins()
{
if(myVars.cpuCardValue == 21 || myVars.playerCardValue > 21) { return false; }
if(myVars.playerCardValue == 21 || myVars.cpuCardValue > 21) { return true; }
else { return null; }
}
private bool cpuShouldPlay(bool stand)
{
Random Dice = new Random();
if (stand == false)
{
if (myVars.cpuCardValue <= 15) { return true; }
if (myVars.cpuCardValue >= 20 && myVars.cpuCardValue <= 21 && myVars.cpuCardValue > myVars.playerCardValue) { return false; }
if (myVars.cpuCardValue == 19 && myVars.cpuCardValue < myVars.playerCardValue) { return true; } else { return false; }
}
else
{
if(myVars.cpuCardValue < myVars.playerCardValue)
{
return true;
}
else { return false; }
}
}
private void btnNewGame_Click(object sender, EventArgs e)
{
newGame();
}
private void btnHit_Click(object sender, EventArgs e)
{
handCard("player"); if(cpuShouldPlay(false) == true) handCard("cpu"); checkCards();
}
private void btnStand_Click(object sender, EventArgs e)
{
if (cpuShouldPlay(true) == true) handCard("cpu"); tieBreak();
}
}
public static class Extensions
{
public static void Shuffle<T>(this IList<T> list)
{
Random rng = new Random();
int n = list.Count;
while (n > 1)
{
n--;
int k = rng.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
}
}
If you're playing from single deck rules, you must use a 'bag' or 'no replacement' model of random value source. Initially , fill the bag with all 52 possible cards. Then each iteration, pick one card at random from what remains in the bag, removing it from the bag. When the bag is empty, refill it.
Do note that when picking a random card from a bag that has n remaining items, your random value, being the index of the item in the bag to take, must be no larger than n-1 (assuming indicies run from 0 to n-1).
However, there are models of blackjack where multiple decks are shuffled together; many casinos play like this. From Wikipedia Blackjack, rules of play at casinos:
At a casino blackjack table, the dealer faces five to seven playing positions from behind a semicircular table. Between one and eight standard 52-card decks are shuffled together.
In this above model, it is certainly possible for the same card to be dealt twice in a row; however, depending on how many decks are shuffled together, this can happen only a limited number of times.
If I understand your code correctly, you currently model a blackjack shoe that has an infinite number of decks shuffled together.
Random.Next method generates random number from current time stamp and previously generated number (known as 'seed'). As you are create new object of Random everytime, it initializes with same seed. In your case, timestamp and seed doesn't change to 'Next' method of Random.
If you use single object of Random for all your operation, seed will change for each call of 'next'.
Second: You need to keep track of which cards are already drawn, so I've create a shoe list. I will remove the cards which are already used, just like real table.
NOTE: create a new shoe, when your number of cards are let's say 20.
List<string> aShoe = new List<string>(); //shoe contains 4 to 8 decks. Depending upon blackjack version.
int numberOfDeckPerShoe = 4;
private void CreateNewDeck()
{
for(int i =0;i <numberOfDeckPerShoe;i++)
for(int j=0;j<52;j++)
{
int cardFace = (j%13)+1;
int cardSuite = (j/13) + 1;
string Suite = null;
switch (cardSuite)
{
case 1:
Suite = "Hearts";
break;
case 2:
Suite = "Diamonds";
break;
case 3:
Suite = "Spades";
break;
case 4:
Suite = "Clubs";
break;
}
aShoe.add(Suite + Convert.ToString(cardFace));
}
}
Random cardPicker = new Random(); //This is change
private void newCard(int x)
{
int cardChoice = 0;
int houseChoice = 0;
string cardDrawn = "";
int cardToDraow = cardPicker.Next(0,aShoe.length);
cardDrawn = card aShoe[cardToDraow];
card.removeAt(cardToDraow);
if (x == 0)
{
makeCard(cardDrawn, 0);
myVars.playerCardValue += cardChoice;
}
if (x == 1)
{
makeCard(cardDrawn, 1);
myVars.cpuCardValue += cardChoice;
}
}
You are declaring a new Random() within the new card method.
If the method is being called twice, and very quickly, the seed's that are automatically generated (Based on time I believe) will be so close that they will generate pretty much the same number.
The best thing to do would be to create your instance of random outside of the method, and pass the random in each time, that way you will not get the same number each call.