賽狗日源碼分享 《Head First C#》第三版

@

前言

這個賽狗日,是給個框架讓自己寫。感覺難度有點大,語言和控件不熟。讀他的說明和程序結構讀了兩三遍。最後才明白要幹啥。寫是寫出來了,但是我感覺還可以優化,優化在最後說明,線來看下效果

效果展示

效果展示

步驟

熟讀任務說明

寫一個程序第一步就是要明白,它要幹啥,他怎麼實現。而不是一遍寫一遍想,寫寫改改,這樣麻煩不說而且還很撈,我們這種新手一般都沒有哪個本事一寫就過。這本書很好,給了程序的結構和邏輯,只要自己想方法實現 就行了。所以要先讀清楚任務說明,以免越寫越亂。

搭界面

書上給的網站應該換地址了,進去不是的,是他們公司官網。無奈網上找不到合適的圖片。只有自己畫了,用PPT簡單畫一個。
👇👇👇👇自己畫的跑道
然後就按照書上的界面搭建一個。👇👇👇👇
搭建的界面
圖片網上好找。拍好佈局,設置好控件的屬性就OK,不想調圖片尺寸,我就用的 背景圖片填充,然後背景圖片設爲自適應。

開始代碼

按照書上的結構代碼分爲一下四個部分:

  1. Form:界面控件的邏輯控制。
  2. Greyhound:賽狗的對象,每個對象控制一條狗。
  3. Guy:賭徒對象,一個賭徒有一個對應的一個對象。
  4. Bet:賭局對象(個人理解),控制一個賭徒本局的下注情況。

