C#及OOP方式编写石头剪刀布的猜拳游戏

概述

OOP(面向对象)较OPP(面向过程)开发效率更高。笔者使用C#编写了一个石头剪刀布的猜拳小游戏供读者学习。

方案原理

UI界面

winform拖拽。。。不解释。。。不会的读者可以参考这2篇。。。图片需要PS协作。
在这里插入图片描述
C#及visual studio入门

C#及winform基础

面向对象

笔者使用了玩家类(play)及计算类(Calculator),玩家类主要存储信息,计算类主要提供方法。

算法

电脑人使用随机数确定出拳顺序,石头剪刀布的概率大体都是1/3。比较及统计后输出结果。

具体实现

玩家类

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

namespace ShitouJiandaoBu
{
    class Player
    {
        //定义变量
        private int Counter_shitou ;
        private int Counter_jiandao;
        private int Counter_bu;
        private int Counter_sum;
        private int Counter_success;
        private int Counter_equal;
        private int Counter_fail;
        private int execulation;
        private double Percent_success;
        private double Percent_equal;
        private double Percent_fail;
        private double Percent_shitou;
        private double Percent_jiandao;
        private double Percent_bu;

        //构造方法
        public Player() {
            Counter_shitou = 1;
            Counter_jiandao = 1;
            Counter_bu = 1;
            Counter_sum = 3;
            Counter_success = 0;
            Counter_equal = 3;
            Counter_fail = 0;
            execulation = 0;
            Percent_success = 0.0;
            Percent_equal = 1.0;
            Percent_fail = 0.0;
            Percent_shitou = 1/3;
            Percent_jiandao = 1/3;
            Percent_bu = 1/3;
        }

        //封装
        //set
        public void shitou() {
            this.Counter_shitou++;
            this.Counter_sum++;
            
        }

        public void jiandao() {
            this.Counter_jiandao++;
            this.Counter_sum++;
        }

        public void bu() {
            this.Counter_bu++;
            this.Counter_sum++;
        }

        public void success() {
            this.Counter_success++;
        }

        public void equal() {
            this.Counter_equal++;
        }

        public void fail() {
            this.Counter_fail++;
        }

        public void Percent() {
            this.Percent_success = (double)Counter_success / (double)Counter_sum;
            this.Percent_equal = (double)Counter_equal / (double)Counter_sum;
            this.Percent_fail = 1.0 - Percent_equal - Percent_success;
            this.Percent_shitou = (double)Counter_shitou / (double)Counter_sum;
            this.Percent_jiandao = (double)Counter_jiandao / (double)Counter_sum;
            this.Percent_bu = 1.0 - Percent_shitou - Percent_jiandao;
        }

        //设置动作:0为石头,1为剪刀,2为布
        public void SetExe(int execulation) {
            this.execulation = execulation;
            switch (this.execulation) {
                case 0:
                    shitou();
                    break;
                case 1:
                    jiandao();
                    break;
                case 2:
                    bu();
                    break;
                default:
                    break;
            }
        }

        //get
        public int Getjiandao() {
            return Counter_jiandao;
        }

        public int Getshitou() {
            return Counter_shitou;
        }

        public int Getbu() {
            return Counter_bu;
        }

        public int GetSc() {
            return Counter_success;
        }

        public int Geteq() {
            return Counter_equal;
        }

        public int GetFl() {
            return Counter_fail;
        }

        public int GetSum() {
            return this.Counter_sum;
        }

        public double GetPctSuccess() {
            return this.Percent_success;
        }

        public double GetPctEqual() {
            return this.Percent_equal;
        }

        public double GetPctFail() {
            return this.Percent_fail;
        }

        public int GetExe() {
            return this.execulation;
        }

        public double GetPctShitou() {
            return this.Percent_shitou;
        }

        public double GetPctJiandao() {
            return this.Percent_jiandao;
        }

        public double GetPctBu() {
            return this.Percent_bu;
        }

    }
}

标准的OOP编写类时需要先定义私有变量,写构造方法(用于初始化类的成员变量),使用get与set封装类确保类内部的安全,编写普通方法。
该类的主要功能是存储数据(并且操作自己的数据)。

定义私有变量

写构造方法

封装类

写普通方法

计算类

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

namespace ShitouJiandaoBu
{
    class Calculator
    {
        //定义变量
        Random Random1 = new Random();
        private double xishu ; 
        private int execulation;
        private int judge;//判断输赢,1vs2输为0,平为1,赢为2
        private double Percent_shitou;
        private double Percent_jiandao;
        private double Percent_bu;


        //构造方法
        public Calculator() {
            this.xishu = 0.0;
            this.judge = 1;
        }

        //封装
        //set
        public void SetPctShitou(double Percent_shitou) {
            this.Percent_shitou = Percent_shitou;
        }

        public void SetPctJiandao(double Percent_jiandao) {
            this.Percent_jiandao = Percent_jiandao;
        }

