I'm learning C# using the Head First C# book. In the first lab when building the Greyhound Racing game, I've encountered some behavior and I'm not understanding why my code is rendering the way it is. Upon the first click of the Race button, the horses race to the end of the track, yet they are rendered such that they each create a trail of previous images behind them until they reach the end of the track whereupon the preceding images finally vanish. Upon subsequent clicks of the Race button, the same thing occurs but it also fails to wipe the PictureBox for each dog from the finish line until the current race is complete.
Here's a short 19 second video that demonstrates what I mean: Example of trailing images
Why do the dogs 'trail' during the race, and why do they not vanish from the finish line upon being rendered at the start again until the completion of the next following race? I would think that when the dogs are repositioned in TakeStartingPosition() they would be moved, not redrawn. Same with the Run(), I would think each new position is a move and not a redraw yet it appears to be redrawing the image at each movement step and not wiping the old until the very end of the race. What am I doing incorrectly?
Greyhound.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace RaceTrackSimulator
{
class Greyhound
{
public int StartingPosition;
public int RacetrackLength;
public PictureBox MyPictureBox = null;
public int Location = 0;
public Random Randomizer;
public bool Run()
{
// Move forward either 1, 2, 3 or 4 spaces at random
int moveSpaces = Randomizer.Next(1, 4);
// Update the position of my Picturebox on the form like this:
// MyPictureBox.Left = StartingPosition + Location;
MyPictureBox.Left = StartingPosition + Location;
// Return true if I won the race
if (Location >= RacetrackLength)
{
return true;
}
else
{
Location += moveSpaces;
return false;
}
}
public void TakeStartingPosition()
{
// Reset my location to 0 and my PictureBox to starting position
Location = 0;
MyPictureBox.Left = StartingPosition;
}
}
}
Form1.cs
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 RaceTrackSimulator
{
public partial class Form1 : Form
{
Greyhound[] Dogs;
public Form1()
{
InitializeComponent();
Random MyRandomizer = new Random();
// Initialize Dogs
Dogs = new Greyhound[4];
Dogs[0] = new Greyhound()
{
MyPictureBox = pictureBox2,
StartingPosition = racetrackPictureBox.Left,
RacetrackLength = racetrackPictureBox.Width - pictureBox2.Width,
Randomizer = MyRandomizer
};
Dogs[1] = new Greyhound()
{
MyPictureBox = pictureBox3,
StartingPosition = racetrackPictureBox.Left,
RacetrackLength = racetrackPictureBox.Width - pictureBox3.Width,
Randomizer = MyRandomizer
};
Dogs[2] = new Greyhound()
{
MyPictureBox = pictureBox4,
StartingPosition = racetrackPictureBox.Left,
RacetrackLength = racetrackPictureBox.Width - pictureBox4.Width,
Randomizer = MyRandomizer
};
Dogs[3] = new Greyhound()
{
MyPictureBox = pictureBox5,
StartingPosition = racetrackPictureBox.Left,
RacetrackLength = racetrackPictureBox.Width - pictureBox5.Width,
Randomizer = MyRandomizer
};
}
private void raceButton_Click(object sender, EventArgs e)
{
bool winner = false;
int winningDog = 0;
for (int eachDog = 0; eachDog < Dogs.Length; eachDog++)
{
Dogs[eachDog].TakeStartingPosition();
}
while (!winner)
{
for (int i = 0; i < 4; i++)
{
if (Dogs[i].Run())
{
winner = true;
winningDog = i+1;
}
System.Threading.Thread.Sleep(1);
}
}
MessageBox.Show("Winning Dog is #" + winningDog);
}
}
}
Form1.Designer.cs
namespace RaceTrackSimulator
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.pictureBox2 = new System.Windows.Forms.PictureBox();
this.racetrackPictureBox = new System.Windows.Forms.PictureBox();
this.pictureBox3 = new System.Windows.Forms.PictureBox();
this.pictureBox4 = new System.Windows.Forms.PictureBox();
this.pictureBox5 = new System.Windows.Forms.PictureBox();
this.raceButton = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.racetrackPictureBox)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBox3)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBox4)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBox5)).BeginInit();
this.SuspendLayout();
//
// pictureBox2
//
this.pictureBox2.Image = global::RaceTrackSimulator.Properties.Resources.dog;
this.pictureBox2.Location = new System.Drawing.Point(13, 22);
this.pictureBox2.Name = "pictureBox2";
this.pictureBox2.Size = new System.Drawing.Size(75, 20);
this.pictureBox2.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
this.pictureBox2.TabIndex = 2;
this.pictureBox2.TabStop = false;
//
// racetrackPictureBox
//
this.racetrackPictureBox.Image = global::RaceTrackSimulator.Properties.Resources.racetrack;
this.racetrackPictureBox.Location = new System.Drawing.Point(13, 12);
this.racetrackPictureBox.Name = "racetrackPictureBox";
this.racetrackPictureBox.Size = new System.Drawing.Size(600, 200);
this.racetrackPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
this.racetrackPictureBox.TabIndex = 0;
this.racetrackPictureBox.TabStop = false;
//
// pictureBox3
//
this.pictureBox3.Image = global::RaceTrackSimulator.Properties.Resources.dog;
this.pictureBox3.Location = new System.Drawing.Point(13, 74);
this.pictureBox3.Name = "pictureBox3";
this.pictureBox3.Size = new System.Drawing.Size(75, 20);
this.pictureBox3.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
this.pictureBox3.TabIndex = 3;
this.pictureBox3.TabStop = false;
//
// pictureBox4
//
this.pictureBox4.Image = global::RaceTrackSimulator.Properties.Resources.dog;
this.pictureBox4.Location = new System.Drawing.Point(13, 126);
this.pictureBox4.Name = "pictureBox4";
this.pictureBox4.Size = new System.Drawing.Size(75, 20);
this.pictureBox4.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
this.pictureBox4.TabIndex = 4;
this.pictureBox4.TabStop = false;
//
// pictureBox5
//
this.pictureBox5.Image = global::RaceTrackSimulator.Properties.Resources.dog;
this.pictureBox5.Location = new System.Drawing.Point(13, 178);
this.pictureBox5.Name = "pictureBox5";
this.pictureBox5.Size = new System.Drawing.Size(75, 20);
this.pictureBox5.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
this.pictureBox5.TabIndex = 5;
this.pictureBox5.TabStop = false;
//
// raceButton
//
this.raceButton.Location = new System.Drawing.Point(538, 377);
this.raceButton.Name = "raceButton";
this.raceButton.Size = new System.Drawing.Size(75, 23);
this.raceButton.TabIndex = 6;
this.raceButton.Text = "RACE!";
this.raceButton.UseVisualStyleBackColor = true;
this.raceButton.Click += new System.EventHandler(this.raceButton_Click);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(625, 412);
this.Controls.Add(this.raceButton);
this.Controls.Add(this.pictureBox5);
this.Controls.Add(this.pictureBox4);
this.Controls.Add(this.pictureBox3);
this.Controls.Add(this.pictureBox2);
this.Controls.Add(this.racetrackPictureBox);
this.Name = "Form1";
this.Text = "Form1";
((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.racetrackPictureBox)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBox3)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBox4)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBox5)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.PictureBox racetrackPictureBox;
private System.Windows.Forms.PictureBox pictureBox2;
private System.Windows.Forms.PictureBox pictureBox3;
private System.Windows.Forms.PictureBox pictureBox4;
private System.Windows.Forms.PictureBox pictureBox5;
private System.Windows.Forms.Button raceButton;
}
}
You are running a tight loop in the button click handler handler, which is monopolizing the main UI thread. When the dog moves forward, it is up to the form to repaint itself to "erase" where the dog previously was. Since the code is stuck in the loop, however, it cannot redraw itself. Similarly, when the race is restarted, the dogs do not disappear from the finish line for the same reason.
One possible "quick fix" is to call Application.DoEvents(); in the code to allow the form to update itself. That would look like this:
private void raceButton_Click(object sender, EventArgs e)
{
bool winner = false;
int winningDog = 0;
for (int eachDog = 0; eachDog < Dogs.Length; eachDog++)
{
Dogs[eachDog].TakeStartingPosition();
}
Application.DoEvents();
while (!winner)
{
for (int i = 0; i < 4; i++)
{
if (Dogs[i].Run())
{
winner = true;
winningDog = i+1;
}
Application.DoEvents();
System.Threading.Thread.Sleep(1);
}
}
MessageBox.Show("Winning Dog is #" + winningDog);
}
This, however, is simply a band-aid on top of the real problem: You shouldn't be monopolizing the main UI thread with a long running loop in the button click handler.
One possible solution is reset the dogs in the button click handler, then start a Timer. In the Tick() event of the Timer() you would call each dogs Run() method and check for a winner. When the race has been won, turn the Timer back off.
Related
I'm a fairly new c# programmer currently in class and I've been doing this side project that (kind of) accurately represents bouncing balls. I also want it to be able to handle balls that are created on mouse click. I've done all of this and it works, for a few seconds. The original ball always works and always bounces/rolls. Dynamically created balls that are created on mouse click will hop and roll for a little but then they all freeze(not all at the same time) as the foreach statement I use stops recognizing that they are there. Weirdly enough when the window is resized using the bottom they start to work again. Am I missing something or is this a bug I can't fix? Here's the form code and the designer code. If you need anything else let me know.
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 testBouncingBallMulti
{
public partial class Form1 : Form
{
const int INITY = 0;
const int INITX = 3;
const int GRAVITY = 1;
public Form1()
{
InitializeComponent();
this.ball0.Tag = new Point(INITX, INITY);
}
byte counter = 1;
private void createBall(object sender, MouseEventArgs e)
{
Label l = new Label();
l.BackColor = System.Drawing.Color.Black;
l.Location = new Point(MousePosition.X - this.Left, MousePosition.Y - this.Top);
this.Controls.Add(l);
l.Size = new System.Drawing.Size(15, 15);
l.Tag = new Point(INITX, INITY);
l.Name = "ball" + Convert.ToString(counter);
counter++;
}
private void physicsLoop1(object sender, EventArgs e)
{
foreach (var ball in this.Controls.OfType<Label>())
{
moveBall(ball);
bounce(ball);
Point? init = ball.Tag as Point?;
Point velocities = init.GetValueOrDefault(new Point(0, 0));
if (velocities.Y == 0 && ball.Location.Y >= ClientSize.Height - 15)
{
return;
}
velocities.Y = velocities.Y + GRAVITY;
ball.Tag = new Point(velocities.X, velocities.Y);
}
}
private void moveBall(Control ball)
{
Point? init = ball.Tag as Point?;
Point velocities = init.GetValueOrDefault(new Point(0,0));
ball.Location = new Point(ball.Location.X + velocities.X, ball.Location.Y + velocities.Y);
}
private void bounce(Control ball)
{
Point? init = ball.Tag as Point?;
Point velocities = init.GetValueOrDefault(new Point(0,0));
if (ball.Location.Y >= ClientSize.Height - 15)
{
if (velocities.Y == 0 && ball.Location.Y >= ClientSize.Height - 15)
{
}
else if (ball.Location.Y > ClientSize.Height - 15)
{
ball.Location = new Point(ball.Location.X, ClientSize.Height - 15);
velocities.Y = -(velocities.Y - 2);
}
}
if (ball.Location.X >= ClientSize.Width - 15)
{
velocities.X = -(velocities.X);
}
if (ball.Location.X <= 0)
{
ball.Location = new Point(0, ball.Location.Y);
velocities.X = -(velocities.X);
}
ball.Tag = new Point(velocities.X, velocities.Y);
}
private void physicsLoop2(object sender, EventArgs e)
{
}
private void physicsLoop3(object sender, EventArgs e)
{
}
}
}
and the designer code:
namespace testBouncingBallMulti
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.timer1 = new System.Windows.Forms.Timer(this.components);
this.ball0 = new System.Windows.Forms.Label();
this.timer2 = new System.Windows.Forms.Timer(this.components);
this.timer3 = new System.Windows.Forms.Timer(this.components);
this.SuspendLayout();
//
// timer1
//
this.timer1.Enabled = true;
this.timer1.Interval = 20;
this.timer1.Tick += new System.EventHandler(this.physicsLoop1);
//
// ball0
//
this.ball0.BackColor = System.Drawing.Color.Black;
this.ball0.Location = new System.Drawing.Point(12, 24);
this.ball0.Name = "ball0";
this.ball0.Size = new System.Drawing.Size(15, 15);
this.ball0.TabIndex = 0;
//
// timer2
//
this.timer2.Tick += new System.EventHandler(this.physicsLoop2);
//
// timer3
//
this.timer3.Tick += new System.EventHandler(this.physicsLoop3);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(504, 396);
this.Controls.Add(this.ball0);
this.Name = "Form1";
this.Text = "Form1";
this.MouseClick += new System.Windows.Forms.MouseEventHandler(this.createBall);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Timer timer1;
private System.Windows.Forms.Label ball0;
private System.Windows.Forms.Timer timer2;
private System.Windows.Forms.Timer timer3;
}
}
Replace return with continue in
if (velocities.Y == 0 && ball.Location.Y >= ClientSize.Height - 15)
{
return;
}
You need to give some breathing room in your label move procedure to repaint the form. Either use best practice and place your painting into a thread or at least process a windows message or two in your timer loop.
Thanks to this answer https://stackoverflow.com/a/13734766/637142 I am able to know when a button is pressed or when the steering wheel is rotated. Now my question is how do I send an effect to the device? For example when I am playing a game if I crash the wheel will vibrate. How could I make the steering wheel vibrate?
I belive what I need to do is to Start() an effect (http://sharpdx.org/documentation/api/t-sharpdx-directinput-effect). The SharpDX.DirectInput.Joystick class does not seem to have a method to return me all the effects. There is a method called GetEffects but that method returns a collection of EffectInfo objects. How does a game sends commands to the joystick?
The source code is copy-pasted from here.
To use this source you need a "Force Effect file" (C:\MyEffectFile.ffe), to "play" it on the joystick.
According to this book to create the "force effect" file you need to use the "Force Editor" that came with DirectX SDK.
(the same book, alternatively, state that you can create the effect from scratch in the code... down in the answer I've found another piece of code that create and use an effect without loading it from a file :-))
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using Microsoft.DirectX;
using Microsoft.DirectX.DirectInput;
namespace JoystickProject
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Label label1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
private Device device = null;
private bool running = true;
private ArrayList effectList = new ArrayList();
private bool button0pressed = false;
private string joyState = "";
public bool InitializeInput()
{
// Create our joystick device
foreach(DeviceInstance di in Manager.GetDevices(DeviceClass.GameControl,
EnumDevicesFlags.AttachedOnly | EnumDevicesFlags.ForceFeeback))
{
// Pick the first attached joystick we see
device = new Device(di.InstanceGuid);
break;
}
if (device == null) // We couldn't find a joystick
return false;
device.SetDataFormat(DeviceDataFormat.Joystick);
device.SetCooperativeLevel(this, CooperativeLevelFlags.Exclusive | CooperativeLevelFlags.Background);
device.Properties.AxisModeAbsolute = true;
device.Properties.AutoCenter = false;
device.Acquire();
// Enumerate any axes
foreach(DeviceObjectInstance doi in device.Objects)
{
if ((doi.ObjectId & (int)DeviceObjectTypeFlags.Axis) != 0)
{
// We found an axis, set the range to a max of 10,000
device.Properties.SetRange(ParameterHow.ById,
doi.ObjectId, new InputRange(-5000, 5000));
}
}
// Load our feedback file
EffectList effects = null;
effects = device.GetEffects(#"C:\MyEffectFile.ffe",
FileEffectsFlags.ModifyIfNeeded);
foreach(FileEffect fe in effects)
{
EffectObject myEffect = new EffectObject(fe.EffectGuid, fe.EffectStruct,
device);
myEffect.Download();
effectList.Add(myEffect);
}
while(running)
{
UpdateInputState();
Application.DoEvents();
}
return true;
}
private void PlayEffects()
{
// See if our effects are playing.
foreach(EffectObject myEffect in effectList)
{
//if (button0pressed == true)
//{
//MessageBox.Show("Button Pressed.");
// myEffect.Start(1, EffectStartFlags.NoDownload);
//}
if (!myEffect.EffectStatus.Playing)
{
// If not, play them
myEffect.Start(1, EffectStartFlags.NoDownload);
}
}
//button0pressed = true;
}
protected override void OnClosed(EventArgs e)
{
running = false;
}
private void UpdateInputState()
{
PlayEffects();
// Check the joystick state
JoystickState state = device.CurrentJoystickState;
device.Poll();
joyState = "Using JoystickState: \r\n";
joyState += device.Properties.ProductName;
joyState += "\n";
joyState += device.ForceFeedbackState;
joyState += "\n";
joyState += state.ToString();
byte[] buttons = state.GetButtons();
for(int i = 0; i < buttons.Length; i++)
joyState += string.Format("Button {0} {1}\r\n", i, buttons[i] != 0 ? "Pressed" : "Not Pressed");
label1.Text = joyState;
//if(buttons[0] != 0)
//button0pressed = true;
}
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// label1
//
this.label1.BackColor = System.Drawing.SystemColors.ActiveCaptionText;
this.label1.Location = new System.Drawing.Point(8, 8);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(272, 488);
this.label1.TabIndex = 0;
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.BackColor = System.Drawing.SystemColors.ControlText;
this.ClientSize = new System.Drawing.Size(288, 502);
this.Controls.AddRange(new System.Windows.Forms.Control[] {
this.label1});
this.Name = "Form1";
this.Text = "Joystick Stuff";
this.ResumeLayout(false);
}
#endregion
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
using (Form1 frm = new Form1())
{
frm.Show();
if (!frm.InitializeInput())
MessageBox.Show("Couldn't find a joystick.");
}
}
}
}
I've just found here another piece of code that maybe useful.
This sample seem to create the effect from scratch, so you shouldn't need an "effect file".
DeviceList xDeviceList = Manager.GetDevices(DeviceClass.GameControl, EnumDevicesFlags.AttachedOnly);
DeviceInstance someDeviceInstance;
foreach (DeviceInstance deviceInstance in xDeviceList)
{
someDeviceInstance = deviceInstance;
break;
}
Device someDevice = new Device(someDeviceInstance.InstanceGuid);
someDevice.SetCooperativeLevel(this.Handle, CooperativeLevelFlags.Exclusive | CooperativeLevelFlags.Background);
int[] axis = new int[0];
foreach (DeviceObjectInstance doi in someDevice.Objects)
{
if((doi.Flags & (int)ObjectInstanceFlags.Actuator) != 0)
{
axis = new int[axis.Length + 1];
axis[axis.Length - 1] = doi.Offset;
}
}
someDevice.Acquire();
Effect effect = new Effect();
effect.SetDirection(new int[axis.Length]);
effect.SetAxes(new int[axis.Length]);
effect.ConditionStruct = new Condition[axis.Length];
effect.Flags = EffectFlags.Cartesian | EffectFlags.ObjectOffsets;
effect.Duration = int.MaxValue;
effect.SamplePeriod = 0;
effect.Gain = 10000;
effect.TriggerButton = (int)Microsoft.DirectX.DirectInput.Button.NoTrigger;
effect.TriggerRepeatInterval = 0;
effect.UsesEnvelope = false;
effect.EffectType = Microsoft.DirectX.DirectInput.EffectType.ConstantForce;
effect.StartDelay = 0;
effect.Constant = new Microsoft.DirectX.DirectInput.ConstantForce();
effect.Constant.Magnitude = -5000;
EffectObject effectObject = null;
foreach (EffectInformation ei in someDevice.GetEffects(EffectType.ConstantForce))
{
effectObject = new EffectObject(ei.EffectGuid, effect, someDevice);
}
effectObject.SetParameters(effect, EffectParameterFlags.Start );
And here is another link then may be useful Force feedback sample
I have a problem with the greyhound application that I have created. when I use the radio button to select who is placing a bet (Say Bob) and put his bet amount to 10 on dog number 4, (see image #1) when I click Bets, to update the 'Bob hasnt placed any bets' label with the description() method I get an error (see image #2)
What should happen is where it says "bob hasnt placed any bets" it should now read "bob bets 10 bucks on dog # 4. I have established this is failing due to the bettor returning NULL, but I cannot work out why this is when Bettor is referencing the Guy class which contains the bettor's name.
On a side notem when the race finishes and if Bob wins, he is note getting paid so either the PayOut() or Collect() methods are not working either.
Below are my 3 classes and my Form1.cs
Greyhound.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Drawing;
using System.Windows.Forms;
namespace A_Day_at_the_Races
{
public class Greyhound
{
public int StartingPosition; //Where my PictureBox starts
public int RacetrackLength; // How long the racetrack is
public PictureBox MyPictureBox = null; //My PictureBox object
public int Location = 0; // My Location on the racetrack
public Random Randomizer; // An instance of Random
public bool Run()
{
//1. Move forward either 1,2,3 or 4 spaces at random
int moveforward = Randomizer.Next(1, 4); // declare an int called 'moveforward' will move forward 1,2,3 or 4 spaces at random
//2. Update the position of my PictureBox on the form
Point p = MyPictureBox.Location; // current location of the picture of the greyhound
p.X += moveforward;
MyPictureBox.Location = p;
//3. Return true if I won the race
if (p.X >= RacetrackLength)
return true;
else
return false;
}
public void TakeStartingPosition()
{
//Reset my location to the start line
//MyPictureBox.Location.X = StartingPosition;
StartingPosition = 0;
}
}
}
Guy.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace A_Day_at_the_Races
{
public class Guy
{
public string Name; // The guy's name
public Bet MyBet = null; // An instance of bet() that has how much he's betting
public int Cash; // How much cash he has
// these last two fields are the guy's GUI controls on the form
public RadioButton MyRadioButton; // My RadioButton
public Label MyLabel; // My Label
public void UpdateLabels()
{
//1.Set my label to my bet's description,
if (MyBet == null)
MyLabel.Text = Name + " hasnt placed any bets";
else
MyLabel.Text = MyBet.GetDescription();
//2.Set the label on my radio button to show my cash ("Joe has 43 dollars")
MyRadioButton.Text = Name + " has " + Cash + " bucks";
}
public void ClearBet()
{
//1.Reset my bet so it's zero
MyBet = null;
}
//1.Place a new bet and store it in my bet field
//2.Return true if the guy had enough money to bet
public bool PlaceBet(int Amount, int Dog)
{
this.MyBet = new Bet();
if (Cash >= Amount)
{
Cash = Cash - Amount;
MyLabel = new Label();
MyBet.Amount = Amount;
MyBet.Dog = Dog;
UpdateLabels();
return true;
}
else
{
return false;
}
}
public void Collect(int Winner)
{
if (MyBet != null)
//1.Ask my bet to pay out (hint use the bet object to do the work)
Cash += MyBet.PayOut(Winner);
}
}
}
Bet.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace A_Day_at_the_Races
{
public class Bet
{
public int Amount; // The amount of cash that was bet
public int Dog; // The number of the dog the bet is on
public Guy Bettor; // The guy who placed the bet
public string GetDescription()
{
if (Amount > 0)
return Bettor.Name + " bets " + Amount + " bucks on dog #" + Dog;
else
return Bettor.Name + " hasnt placed a bet";
}
public int PayOut(int Winner)
{
if (Winner == Dog)
return Amount;
else
return -1 * Amount;
}
}
}
Form1.cs
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 A_Day_at_the_Races
{
public partial class Form1 : Form
{
Guy[] Bettors;
Greyhound[] Dogs;
Guy CurrentBettor;
public Form1()
{
InitializeComponent();
Random Randomizer = new Random();
//initialise all my guys and dogs
Bettors = new Guy[3];
Dogs = new Greyhound[4];
//guys
Bettors[0] = new Guy();
Bettors[0].Name = "Joe";
Bettors[0].MyRadioButton = joeRadioButton;
Bettors[0].MyLabel = joeBetLabel;
Bettors[0].Cash = 50;
Bettors[0].UpdateLabels();
Bettors[1] = new Guy();
Bettors[1].Name = "Bob";
Bettors[1].MyRadioButton = bobRadioButton;
Bettors[1].MyLabel = bobBetLabel;
Bettors[1].Cash = 75;
Bettors[1].UpdateLabels();
Bettors[2] = new Guy();
Bettors[2].Name = "Al";
Bettors[2].MyRadioButton = alRadioButton;
Bettors[2].MyLabel = alBetLabel;
Bettors[2].Cash = 45;
Bettors[2].UpdateLabels();
int StartPosition = pictureBoxDog1.Location.X;
int distance = pictureBox1.Width;
for (int i = 0; i < 4; i++)
{
Dogs[i] = new Greyhound();
Dogs[i].Randomizer = Randomizer;
Dogs[i].RacetrackLength = distance;
Dogs[i].Location = Dogs[i].StartingPosition = StartPosition;
}
Dogs[0].MyPictureBox = pictureBoxDog1;
Dogs[1].MyPictureBox = pictureBoxDog2;
Dogs[2].MyPictureBox = pictureBoxDog3;
Dogs[3].MyPictureBox = pictureBoxDog4;
CurrentBettor = Bettors[0];
}
private void RaceButton_Click(object sender, EventArgs e)
{
int winner = 0;
int num_winners = 0;
while (num_winners == 0)
{
for (int i = 0; i < Dogs.Length; i++)
{
if (Dogs[i].Run())
{
num_winners++;
winner = i + 1;
}
}
Application.DoEvents();
System.Threading.Thread.Sleep(3);
}
if (num_winners > 1)
MessageBox.Show("We have " + num_winners + " winners");
else
MessageBox.Show(" Dog #" + winner + "wins!");
for (int i = 0; i < Dogs.Length; i++)
{
Dogs[i].TakeStartingPosition();
}
for (int i = 0; i < Bettors.Length; i ++)
{
Bettors[i].Collect(winner);
Bettors[i].ClearBet();
Bettors[i].UpdateLabels();
}
numericUpDownBet.Value = numericUpDownBet.Minimum;
numericUpDownDog.Value = numericUpDownDog.Minimum;
}
private void joeRadioButton_CheckedChanged(object sender, EventArgs e)
{
SetBettor(0);
}
private void bobRadioButton_CheckedChanged_1(object sender, EventArgs e)
{
SetBettor(1);
}
private void alRadioButton_CheckedChanged_1(object sender, EventArgs e)
{
SetBettor(2);
}
private void BetsButton_Click(object sender, EventArgs e)
{
CurrentBettor.PlaceBet((int)numericUpDownBet.Value, (int)numericUpDownDog.Value);
CurrentBettor.UpdateLabels();
}
private void SetBettor(int index)
{
CurrentBettor = Bettors[index];
NameLabel.Text = CurrentBettor.Name;
if (CurrentBettor.MyBet != null)
{
numericUpDownBet.Value = CurrentBettor.MyBet.Amount;
numericUpDownDog.Value = CurrentBettor.MyBet.Dog;
}
else
{
numericUpDownBet.Value = numericUpDownBet.Minimum;
numericUpDownDog.Value = 1;
}
}
private void Form1_Load(object sender, EventArgs e)
{
minimumBetLabel.Text = "Minimum Bet $5.00";
}
private void ResetButton_Click(object sender, EventArgs e)
{
pictureBoxDog1.Location = new Point(61,32);
pictureBoxDog2.Location = new Point(61,84);
pictureBoxDog3.Location = new Point(61,131);
pictureBoxDog4.Location = new Point(61,181);
}
}
}
Form1.Designer.cs
namespace A_Day_at_the_Races
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1));
this.pictureBox1 = new System.Windows.Forms.PictureBox();
this.pictureBoxDog1 = new System.Windows.Forms.PictureBox();
this.pictureBoxDog2 = new System.Windows.Forms.PictureBox();
this.pictureBoxDog3 = new System.Windows.Forms.PictureBox();
this.pictureBoxDog4 = new System.Windows.Forms.PictureBox();
this.RaceButton = new System.Windows.Forms.Button();
this.minimumBetLabel = new System.Windows.Forms.Label();
this.joeRadioButton = new System.Windows.Forms.RadioButton();
this.bobRadioButton = new System.Windows.Forms.RadioButton();
this.alRadioButton = new System.Windows.Forms.RadioButton();
this.BetsLabel = new System.Windows.Forms.Label();
this.joeBetLabel = new System.Windows.Forms.Label();
this.bobBetLabel = new System.Windows.Forms.Label();
this.alBetLabel = new System.Windows.Forms.Label();
this.NameLabel = new System.Windows.Forms.Label();
this.BetsButton = new System.Windows.Forms.Button();
this.numericUpDownBet = new System.Windows.Forms.NumericUpDown();
this.label1 = new System.Windows.Forms.Label();
this.numericUpDownDog = new System.Windows.Forms.NumericUpDown();
this.ResetButton = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBoxDog1)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBoxDog2)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBoxDog3)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBoxDog4)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.numericUpDownBet)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.numericUpDownDog)).BeginInit();
this.SuspendLayout();
//
// pictureBox1
//
this.pictureBox1.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox1.Image")));
this.pictureBox1.Location = new System.Drawing.Point(12, 12);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(602, 201);
this.pictureBox1.TabIndex = 0;
this.pictureBox1.TabStop = false;
//
// pictureBoxDog1
//
this.pictureBoxDog1.Image = ((System.Drawing.Image)(resources.GetObject("pictureBoxDog1.Image")));
this.pictureBoxDog1.Location = new System.Drawing.Point(22, 21);
this.pictureBoxDog1.Name = "pictureBoxDog1";
this.pictureBoxDog1.Size = new System.Drawing.Size(75, 21);
this.pictureBoxDog1.TabIndex = 1;
this.pictureBoxDog1.TabStop = false;
//
// pictureBoxDog2
//
this.pictureBoxDog2.Image = ((System.Drawing.Image)(resources.GetObject("pictureBoxDog2.Image")));
this.pictureBoxDog2.Location = new System.Drawing.Point(22, 70);
this.pictureBoxDog2.Name = "pictureBoxDog2";
this.pictureBoxDog2.Size = new System.Drawing.Size(75, 22);
this.pictureBoxDog2.TabIndex = 2;
this.pictureBoxDog2.TabStop = false;
//
// pictureBoxDog3
//
this.pictureBoxDog3.Image = ((System.Drawing.Image)(resources.GetObject("pictureBoxDog3.Image")));
this.pictureBoxDog3.Location = new System.Drawing.Point(22, 120);
this.pictureBoxDog3.Name = "pictureBoxDog3";
this.pictureBoxDog3.Size = new System.Drawing.Size(75, 24);
this.pictureBoxDog3.TabIndex = 3;
this.pictureBoxDog3.TabStop = false;
//
// pictureBoxDog4
//
this.pictureBoxDog4.Image = ((System.Drawing.Image)(resources.GetObject("pictureBoxDog4.Image")));
this.pictureBoxDog4.Location = new System.Drawing.Point(22, 170);
this.pictureBoxDog4.Name = "pictureBoxDog4";
this.pictureBoxDog4.Size = new System.Drawing.Size(75, 24);
this.pictureBoxDog4.TabIndex = 4;
this.pictureBoxDog4.TabStop = false;
//
// RaceButton
//
this.RaceButton.Location = new System.Drawing.Point(468, 269);
this.RaceButton.Name = "RaceButton";
this.RaceButton.Size = new System.Drawing.Size(146, 73);
this.RaceButton.TabIndex = 5;
this.RaceButton.Text = "Race!";
this.RaceButton.UseVisualStyleBackColor = true;
this.RaceButton.Click += new System.EventHandler(this.RaceButton_Click);
//
// minimumBetLabel
//
this.minimumBetLabel.AutoSize = true;
this.minimumBetLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.minimumBetLabel.Location = new System.Drawing.Point(9, 241);
this.minimumBetLabel.Name = "minimumBetLabel";
this.minimumBetLabel.Size = new System.Drawing.Size(0, 13);
this.minimumBetLabel.TabIndex = 6;
//
// joeRadioButton
//
this.joeRadioButton.AutoSize = true;
this.joeRadioButton.Location = new System.Drawing.Point(12, 269);
this.joeRadioButton.Name = "joeRadioButton";
this.joeRadioButton.Size = new System.Drawing.Size(85, 17);
this.joeRadioButton.TabIndex = 7;
this.joeRadioButton.TabStop = true;
this.joeRadioButton.Text = "radioButton1";
this.joeRadioButton.UseVisualStyleBackColor = true;
this.joeRadioButton.CheckedChanged += new System.EventHandler(this.joeRadioButton_CheckedChanged);
//
// bobRadioButton
//
this.bobRadioButton.AutoSize = true;
this.bobRadioButton.Location = new System.Drawing.Point(12, 293);
this.bobRadioButton.Name = "bobRadioButton";
this.bobRadioButton.Size = new System.Drawing.Size(85, 17);
this.bobRadioButton.TabIndex = 8;
this.bobRadioButton.TabStop = true;
this.bobRadioButton.Text = "radioButton1";
this.bobRadioButton.UseVisualStyleBackColor = true;
this.bobRadioButton.CheckedChanged += new System.EventHandler(this.bobRadioButton_CheckedChanged_1);
//
// alRadioButton
//
this.alRadioButton.AutoSize = true;
this.alRadioButton.Location = new System.Drawing.Point(12, 317);
this.alRadioButton.Name = "alRadioButton";
this.alRadioButton.Size = new System.Drawing.Size(85, 17);
this.alRadioButton.TabIndex = 9;
this.alRadioButton.TabStop = true;
this.alRadioButton.Text = "radioButton2";
this.alRadioButton.UseVisualStyleBackColor = true;
this.alRadioButton.CheckedChanged += new System.EventHandler(this.alRadioButton_CheckedChanged_1);
//
// BetsLabel
//
this.BetsLabel.AutoSize = true;
this.BetsLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
this.BetsLabel.Location = new System.Drawing.Point(164, 241);
this.BetsLabel.Name = "BetsLabel";
this.BetsLabel.Size = new System.Drawing.Size(32, 13);
this.BetsLabel.TabIndex = 10;
this.BetsLabel.Text = "Bets";
//
// joeBetLabel
//
this.joeBetLabel.AutoSize = true;
this.joeBetLabel.Location = new System.Drawing.Point(164, 269);
this.joeBetLabel.Name = "joeBetLabel";
this.joeBetLabel.Size = new System.Drawing.Size(35, 13);
this.joeBetLabel.TabIndex = 11;
this.joeBetLabel.Text = "label1";
//
// bobBetLabel
//
this.bobBetLabel.AutoSize = true;
this.bobBetLabel.Location = new System.Drawing.Point(164, 293);
this.bobBetLabel.Name = "bobBetLabel";
this.bobBetLabel.Size = new System.Drawing.Size(35, 13);
this.bobBetLabel.TabIndex = 12;
this.bobBetLabel.Text = "label1";
//
// alBetLabel
//
this.alBetLabel.AutoSize = true;
this.alBetLabel.Location = new System.Drawing.Point(164, 317);
this.alBetLabel.Name = "alBetLabel";
this.alBetLabel.Size = new System.Drawing.Size(35, 13);
this.alBetLabel.TabIndex = 13;
this.alBetLabel.Text = "label1";
//
// NameLabel
//
this.NameLabel.AutoSize = true;
this.NameLabel.Location = new System.Drawing.Point(9, 359);
this.NameLabel.Name = "NameLabel";
this.NameLabel.Size = new System.Drawing.Size(0, 13);
this.NameLabel.TabIndex = 14;
//
// BetsButton
//
this.BetsButton.Location = new System.Drawing.Point(54, 354);
this.BetsButton.Name = "BetsButton";
this.BetsButton.Size = new System.Drawing.Size(75, 23);
this.BetsButton.TabIndex = 15;
this.BetsButton.Text = "Bets";
this.BetsButton.UseVisualStyleBackColor = true;
this.BetsButton.Click += new System.EventHandler(this.BetsButton_Click);
//
// numericUpDownBet
//
this.numericUpDownBet.Location = new System.Drawing.Point(135, 357);
this.numericUpDownBet.Minimum = new decimal(new int[] {
5,
0,
0,
0});
this.numericUpDownBet.Name = "numericUpDownBet";
this.numericUpDownBet.Size = new System.Drawing.Size(72, 20);
this.numericUpDownBet.TabIndex = 16;
this.numericUpDownBet.Value = new decimal(new int[] {
5,
0,
0,
0});
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(214, 359);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(113, 13);
this.label1.TabIndex = 17;
this.label1.Text = "bucks on dog number ";
//
// numericUpDownDog
//
this.numericUpDownDog.Location = new System.Drawing.Point(334, 356);
this.numericUpDownDog.Maximum = new decimal(new int[] {
4,
0,
0,
0});
this.numericUpDownDog.Minimum = new decimal(new int[] {
1,
0,
0,
0});
this.numericUpDownDog.Name = "numericUpDownDog";
this.numericUpDownDog.Size = new System.Drawing.Size(79, 20);
this.numericUpDownDog.TabIndex = 18;
this.numericUpDownDog.Value = new decimal(new int[] {
1,
0,
0,
0});
//
// ResetButton
//
this.ResetButton.Location = new System.Drawing.Point(468, 349);
this.ResetButton.Name = "ResetButton";
this.ResetButton.Size = new System.Drawing.Size(146, 41);
this.ResetButton.TabIndex = 19;
this.ResetButton.Text = "Reset";
this.ResetButton.UseVisualStyleBackColor = true;
this.ResetButton.Click += new System.EventHandler(this.ResetButton_Click);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(626, 410);
this.Controls.Add(this.ResetButton);
this.Controls.Add(this.numericUpDownDog);
this.Controls.Add(this.label1);
this.Controls.Add(this.numericUpDownBet);
this.Controls.Add(this.BetsButton);
this.Controls.Add(this.NameLabel);
this.Controls.Add(this.alBetLabel);
this.Controls.Add(this.bobBetLabel);
this.Controls.Add(this.joeBetLabel);
this.Controls.Add(this.BetsLabel);
this.Controls.Add(this.alRadioButton);
this.Controls.Add(this.bobRadioButton);
this.Controls.Add(this.joeRadioButton);
this.Controls.Add(this.minimumBetLabel);
this.Controls.Add(this.RaceButton);
this.Controls.Add(this.pictureBoxDog4);
this.Controls.Add(this.pictureBoxDog3);
this.Controls.Add(this.pictureBoxDog2);
this.Controls.Add(this.pictureBoxDog1);
this.Controls.Add(this.pictureBox1);
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBoxDog1)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBoxDog2)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBoxDog3)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.pictureBoxDog4)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.numericUpDownBet)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.numericUpDownDog)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.PictureBox pictureBox1;
private System.Windows.Forms.PictureBox pictureBoxDog1;
private System.Windows.Forms.PictureBox pictureBoxDog2;
private System.Windows.Forms.PictureBox pictureBoxDog3;
private System.Windows.Forms.PictureBox pictureBoxDog4;
private System.Windows.Forms.Button RaceButton;
private System.Windows.Forms.Label minimumBetLabel;
private System.Windows.Forms.RadioButton joeRadioButton;
private System.Windows.Forms.RadioButton bobRadioButton;
private System.Windows.Forms.RadioButton alRadioButton;
private System.Windows.Forms.Label BetsLabel;
private System.Windows.Forms.Label joeBetLabel;
private System.Windows.Forms.Label bobBetLabel;
private System.Windows.Forms.Label alBetLabel;
private System.Windows.Forms.Label NameLabel;
private System.Windows.Forms.Button BetsButton;
private System.Windows.Forms.NumericUpDown numericUpDownBet;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.NumericUpDown numericUpDownDog;
private System.Windows.Forms.Button ResetButton;
}
}
in PlaceBet method you have forgotten to set the Bettor property:
if (Cash >= Amount)
{
Cash = Cash - Amount;
MyLabel = new Label();
MyBet.Amount = Amount; // HERE
MyBet.Dog = Dog; // HERE
UpdateLabels();
return true;
just add there also a line:
MyBet.Bettor = this;
Explanation/rationale: The point is that without it, when a "Guy" creates a "Bet", the Bet does not get to know who has created it. Nowhere in your code you set the Bettor field, so it never has a chance to be set to something meaningful. The bet will simply retain the default NULL value in this field. As I do not actually read/trace all the code, I think the simpliest way would be to make the Bet know his owner straight from the very beginning.
In Guy.cs when you call PlaceBet(...) and create instantiate the bet, you need to set:
this.MyBet.Bettor = this;
Within this function, this refers to the instance of Guy that is placing the bet.
The second problem you have is with the creation of a new instance of Label, without actually replacing the Label on your form with the new one. In summary fix the PlaceBet(...) method like so:
public bool PlaceBet(int Amount, int Dog)
{
this.MyBet = new Bet();
if (Cash >= Amount)
{
Cash = Cash - Amount;
// remove the following line
// MyLabel = new Label();
MyBet.Amount = Amount;
MyBet.Dog = Dog;
// insert this line...
MyBet.Bettor = this;
UpdateLabels();
return true;
}
else
{
return false;
}
}
I just performed this exercise myself in the book... been running through it. I looked over your code to see how you took care of this problem and I found a pretty big bug in how you handled paying out the betters - In form1.cs when you allow your loop to capture multiple winners you are not continuing to distribute winnings with the Collect method to anyone who bet on anything besides the last winning dog
while (num_winners == 0)
{
for (int i = 0; i < Dogs.Length; i++)
{
if (Dogs[i].Run())
{
num_winners++;
winner = i + 1;
}
}
Application.DoEvents();
System.Threading.Thread.Sleep(3);
}
if (num_winners > 1)
// you say that you have multiple winners right here but you never eval on
//it - winner is still set to one value above
MessageBox.Show("We have " + num_winners + " winners");
else
MessageBox.Show(" Dog #" + winner + "wins!");
for (int i = 0; i < Dogs.Length; i++)
{
Dogs[i].TakeStartingPosition();
}
for (int i = 0; i < Bettors.Length; i ++)
{
Bettors[i].Collect(winner);
Bettors[i].ClearBet();
Bettors[i].UpdateLabels();
}
What will need to be changed to correct this and disperse bets appropriately:
1) Make the betting scheme more realistic - when the bet is placed - subtract the money. You need to allow for a Re-Bet to take place just in case someone wants to redo one of the users on the front page
in guy.cs
public bool PlaceBet(int amount, int dog)
{
// place a new bet and store it in the bet field, return true if there is enough money
if (amount > Cash)
{
MessageBox.Show("I don't have enough money for that bet!", Name + " says...");
return false;
}
else
{
if (this.MyBet == null)
{
this.MyBet = new Bet() { Amount = amount, Bettor = this, Dog = dog };
this.Cash -= amount;
this.UpdateLabels();
return true;
}
else
{
this.Cash += this.MyBet.Amount;
this.MyBet = null;
this.MyBet = new Bet() { Amount = amount, Bettor = this, Dog = dog };
this.Cash -= amount;
this.UpdateLabels();
return true;
}
}
}
2) Now that the betters already lost/submitted their money and we don't have to worry about sending negative monies to them if their dog doesn't win, the Bet.cs Payout method can be updated to only provide a positive return if the winning dog matches their bet dog. if it doesn't, it returns nothing.
public int PayOut(int Winner)
{
// the parameter is the winner of the race. If the dog won, return the amount bet.
// otherwise return nothing
if (Winner == Dog)
{
int payout = Amount*2;
return payout;
}
else
{
int payout = 0;
return payout;
}
}
3) and now we can adjust our scheme in form1.cs to take care of paying multiples (even though this never really happens)
private void formButtonRace_Click(object sender, EventArgs e)
{
int winner = 0;
int windog = 0;
int count = 0;
for (int i = 0; i < Bettors.Length; i++)
{
if (Bettors[1].MyBet != null)
{
count++;
}
}
if (count == Bettors.Length)
{
while (winner == 0)
{
for (int i = 0; i < Dogs.Length; i++)
{
if (Dogs[i].Run())
{
winner++;
windog = i + 1;
for (int i2 = 0; i2 < Bettors.Length; i2++)
{
Bettors[i2].Collect(i + 1);
}
}
Application.DoEvents();
System.Threading.Thread.Sleep(3);
}
}
if (winner > 1)
{
MessageBox.Show("Multiple winners!", "WOW");
}
else
{
MessageBox.Show("The winner was dog #" + windog);
}
for (int i = 0; i < Bettors.Length; i++)
{
Bettors[i].ClearBet(true);
}
for (int i = 0; i < Dogs.Length; i++)
{
Dogs[i].TakeStartingPosition();
}
}
else
{
MessageBox.Show("Not all players have placed their bets!", "Wait wait!");
}
}
The reason why my ClearBet is passing in a bool is because I had to restore the money bet to each individual Guy if the reset button was pressed. However, if the race was completed I wanted to reset them without returning their bets.
This is that section for me in my code:
public void ClearBet(bool isRaceOver)
{
if (isRaceOver)
// reset bet when race is over
{
MyBet = null;
}
else
{
if (this.MyBet != null)
{
Cash += this.MyBet.Amount;
this.MyBet = null;
}
else
{
this.MyBet = null;
}
}
UpdateLabels();
}
In the PlaceBet() method, you are overwriting MyLabel with a new Label() therefore the original context of the label on the form is lost.
Although you are actually updating a Label, it's not the Label on the form.
public bool PlaceBet(int Amount, int Dog)
{
this.MyBet = new Bet();
if (Cash >= Amount)
{
Cash = Cash - Amount;
MyLabel = new Label(); // remove this
MyBet.Amount = Amount;
MyBet.Dog = Dog;
UpdateLabels();
return true;
}
else
{
return false;
}
}
I'm trying to implement a C# drag and drop row-reorder with a listbox. I've come across some snippets of code on the internet but none seem to be working with my needs.
I want you to show me an example code of how to move rows in ListBox.
Thanks!
The moving of rows is done in methods "listBox1_MouseUp and listBox1_MouseDown.
Use view code to change this:
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 Calculator
{
public partial class ComponentMover : Form
{
private Control trackedControl;
private int gridWidth = 100, gridHeight = 20;
private int row;
public ComponentMover()
{
this.InitializeComponent();
this.InitializeDynamic();
}
void draggable_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (this.trackedControl == null)
this.trackedControl = (Control)sender;
}
void draggable_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (this.trackedControl != null)
{
int x = e.X + this.trackedControl.Location.X;
int y = e.Y + this.trackedControl.Location.Y;
Point moved = new Point(x - x % this.gridWidth, y - y % this.gridHeight);
Console.WriteLine(e.X + ", " + e.Y + ", " + ", " + moved.X + ", " + moved.Y);
if (moved != this.trackedControl.Location)
this.trackedControl.Location = moved;
}
}
void draggable_MouseUp(object sender, MouseEventArgs e)
{
this.trackedControl = null;
}
private void AddDragListeners(Control draggable)
{
draggable.MouseDown += new MouseEventHandler(draggable_MouseDown);
draggable.MouseMove += new MouseEventHandler(draggable_MouseMove);
draggable.MouseUp += new MouseEventHandler(draggable_MouseUp);
}
}
}
Designer code:
namespace Calculator
{
// Designer code.
partial class ComponentMover
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
private void InitializeDynamic()
{
this.AddDragListeners(button1);
this.AddDragListeners(button4);
this.AddDragListeners(domainUpDown1);
this.AddDragListeners(textBox1);
this.AddDragListeners(checkBox1);
this.AddDragListeners(radioButton1);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.button4 = new System.Windows.Forms.Button();
this.domainUpDown1 = new System.Windows.Forms.DomainUpDown();
this.textBox1 = new System.Windows.Forms.TextBox();
this.checkBox1 = new System.Windows.Forms.CheckBox();
this.radioButton1 = new System.Windows.Forms.RadioButton();
this.listBox1 = new System.Windows.Forms.ListBox();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(13, 13);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.UseVisualStyleBackColor = true;
//
// button4
//
this.button4.Location = new System.Drawing.Point(177, 43);
this.button4.Name = "button4";
this.button4.Size = new System.Drawing.Size(75, 23);
this.button4.TabIndex = 3;
this.button4.Text = "button4";
this.button4.UseVisualStyleBackColor = true;
//
// domainUpDown1
//
this.domainUpDown1.Location = new System.Drawing.Point(95, 42);
this.domainUpDown1.Name = "domainUpDown1";
this.domainUpDown1.Size = new System.Drawing.Size(74, 20);
this.domainUpDown1.TabIndex = 4;
this.domainUpDown1.Text = "domainUpDown1";
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(177, 72);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(100, 20);
this.textBox1.TabIndex = 5;
//
// checkBox1
//
this.checkBox1.AutoSize = true;
this.checkBox1.Location = new System.Drawing.Point(281, 13);
this.checkBox1.Name = "checkBox1";
this.checkBox1.Size = new System.Drawing.Size(80, 17);
this.checkBox1.TabIndex = 6;
this.checkBox1.Text = "checkBox1";
this.checkBox1.UseVisualStyleBackColor = true;
//
// radioButton1
//
this.radioButton1.AutoSize = true;
this.radioButton1.Location = new System.Drawing.Point(366, 42);
this.radioButton1.Name = "radioButton1";
this.radioButton1.Size = new System.Drawing.Size(85, 17);
this.radioButton1.TabIndex = 7;
this.radioButton1.TabStop = true;
this.radioButton1.Text = "radioButton1";
this.radioButton1.UseVisualStyleBackColor = true;
//
// listBox1
//
this.listBox1.FormattingEnabled = true;
this.listBox1.Items.AddRange(new object[] {
"word1",
"word2",
"word3"});
this.listBox1.Location = new System.Drawing.Point(13, 42);
this.listBox1.Name = "listBox1";
this.listBox1.Size = new System.Drawing.Size(76, 82);
this.listBox1.TabIndex = 8;
this.listBox1.MouseDown += new System.Windows.Forms.MouseEventHandler(listBox1_MouseDown);
this.listBox1.MouseUp += new System.Windows.Forms.MouseEventHandler(listBox1_MouseUp);
//
// ComponentMover
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(485, 159);
this.Controls.Add(this.listBox1);
this.Controls.Add(this.radioButton1);
this.Controls.Add(this.checkBox1);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.domainUpDown1);
this.Controls.Add(this.button4);
this.Controls.Add(this.button1);
this.Name = "ComponentMover";
this.Text = "ComponentMover";
this.ResumeLayout(false);
this.PerformLayout();
}
void listBox1_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
{
System.Windows.Forms.ListBox list = (System.Windows.Forms.ListBox)sender;
int swap = list.SelectedIndex;
if(swap != this.row)
{
string temp = (string)list.Items[this.row];
list.Items[this.row] = list.Items[swap];
list.Items[swap] = temp;
}
}
void listBox1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
this.row = ((System.Windows.Forms.ListBox)sender).SelectedIndex;
}
#endregion
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button4;
private System.Windows.Forms.DomainUpDown domainUpDown1;
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.CheckBox checkBox1;
private System.Windows.Forms.RadioButton radioButton1;
private System.Windows.Forms.ListBox listBox1;
}
}
I have a simple Windows Forms application which is used to calculate the solutions to a quadratic equation. Since it requires some values to be inputted into three different textboxes and then upon clicking a "Calculate" button, makes some calculations with the inputted values. Upon testing the application, and clicking the "Calculate" button prior to inputting any values, I get a Input string was not in a correct format This is due to trying to parse a non-existent value. Is there any way to avoid this? I tried to construct a conditional based on if the button was clicked and there was no values in the textboxes, to not do anything, but that didn't quite work. Here is my designer code:
namespace QuadraticSolver
{
partial class QuadraticSolver
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.lblPrompt = new System.Windows.Forms.Label();
this.lblA = new System.Windows.Forms.Label();
this.lblB = new System.Windows.Forms.Label();
this.lblC = new System.Windows.Forms.Label();
this.txtA = new System.Windows.Forms.TextBox();
this.txtB = new System.Windows.Forms.TextBox();
this.txtC = new System.Windows.Forms.TextBox();
this.btnCalculate = new System.Windows.Forms.Button();
this.lblSolutions = new System.Windows.Forms.Label();
this.txtSolution1 = new System.Windows.Forms.TextBox();
this.txtSolution2 = new System.Windows.Forms.TextBox();
this.chkImaginary = new System.Windows.Forms.CheckBox();
this.SuspendLayout();
//
// lblPrompt
//
this.lblPrompt.AutoSize = true;
this.lblPrompt.Location = new System.Drawing.Point(12, 9);
this.lblPrompt.Name = "lblPrompt";
this.lblPrompt.Size = new System.Drawing.Size(92, 13);
this.lblPrompt.TabIndex = 0;
this.lblPrompt.Text = "Enter Your Values";
//
// lblA
//
this.lblA.AutoSize = true;
this.lblA.Location = new System.Drawing.Point(12, 49);
this.lblA.Name = "lblA";
this.lblA.Size = new System.Drawing.Size(16, 13);
this.lblA.TabIndex = 1;
this.lblA.Text = "a:";
//
// lblB
//
this.lblB.AutoSize = true;
this.lblB.Location = new System.Drawing.Point(12, 85);
this.lblB.Name = "lblB";
this.lblB.Size = new System.Drawing.Size(16, 13);
this.lblB.TabIndex = 2;
this.lblB.Text = "b:";
//
// lblC
//
this.lblC.AutoSize = true;
this.lblC.Location = new System.Drawing.Point(12, 122);
this.lblC.Name = "lblC";
this.lblC.Size = new System.Drawing.Size(16, 13);
this.lblC.TabIndex = 3;
this.lblC.Text = "c:";
//
// txtA
//
this.txtA.Location = new System.Drawing.Point(34, 46);
this.txtA.Name = "txtA";
this.txtA.Size = new System.Drawing.Size(360, 20);
this.txtA.TabIndex = 4;
//
// txtB
//
this.txtB.Location = new System.Drawing.Point(34, 82);
this.txtB.Name = "txtB";
this.txtB.Size = new System.Drawing.Size(360, 20);
this.txtB.TabIndex = 5;
//
// txtC
//
this.txtC.Location = new System.Drawing.Point(34, 122);
this.txtC.Name = "txtC";
this.txtC.Size = new System.Drawing.Size(360, 20);
this.txtC.TabIndex = 6;
//
// btnCalculate
//
this.btnCalculate.Location = new System.Drawing.Point(175, 154);
this.btnCalculate.Name = "btnCalculate";
this.btnCalculate.Size = new System.Drawing.Size(75, 23);
this.btnCalculate.TabIndex = 7;
this.btnCalculate.Text = "Calculate!";
this.btnCalculate.UseVisualStyleBackColor = true;
this.btnCalculate.Click += new System.EventHandler(this.btnCalculate_Click);
//
// lblSolutions
//
this.lblSolutions.AutoSize = true;
this.lblSolutions.Location = new System.Drawing.Point(31, 226);
this.lblSolutions.Name = "lblSolutions";
this.lblSolutions.Size = new System.Drawing.Size(53, 13);
this.lblSolutions.TabIndex = 8;
this.lblSolutions.Text = "Solutions:";
//
// txtSolution1
//
this.txtSolution1.Location = new System.Drawing.Point(34, 242);
this.txtSolution1.Name = "txtSolution1";
this.txtSolution1.ReadOnly = true;
this.txtSolution1.Size = new System.Drawing.Size(165, 20);
this.txtSolution1.TabIndex = 9;
//
// txtSolution2
//
this.txtSolution2.Location = new System.Drawing.Point(222, 242);
this.txtSolution2.Name = "txtSolution2";
this.txtSolution2.ReadOnly = true;
this.txtSolution2.Size = new System.Drawing.Size(172, 20);
this.txtSolution2.TabIndex = 10;
//
// chkImaginary
//
this.chkImaginary.AutoSize = true;
this.chkImaginary.Location = new System.Drawing.Point(33, 189);
this.chkImaginary.Name = "chkImaginary";
this.chkImaginary.Size = new System.Drawing.Size(71, 17);
this.chkImaginary.TabIndex = 11;
this.chkImaginary.Text = "Imaginary";
this.chkImaginary.UseVisualStyleBackColor = true;
//
// QuadraticSolver
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(406, 285);
this.Controls.Add(this.chkImaginary);
this.Controls.Add(this.txtSolution2);
this.Controls.Add(this.txtSolution1);
this.Controls.Add(this.lblSolutions);
this.Controls.Add(this.btnCalculate);
this.Controls.Add(this.txtC);
this.Controls.Add(this.txtB);
this.Controls.Add(this.txtA);
this.Controls.Add(this.lblC);
this.Controls.Add(this.lblB);
this.Controls.Add(this.lblA);
this.Controls.Add(this.lblPrompt);
this.Name = "QuadraticSolver";
this.Text = "Quadratic Solver";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Label lblPrompt;
private System.Windows.Forms.Label lblA;
private System.Windows.Forms.Label lblB;
private System.Windows.Forms.Label lblC;
private System.Windows.Forms.TextBox txtA;
private System.Windows.Forms.TextBox txtB;
private System.Windows.Forms.TextBox txtC;
private System.Windows.Forms.Button btnCalculate;
private System.Windows.Forms.Label lblSolutions;
private System.Windows.Forms.TextBox txtSolution1;
private System.Windows.Forms.TextBox txtSolution2;
private System.Windows.Forms.CheckBox chkImaginary;
}
}
Here is my program's code which does the actual data manipulation:
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 QuadraticSolver
{
public partial class QuadraticSolver : Form
{
public QuadraticSolver()
{
InitializeComponent();
}
private void btnCalculate_Click(object sender, EventArgs e)
{
if (txtA.Text == "" || txtB.Text == "" || txtC.Text == "")
{
string stringSol = "Please enter some values!";
txtSolution1.Text = stringSol;
txtSolution2.Text = stringSol;
}
double aValue = double.Parse(txtA.Text);
double bValue = double.Parse(txtB.Text);
double cValue = double.Parse(txtC.Text);
double solution1Double, solution2Double;
//Quadratic Formula: x = (-b +- sqrt(b^2 - 4ac)) / 2a
//Calculate discriminant
double insideSquareRoot = (bValue * bValue) - 4 * aValue * cValue;
if (insideSquareRoot < 0)
{
//No real solution
solution1Double = Double.NaN;
solution2Double = Double.NaN;
txtSolution1.Text = solution1Double.ToString();
txtSolution2.Text = solution2Double.ToString();
}
else if (insideSquareRoot == 0)
{
//One real solution
double sqrtOneSolution = Math.Sqrt(insideSquareRoot);
solution1Double = (-bValue + sqrtOneSolution) / (2 * aValue);
solution2Double = double.NaN;
txtSolution1.Text = solution1Double.ToString();
txtSolution2.Text = solution2Double.ToString();
}
else if (insideSquareRoot > 0)
{
//Two real solutions
double sqrtTwoSolutions = Math.Sqrt(insideSquareRoot);
solution1Double = (-bValue + sqrtTwoSolutions) / (2 * aValue);
solution2Double = (-bValue - sqrtTwoSolutions) / (2 * aValue);
txtSolution1.Text = solution1Double.ToString();
txtSolution2.Text = solution2Double.ToString();
}
}
}
}
You can use the double.TryParse method.
This is better than checking for == "" since it will tell you that you can not parse "Hello" as a double too.
You also need to return from the event handler if one of the TryParse returns false.
You may consider using a NumericUpDown control instead. You are guaranteed the input from this control will be numeric. All the code that is required is then:
double userNumber = myNumUpDown.Value;
You can even restrict the number input to ensure it falls within your defined range
myNumUpDown.Minimum = 300;
myNumUpDown.Maximum = 500;
Along with many other things. Finally, it even comes with up/down GUI controls so your users can be super lazy and enter the number with their mouse!
You can try this format,
replace the textbox1 with your textbox name.
int a = textbox1.Text != "" ? Convert.ToInt32(textbox1.Text) : 0;
int b = textbox2.Text != "" ? Convert.ToInt32(textbox2.Text) : 0;
int total = a + b;
you can reassign the result this way:
textbox3 = total.toString();
if (txtA.Text == "" || txtB.Text == "" || txtC.Text == "")
{
string stringSol = "Please enter some values!";
txtSolution1.Text = stringSol;
txtSolution2.Text = stringSol;
return;
}