From.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 Day_at_the_Races
{
    public partial class Form1 : Form
    {
        Greyhound[] greyhounds = new Greyhound[4];//聲明一個數組管理Grehound對象
        Guy[] guys = new Guy[3];//聲明一個數組管理Guy對象
        Random random = new Random();//創建一個Random對象。

        public Form1()
        {
            InitializeComponent();

            initDog();//初始化狗
            initGuy();//初始化賭徒和對應的賭注。

        }


        /// <summary>
        /// 初始化比賽的狗:綁定狗的圖片對象,賽道的長度,起點位置,隨機Random對象;同時,初始化狗的位置。
        /// </summary>

        public void initDog()
        {
            //創建對象,同時對屬性賦值。
            greyhounds[0] = new Greyhound()
            {
                MypictureBox = dog1,
                StartingPosition = raceRoad.Left,
                RacetrackLength = raceRoad.Width,
                randomizer = random
            };
            //重置狗的位置
            greyhounds[0].TakeStaringPosition();
            //Console.WriteLine("0號狗位置"+ greyhounds[0].StartingPosition);
            //Console.WriteLine("0號狗圖片左邊位置" + greyhounds[0].MypictureBox.Left);
            greyhounds[1] = new Greyhound()
            {
                MypictureBox = dog2,
                StartingPosition = raceRoad.Left,
                RacetrackLength = raceRoad.Width,
                randomizer = random
            };
            greyhounds[1].TakeStaringPosition();
            //0Console.WriteLine("1號狗位置" + greyhounds[1].StartingPosition);
            //Console.WriteLine("1號狗圖片左邊位置" + greyhounds[1].MypictureBox.Left);
            greyhounds[2] = new Greyhound()
            {
                MypictureBox = dog3,
                StartingPosition = raceRoad.Left,
                RacetrackLength = raceRoad.Width,
                randomizer = random
            };
            greyhounds[2].TakeStaringPosition();
            //Console.WriteLine("2號狗位置" + greyhounds[2].StartingPosition);
            //Console.WriteLine("2號狗圖片左邊位置" + greyhounds[2].MypictureBox.Left);
            greyhounds[3] = new Greyhound()
            {
                MypictureBox = dog4,
                StartingPosition = raceRoad.Left,
                RacetrackLength = raceRoad.Width,
                randomizer = random
            };
            greyhounds[3].TakeStaringPosition();
            //Console.WriteLine("3號狗位置" + greyhounds[3].StartingPosition);
            //Console.WriteLine("3號狗圖片左邊位置" + greyhounds[3].MypictureBox.Left);
        }

        /// <summary>
        /// 初始化賭徒,姓名 ,賭資,radio button,和label;最後創建每個的賭注(bet)對象;
        /// </summary>
        public void initGuy()
        {
            guys[0] = new Guy()
            {
                Name = "盧本偉",
                Cash = 50,
                MyRadio = radiolbw,
                Mylabel = lablbwInfo
            };

            guys[1] = new Guy()
            {
                Name = "孫笑川",
                Cash = 60,
                MyRadio = radsxc,
                Mylabel = labsxcInfo
            };


            guys[2] = new Guy()
            {
                Name = "大司馬",
                Cash = 20,
                MyRadio = raddsm,
                Mylabel = labdsmInfo
            };

            initbet();
        }

        /// <summary>
        /// 初始化bet對象,默認以0未初始化。
        /// </summary>
        public void initbet()
        {
            guys[0].UpdateLabel();
            guys[0].PlaceBet(0, 0);

            guys[1].UpdateLabel();
            guys[1].PlaceBet(0, 0);

            guys[2].UpdateLabel();
            guys[2].PlaceBet(0, 0);
        }

        /// <summary>
        /// timer調用的方法,每次調用都進行四條狗的Run函數,檢測到有true返回就開始進行Guy的Collect(),結算。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timer1_Tick(object sender, EventArgs e)
        {
            for (int i = 0; i < 4; i++)
            {

                if (greyhounds[i].Run())
                {
                    timer1.Stop();
                    for (int j = 0; j < 3; j++)
                    {
                        guys[j].Collect(i);

                    }
                    //顯示提示信息
                    MessageBox.Show("本局" + i + "號狗取得勝利!");
                    //釋放每個狗的對象
                    for (int k = 0; k < 4; k++)
                    {
                        greyhounds[k] = null;
                    }
                    //初始化狗
                    initDog();
                    //初始化賭注,賭注對象已經在Collect()裏面刪除。
                    initbet();
                    //將面板組件激活,進行下次賭局。
                    groupBox1.Enabled = true;
                    //重置單選框
                    radiolbw.Checked = false;
                    radsxc.Checked = false;
                    raddsm.Checked = false;
                    money.Text = "0";//下注輸入框重置
                    dog.Text = "0";
                    break;//一定要加上,結束循環,如果不加初始化後還會調用greyhounds[i].Run(),就會不在原點。
                }

            }
        }

        /// <summary>
        /// 點擊後進行最下方Label跟新和兩個輸入框的刷新。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void radiolbw_Click(object sender, EventArgs e)
        {

            labguy.Text = "盧本偉壓注";
            money.Text = "0";
            dog.Text = "0";
        }

        private void raddsm_Click(object sender, EventArgs e)
        {
            labguy.Text = "大司馬壓注";
            money.Text = "0";
            dog.Text = "0";
        }

        private void radsxc_Click(object sender, EventArgs e)
        {
            labguy.Text = "孫笑川壓注";
            money.Text = "0";
            dog.Text = "0";
        }

        /// <summary>
        /// 比賽開始按鈕,激活計時器。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_start_Click(object sender, EventArgs e)
        {

            //驗證本局是否有人下注
            if (guys[0].Mybet.Amount == 0 && guys[1].Mybet.Amount == 0 && guys[2].Mybet.Amount == 0)
            {
                MessageBox.Show("暫無選手下注!");
            }
            else
            {
                groupBox1.Enabled = false;//禁用下注面板
                timer1.Interval = 100;//設置計時器的時間間隔爲100ms。
                timer1.Start();//開始計時器
            }
        }

        /// <summary>
        /// 確認下注按鈕,跟新Guy的bet對象,跟新label
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_ok_Click(object sender, EventArgs e)
        {
            //如果此時選中的是盧本偉的單選按鈕。
            if (radiolbw.Checked)
            {
                if (Int32.Parse(money.Text) < 5)
                {
                    MessageBox.Show("下注金額至少爲5元!");
                }
                else if (Int32.Parse(dog.Text) < 0 || Int32.Parse(dog.Text) > 3)
                {
                    MessageBox.Show("沒有" + Int32.Parse(dog.Text) + "號狗!");
                }
                else
                {
                    guys[0].PlaceBet(Int32.Parse(money.Text), Int32.Parse(dog.Text));//更新bet對象
                    guys[0].UpdateLabel();//更新label
                }

            }
            //如果此時選中的是孫笑川的單選按鈕。
            if (radsxc.Checked)
            {
                if (Int32.Parse(money.Text) < 5)
                {
                    MessageBox.Show("下注金額至少爲5元!");
                }
                else if (Int32.Parse(dog.Text) < 0 || Int32.Parse(dog.Text) > 3)
                {
                    MessageBox.Show("沒有" + Int32.Parse(dog.Text) + "號狗!");
                }
                else
                {
                    guys[1].PlaceBet(Int32.Parse(money.Text), Int32.Parse(dog.Text));
                    guys[1].UpdateLabel();
                }

            }
            //如果此時選中的是大司馬的單選按鈕。
            if (raddsm.Checked)
            {
                if (Int32.Parse(money.Text) < 5)
                {
                    MessageBox.Show("下注金額至少爲5元!");
                }
                else if (Int32.Parse(dog.Text) < 0 || Int32.Parse(dog.Text) > 3)
                {
                    MessageBox.Show("沒有" + Int32.Parse(dog.Text) + "號狗!");
                }
                else
                {
                    guys[2].PlaceBet(Int32.Parse(money.Text), Int32.Parse(dog.Text));
                    guys[2].UpdateLabel();
                }

            }
        }
    }
}