        public void SetPctBu(double Percent_bu) {
            this.Percent_bu = Percent_bu;
        }

        //get
        public int GetExe() {
            return this.execulation;
        }

        public int GetJudge() {
            return this.judge;
        }

        //类的普通方法
        public void CalRandom() {   //用于计算0~1之间的平均数并确定出拳
            this.xishu = Random1.NextDouble();
        }

        public void CalExeculation1() {//带简单机器学习算法
            if (this.xishu >= 0.0 && this.xishu < Percent_jiandao)
            {
                this.execulation = 0;//出石头
            }
            else if (this.xishu >= Percent_jiandao && this.xishu < (Percent_jiandao+Percent_bu))
            {
                this.execulation = 1;//出剪刀
            }
            else
            {
                this.execulation = 2;//出布
            }
        }

        public void CalExeculation2(){//不带简单机器学习算法
            if (this.xishu >= 0.0 && this.xishu < 0.33)
            {
                this.execulation = 0;//出石头
            }
            else if (this.xishu >= 0.33 && this.xishu < 0.66)
            {
                this.execulation = 1;//出剪刀
            }
            else
            {
                this.execulation = 2;//出布
            }
        }

        public void judge1(int execulation1,int execulation2) { //判断胜负算法1
            if (execulation1 == execulation2) {
                this.judge = 1;
            } else
            if (execulation1 == 0 && execulation2 == 1) { //左石头右剪刀
                this.judge = 0;
            } else
            if (execulation1 == 0 && execulation2 == 2) {//左石头右布
                this.judge = 2;
            } else
            if (execulation1 == 1 && execulation2 == 0){ //左剪刀右石头
                this.judge = 2;
            } else
            if (execulation1 == 1 && execulation2 == 2){//左剪刀右布
                this.judge = 0;
            } else
            if (execulation1 == 2 && execulation2 == 0){ //左布右石头
                this.judge = 0;
            } else
            if (execulation1 == 2 && execulation2 == 1){//左布右剪刀
                this.judge = 2;
            }
        }

    }
}

同样的套路,写出计算类。该类的主要功能就是计算。

定义私有变量

写构造方法

封装类

写普通方法

form事件

初始化

 //定义变量
        public int sum;
        public int exe1;
        public int exe2;
        //public int 
        public Image image1_wenhao = new Bitmap(@"E:\工作文件夹\2021.3.25\素材\左红问号.png");
        public Image image1_shitou = new Bitmap(@"E:\工作文件夹\2021.3.25\素材\左红拳头.png");
        public Image image1_jiandao = new Bitmap(@"E:\工作文件夹\2021.3.25\素材\左红剪刀.png");
        public Image image1_bu = new Bitmap(@"E:\工作文件夹\2021.3.25\素材\左红手掌.png");

        public Image image2_wenhao = new Bitmap(@"E:\工作文件夹\2021.3.25\素材\右绿问号.png");
        public Image image2_shitou = new Bitmap(@"E:\工作文件夹\2021.3.25\素材\右绿拳头.png");
        public Image image2_jiandao = new Bitmap(@"E:\工作文件夹\2021.3.25\素材\右绿剪刀.png");
        public Image image2_bu = new Bitmap(@"E:\工作文件夹\2021.3.25\素材\右绿手掌.png");

        public int num_suanfa = 0;


        //构造函数初始化
        public MainForm()
        {
            InitializeComponent();
            //this.lb_pct_sc1.Text = 25.ToString() + "%";
            //Image image1_wenhao = new Bitmap(@"E:\工作文件夹\2021.3.25\素材\左红问号.png");
            //ra_bu.Enabled = false;
            //ra_jiandao.Enabled = false;
            //ra_shitou.Enabled = false;
            button1.Text = "已经开始第一局";
            button1.Enabled = false;
            //MessageBox.Show("初始化完成");
            open_off.Select();
            ra_shitou.Select();
            ready();
            pb1.Image = image1_wenhao;
            pb2.Image = image2_wenhao;
        }

创造类的实体对象

//创建类的实体对象
        Player player1 = new Player();
        Player player2 = new Player();
        Calculator Calculator = new Calculator();

随机算法切换

private void open_on_CheckedChanged(object sender, EventArgs e)
        {
            if (open_on.Checked) {
                num_suanfa = 1;
                MessageBox.Show("已经打开机器学习模式,玩家的胜率将会降低");
            }
        }

        private void open_off_CheckedChanged(object sender, EventArgs e)
        {
            if (open_off.Checked)
            {
                num_suanfa = 2;
                MessageBox.Show("已经关闭机器学习,玩家的胜率将会提高到1/3附近");
            }
        }

最简单的机器学习算法。。。利用统计结果动态调整随机的概率。。。

玩家图片切换