Greyhound.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Day_at_the_Races
{
    public class Greyhound
    {
        public int StartingPosition;//起點位置,我設置的是以賽道的左邊爲起點
        public int RacetrackLength;//賽道長度,就是賽道圖片的with寬度,由於我算終點的寬度,我量的是100個像素,所以計算的時候要減去95(營造衝線假象)
        public PictureBox MypictureBox = null;//狗的圖片
        public int Location = 0;//狗跑出的距離,再次距離上進行位置疊加
        public Random randomizer;

        public bool Run()
        {
            bool isWin = false;//輸贏的標誌變量

            Location += randomizer.Next(0,20);//隨機對象,隨機移動0-20個像素。

            MypictureBox.Left = StartingPosition + Location;//位置更新
            if(MypictureBox.Left>= (RacetrackLength-95) - MypictureBox.Width)//判斷是否衝線,95在上方屬性有解釋。
            {
                isWin = true;
            }
            
            return isWin;
        }

        //初始狗的位置
        public void TakeStaringPosition()
        {
            this.MypictureBox.Left = StartingPosition;
            this.Location = 0;
        }
        
    }
}

Guy.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Day_at_the_Races
{
    public class Guy
    {
        public string Name;//姓名
        public Bet Mybet;//賭注對象
        public int Cash;//賭資

        public RadioButton MyRadio;//radio button對象
        public Label Mylabel;//label對象

        //跟新radio button對象
        public void UpdateLabel()
        {
            MyRadio.Text = Name + "有" + Cash + "元";

        }

        //清除賭局對象
        public void ClearBet()
        {
            Mybet = null;
        }

        //創建賭局對象
        public bool PlaceBet(int BetAmount,int DogTOWin)
        {
            if (Mybet != null)//爲空就初始化
            {
                //if (BetAmount < 5)
                //{
                //    MessageBox.Show("下注金額至少爲5元!");  //已經在開始按鈕處判斷
                //    return false;
                //}
                if(BetAmount > Cash){
                    MessageBox.Show(Name+"的金額不足"+BetAmount+"!");
                    
                    return false;
                }
                else
                {
                    //進行行賭局對象屬性的更新
                    Console.WriteLine("下注成功!");
                    Mybet.Amount = BetAmount;
                    Mybet.dog = DogTOWin;
                    Mylabel.Text = Mybet.GetDiscreaption();
                    return true;
                }
                
            }
            else
            {
                //初始化
                Mybet = new Bet() { Amount = BetAmount, Better = this, dog = DogTOWin };
                Mylabel.Text = Mybet.GetDiscreaption();
                return false;
            }
            
        }

        //進行賭局結算,更新資產,radio button的文字,刪除上局的bet對象。
        public void Collect(int Winner)
        {
            Cash += Mybet.Payout(Winner);
            ClearBet();
            MyRadio.Text= Name + "有" + Cash + "元";
        }
        
    }
}

Bet.cs

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

namespace Day_at_the_Races
{
    public class Bet
    {
        public int Amount;//下注金額
        public int dog;//壓得狗
        public Guy Better;//賭徒

        //賭徒在本局一個描述
        public string GetDiscreaption()
        {
            string dis = "";
            if (Amount == 0)
            {
                dis = Better.Name + "沒有下注";
            }
            else
            {
                
                dis = Better.Name + "下注" + Amount + "元,賭" + dog + "號狗會贏";
                
            }
            return dis;

        }

        //返回本局的輸贏金額
        public int Payout(int Winner)
        {
            if (dog == Winner)
            {
                return Amount;
            }
            else
            {
                return -Amount;
            }

        }
    }
}

寫在後面的話

本次遇見的一些問題

論壇給了這麼好的交流平臺,當然要交流下自己的問題。作爲初學者更應該交流。

  1. 書要仔細,最開始遺漏了一個bet按鈕,書上也不顯眼,糾結了好久Raadiobutton功能寫不好,總不滿意。最後一看下注那句話裏面藏個按鈕。。。這樣就好辦了。
  2. 最後判斷完勝利者,重新初始化狗的位置時總有偏移。👇👇
    在這裏插入圖片描述
    然後我輸出圖片的位置查看一下初始化時圖片的位置發現沒毛病。👇
    在這裏插入圖片描述
    然後我以爲是電腦有問題了,直到一次0號狗跑了第一和一次3號狗跑了第一,一對比才想到,沒有控制好結束的邏輯,結束後不適用break初始化後還會調用後面狗的Run(),從而發生偏移。
    在這裏插入圖片描述

關於優化

可以設定狗的特性

可以參照遊戲設定狗的一些特性,讓比賽隨機,但又可以預料。

去掉Bet類

我覺得哪個Bet類顯得有點礙事,讓程序有點複雜。可以直接合併到Guy類裏面。==這個只是個人見解,如不正確還望大神指點==。

自己的不足

我寫完後自己有看了遍代碼,雖然完成了書上的功能,但是覺得自己也有寫偏的。比如:

  • Bet類默認都創建,我覺得書上得意思是,這局賭了纔會創建一個Bet對象,而我是默認都創建了。同時還增加了多餘的判斷條件。
  • 關於label的跟新我都是依賴Bet類裏面的GetDiscreaption()來獲得文本,總體我覺得不好。

    可能還有許多不足的地方,希望有大佬看出來能夠交流下,我以後避免再犯這樣的錯誤。❤❤❤🙇‍♂️

在這裏插入圖片描述
2020-2-24

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章