private void ra_shitou_CheckedChanged(object sender, EventArgs e)
        {
            if (ra_shitou.Checked) {
                pb1.Image = image1_shitou;
                exe1 = 0;
            }
        }

        private void ra_jiandao_CheckedChanged(object sender, EventArgs e)
        {
            if (ra_jiandao.Checked)
            {
                pb1.Image = image1_jiandao;
                exe1 = 1;
            }
        }

        private void ra_bu_CheckedChanged(object sender, EventArgs e)
        {
            if (ra_bu.Checked)
            {
                pb1.Image = image1_bu;
                exe1 = 2;
            }
        }

电脑人准备

#region   电脑人准备
        public void ready() {
            Calculator.CalRandom();
            Calculator.SetPctBu(player1.GetPctBu());
            Calculator.SetPctJiandao(player1.GetPctJiandao());
            Calculator.SetPctShitou(player1.GetPctShitou());

            if (num_suanfa == 1) {//使用机器学习算法
                Calculator.CalExeculation1();
            } else
            if (num_suanfa == 2) { //使用1/3算法
                Calculator.CalExeculation2();
            }

            exe2 = Calculator.GetExe();
            player2.SetExe(exe2);
            //MessageBox.Show(player2.GetSum().ToString());

        }
        #endregion

电脑需要在玩家之前做好准备。

玩家动作

#region   玩家动作
        public void action(){
            player1.SetExe(exe1);
            Calculator.judge1(exe1, exe2);

            switch (Calculator.GetJudge())
            {
                case 0:
                    player1.success();
                    player2.fail();
                    label4.Text = "左边胜利";
                    break;
                case 1:
                    player1.equal();
                    player2.equal();
                    label4.Text = "平局";
                    break;
                case 2:
                    player1.fail();
                    player2.success();
                    label4.Text = "右边胜利";
                    break;
                default:
                    break;
            }

            player1.Percent();
            player2.Percent();

        }
        #endregion

这部分是玩家的动作对游戏的影响,涉及到判断胜负及数据存储等操作。

刷新界面

#region   刷新界面
        public void flush() {
            //更新文字
            lb_sc1.Text = player1.GetSc().ToString();
            lb_eq1.Text = player1.Geteq().ToString();
            lb_fl1.Text = player1.GetFl().ToString();
            lb_pct_sc1.Text = (player1.GetPctSuccess()*100).ToString()+"%";
            lb_pct_eq1.Text = (player1.GetPctEqual()*100).ToString()+"%";
            lb_pct_fl1.Text = (player1.GetPctFail()*100).ToString()+"%";

            lb_sc2.Text = player2.GetSc().ToString();
            lb_eq2.Text = player2.Geteq().ToString();
            lb_fl2.Text = player2.GetFl().ToString();
            lb_pct_sc2.Text = (player1.GetPctFail() * 100).ToString() + "%";
            lb_pct_eq2.Text = (player2.GetPctEqual() * 100).ToString() + "%";
            lb_pct_fl2.Text = (player1.GetPctSuccess() * 100).ToString() + "%";

            //更新右侧图
            if (exe2 == 0) {
                pb2.Image = image2_shitou;
            } else
            if (exe2 == 1) {
                pb2.Image = image2_jiandao;
            } else
            if (exe2 == 2) {
                pb2.Image = image2_bu;
            }

            //更新左侧图
            if (exe1 == 0)
            {
                pb1.Image = image1_shitou;
            }
            else
            if (exe1 == 1)
            {
                pb1.Image = image1_jiandao;
            }
            else
            if (exe1 == 2)
            {
                pb1.Image = image1_bu;
            }


        }
        #endregion

这部分主要是刷新展示的内容,故笔者进行了封装。

调用

#region   准备出拳
        private void button1_Click(object sender, EventArgs e)
        {
            button1.Enabled = false;
            ra_jiandao.Enabled = true;
            ra_shitou.Enabled = true;
            ra_bu.Enabled = true;
            button1.Text = "请出拳";
            ready();
            button2.Enabled = true;
            pb1.Image = image1_wenhao;
            pb2.Image = image2_wenhao;
            label4.Text = "请出拳";
        }
        #endregion


        #region   确定出拳
        private void button2_Click(object sender, EventArgs e)
        {
            //MessageBox.Show(player2.GetSc().ToString());
            button1.Text = "不服,再来一局!";
            button1.Enabled = true;
            button2.Enabled = false;
            ra_jiandao.Enabled = false;
            ra_shitou.Enabled = false;
            ra_bu.Enabled = false;
            action();
            flush();
            
        }
        #endregion

对封装好的方法进行调用,这是主要功能。

效果展示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
开启最简单的机器学习算法后,胜率较之前会降低,尤其是玩家无脑出同一个拳的时候尤为明显。

尾言

算法中判断输赢采用了枚举的方式,事实上,由于只存在0,1,2这3种情况,按照共模的基本原理,还可以判断player1.ex==(player2.ex+2)%3为胜利,player1.ex==(player2.ex+1)%3为失败。

0 00 10 21 01 11 22 02 12 2

没错吧?

至于像样的机器学习算法。。。已经留好了接口,日后有机会学习和验证。

石头剪刀布猜拳小游戏下载链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值