当前位置: 首页 > news >正文

策略模式实战 - 猜拳游戏

**可以整体的替换一套算法,这就是策略模式。**这样对于同一个问题,可以有多种解决方案——算法实现的时候,可以通过策略模式来非常方便的进行算法的整体替换,而各种算法是独立封装好的,不用修改其内部逻辑。

具体的实战,下面给出一个经典案例——“猜拳游戏”。该示例来自于【日】结城浩的《图解设计模式》,策略算法做了一些简化调整。

“石头剪刀布”的游戏每轮出什么样的手势,可以遵循一定的策略。比如可以按照下面两种策略来出手势:

  1. 看上一轮自己出的手势,如果赢了,继续用上一轮出的手势;否则出任意的手势
  2. 看上一轮对方出的手势
    1. 如果赢了,就出和上一轮不一样的手势;
    2. 如果上一轮平了(比如出的剪刀),本轮就出石头;
    3. 如果上一轮输了,本轮就出上一轮和对方一样的手势

文章目录

    • 整体类图设计
    • 出手势策略接口
    • 手势类
    • 玩家类
    • 策略实现类
    • 测试类

整体类图设计

在这里插入图片描述

出手势策略接口

因此抽象出一个出手势的策略接口:

/*** Java小卷带你轻松高效学编程,一对一辅导加q1372569394*/
package com.juan.java.designpattern.strategy;/**** @author Java小卷* @date 2024-12-04 14:16* @since 1.0*/
public interface Strategy {/*** 下一回合出手势的方法* @author Java小卷* @date 2024/12/5 14:04* @return 出的手势* @since 1.0*/Hand nextHand();/*** 仔细考虑上一轮的结果,作为下一轮出手势的策略的依据* @author Java小卷* @date 2024/12/5 14:07* @param result 上一轮的结果 0-打平 1-胜 -1-负* @param other 上一轮对方的手势* @since 1.0*/void study(int result, Hand other);}

在这里插入图片描述

手势类

封装了手势具体信息和比手势的方法。

在这里插入图片描述

这里会维护3个公开的静态常量来分别维护“石头、剪刀、布”的手势数值。

/** 出的石头 */
public static final int HANDVALUE_STONE = 0;
/** 出的剪刀 */
public static final int HANDVALUE_SCISSORS = 1;
/** 出的布 */
public static final int HANDVALUE_PAPER = 2;

为方便对三种手势对象的获取,这里的手势值和三种手势对象的数组的索引值保持一致。

Hand类中维护一个私有的静态数组常量,初始化3个手势对象:

/** 初始化三种手势:石头、剪刀、布 */
private static final Hand[] HANDS = {new Hand(HANDVALUE_STONE),new Hand(HANDVALUE_SCISSORS),new Hand(HANDVALUE_PAPER)
};

同时维护一个对应手势名称的静态数组常量:

/** 描述出的手势的名称数组 */
private static final String[] HAND_NAMES = {"石头", "剪刀", "布"};

提供一个代表所出的手势值的成员变量,并提供相应的构造方法完成其初始化,注意Hand类不能在外部实例化,只能在内部维护,因此用private修饰:

/** 出的当前手势值 */
private final int handValue;/** 私有的带有手势值的构造 */
private Hand(int handValue) {this.handValue = handValue;
}

提供几个获取手势信息的方法:

/*** 根据手势值获取对应的手势对象* @param handValue 手势值* @return 对应的手势对象*/
public static Hand getHand(int handValue) {return HANDS[handValue];
}/*** 返回当前实例的手势名称* @author Java小卷* @date 2024/12/4 10:57* @return 手势名称* @since 1.0
*/
@Override
public String toString() {return HAND_NAMES[handValue];
}/*** 获取手势数值* @author Java小卷* @date 2024/12/5 15:14* @return int 手势数值* @since 1.0
*/
public int getHandValue() {return handValue;
}

提供比较手势的方法

/*** 手势对战方法* @author Java小卷* @date 2024/12/4 10:42* @param hand 对方出的手势* @return int 0-平局 1-胜 -1-负* @since 1.0
*/
private int fight(Hand hand) {// 自身比较无意义,但这里也记为平局if (this == hand) {return 0;} else if ((this.handValue + 1) % 3 == hand.handValue) {// 游戏规则:石头>剪刀>布>石头// 因此,只要按照数组的顺序,当前手势的下一个元素与对方手势相等,就认为自己赢了return 1;} else {// 其他情况都是判负return -1;}
}/*** 对外提供的判断赢了方法* @author Java小卷* @date 2024/12/4 10:55* @param hand 对方手势* @return boolean* @since 1.0
*/
public boolean isStrongThan(Hand hand) {return this.fight(hand) == 1;
}

玩家类

Player类在策略模式的类设计中,作为Context,由它负责设置和切换策略并调用策略的行为。

该玩家类除了namestrategy属性外,还包含了全局的状态信息(比赛总轮数、胜的轮数、败的轮数)。另外提供了调用策略对象完成出手势的方法以及对一轮比赛结果处理的方法。

在这里插入图片描述

策略实现类

正如前面一开始介绍的出手势的两种实现策略,这里提供两种具体的实现:

/*** Java小卷带你轻松高效学编程,一对一辅导加q1372569394*/
package com.juan.java.designpattern.strategy.impl;import .../**** @author Java小卷* @date 2024-12-04 14:21* @since 1.0*/
public class WinningStrategy implements Strategy {private final Random random;private int prevResult;private Hand prevHand;public WinningStrategy() {random = new Random();}@Overridepublic Hand nextHand() {// 前一轮不胜,则随意出if (prevResult != 1) {prevHand = Hand.getHand(random.nextInt(3));}// 否则出上一轮的手势return prevHand;}@Overridepublic void study(int result, Hand other) {this.prevResult = result;}
}
/*** Java小卷带你轻松高效学编程,一对一辅导加q1372569394*/
package com.juan.java.designpattern.strategy.impl;import .../**** @author Java小卷* @date 2024-12-04 15:38* @since 1.0*/
public class SmartStrategy implements Strategy {private final Random random;private int prevResult = 1;private Hand prevOtherHand;public SmartStrategy() {this.random = new Random();}@Overridepublic Hand nextHand() {// 如果前一轮平,则出比它大的if (prevResult == 0) {return Hand.getHand(Math.floorMod(prevOtherHand.getHandValue() - 1, 3));} else if (prevResult == -1) {// 输了则出和对方一样的return Hand.getHand(prevOtherHand.getHandValue());} else {// 赢了,则出不一样的if (prevOtherHand == null) {return Hand.getHand(random.nextInt(3));} else {Hand prevHand = Hand.getHand(Math.floorMod(prevOtherHand.getHandValue() - 1, 3));// 出和prevHand不一样的随机手势return Hand.getHand(Math.floorMod(prevHand.getHandValue() + random.nextInt(2) + 1, 3));}}}@Overridepublic void study(int result, Hand other) {this.prevResult = result;this.prevOtherHand = other;}
}

测试类

/*** Java小卷带你轻松高效学编程,一对一辅导加q1372569394*/
package com.juan.java.designpattern.strategy;import .../**** @author Java小卷* @date 2024-12-04 14:46* @since 1.0*/
public class Main {public static void main(String[] args) {Player player1 = new Player("糖宝", new WinningStrategy());Player player2 = new Player("小卷", new SmartStrategy());// 比赛10轮for (int i = 0; i < 10; i++) {Hand hand1 = player1.nextHand();Hand hand2 = player2.nextHand();if (hand1.isStrongThan(hand2)) {System.out.println("胜者: " + player1);player1.win(hand2);player2.lose(hand1);} else if (hand2.isStrongThan(hand1)) {System.out.println("胜者: " + player2);player2.win(hand1);player1.lose(hand2);} else {System.out.println("打平...");player1.even(hand2);player2.even(hand1);}}System.out.println("最终结果:");System.out.println(player1);System.out.println(player2);}}

程序输出:

在这里插入图片描述

相关文章:

策略模式实战 - 猜拳游戏

**可以整体的替换一套算法&#xff0c;这就是策略模式。**这样对于同一个问题&#xff0c;可以有多种解决方案——算法实现的时候&#xff0c;可以通过策略模式来非常方便的进行算法的整体替换&#xff0c;而各种算法是独立封装好的&#xff0c;不用修改其内部逻辑。 具体的实…...

AWS ECS Task 添加 Prometheus 监控采集配置详细指南

以下是一篇完整的博文,介绍如何在 AWS ECS 环境中实现 JVM 监控。 AWS ECS 环境下的 JVM 监控实践 概述 在 AWS ECS (Elastic Container Service) 环境中监控 Java 应用性能是一项重要任务。本文将详细介绍如何使用 AWS Distro for OpenTelemetry (ADOT) 结合 Spring Boot …...

5. 一分钟读懂“工厂方法模式”

5.1 模式介绍 你可能会发现&#xff0c;简单工厂模式没在经典设计模式里出现&#xff0c;别急&#xff0c;它其实只是个常用的编程技巧&#xff0c;而不是标准的设计模式。简单工厂模式有三个要素&#xff1a;1个产品接口、n个产品类、1个工厂类&#xff0c;工厂类通过if/else来…...

基于 AutoFlow 快速搭建基于 TiDB 向量搜索的本地知识库问答机器人

导读 本文将详细介绍如何通过 PingCAP 开源项目 AutoFlow 实现快速搭建基于 TiDB 的本地知识库问答机器人。如果提前准备好 Docker、TiDB 环境&#xff0c;整个搭建过程估计在 10 分钟左右即可完成&#xff0c;无须开发任何代码。 文中使用一篇 TiDB 文档作为本地数据源作为示…...

C语言学习:速通指针(2)

这里要学习的有以下内容 1. const修饰指针 2. 野指针 3. assert断⾔ 4. 指针的使⽤和传址调⽤ 那么从这里开始 1. const 修饰指针 const修饰变量 首先我们知道变量是可以修改的&#xff0c;如果把变量的地址交给⼀个指针变量&#xff0c;通过指针变量的也可以修改这个变…...

windows 上ffmpeg编译好的版本选择

1. Gyan.dev Gyan.dev 是一个广受信赖的 FFmpeg 预编译库提供者&#xff0c;提供多种版本的 FFmpeg&#xff0c;包括静态和动态链接版本。 下载链接: https://www.gyan.dev/ffmpeg/builds/ 特点&#xff1a; 提供最新稳定版和开发版。 支持静态和共享&#xff08;动态&…...

Java设计模式笔记(二)

十四、模版方法模式 1、介绍 1&#xff09;模板方法模式(Template Method Pattern)&#xff0c;又叫模板模式(Template Patern)&#xff0c;在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需重写方法实现&#xff0c;但调用将以抽象类中定义的方式进行。 2&…...

Vue CLI的作用

Vue CLI&#xff08;Command Line Interface&#xff09;是一个基于Vue.js的官方脚手架工具&#xff0c;其主要作用是帮助开发者快速搭建Vue项目的基础结构和开发环境。以下是Vue CLI的具体作用&#xff1a; 1、项目模板与快速生成 Vue CLI提供了一系列预设的项目模板&#x…...

短视频矩阵系统开发|技术源代码部署

短视频矩阵系统通过多账号运营管理、多平台视频智能分发等功能&#xff0c;助力企业实现视频引流、粉丝沉淀和转化。 短视频矩阵系统是一种创新的营销工具&#xff0c;它整合了多账号管理、视频智能分发、数据可视化等多种功能&#xff0c;为企业在短视频领域的发展提供了强大…...

Erlang socket编程(二)

模拟服务器和客户端通信 %%%------------------------------------------------------------------- %%% author Administrator %%% copyright (C) 2024, <COMPANY> %%% doc %%% %%% end %%% Created : 03. 12月 2024 22:28 %%%---------------------------------------…...

工业检测基础-线扫相机和面阵相机参数及应用

以下是工业面阵相机和线扫相机的重要参数、应用场景以及调节方法的科普&#xff1a; 重要参数 分辨率&#xff1a; 面阵相机&#xff1a;由相机所采用的芯片分辨率决定&#xff0c;常用的有500万、1200万、6500万等像素&#xff0c;一般用长宽表示。如19201080等&#xff0c;…...

【无标题】建议用坚果云直接同步zotero,其他方法已经过时,容易出现bug

created: 2024-12-06T16:07:45 (UTC 08:00) tags: [] source: https://zotero-chinese.com/user-guide/sync author: 数据与文件的同步 | Zotero 中文社区 Excerpt Zotero 中文社区&#xff0c;Zotero 中文维护小组&#xff0c;Zotero 插件&#xff0c;Zotero 中文 CSL 样式 数…...

基于STM32设计的智能宠物喂养系统(华为云IOT)_273

文章目录 一、前言1.1 项目介绍【1】项目开发背景【2】设计实现的功能【3】项目硬件模块组成【4】设计意义【5】国内外研究现状【6】摘要1.2 设计思路1.3 系统功能总结1.4 开发工具的选择【1】设备端开发【2】上位机开发1.5 参考文献1.6 系统框架图1.7 系统原理图1.8 实物图1.9…...

cesium truf 利用缓冲如何将一个点缓冲成一个方形

&#xff1a; 在Cesium中如果你想要一个更简单的方法将一个点缓冲成一个方形区域&#xff0c;你可以考虑以下步骤&#xff1a; 确定中心点&#xff1a;首先&#xff0c;你需要有一个中心点的经纬度坐标。计算边长&#xff1a;确定你想要缓冲的方形的边长&#xff0c;这里以10…...

HarmonyOS 5.0应用开发——Ability与Page数据传递

【高心星出品】 文章目录 Ability与Page数据传递Page向Ability传递数据Ability向Page传递数据 Ability与Page数据传递 基于当前的应用模型&#xff0c;可以通过以下几种方式来实现UIAbility组件与UI之间的数据同步。 使用EventHub进行数据通信&#xff1a;在基类Context中提供…...

【推荐算法】推荐系统的评估

这篇文章是笔者阅读《深度学习推荐系统》第五章推荐系统的评估的学习笔记&#xff0c;在原文的基础上增加了自己的理解以及内容的补充&#xff0c;在未来的日子里会不断完善这篇文章的相关工作。 文章目录 离线评估划分数据集方法客观评价指标P-R曲线ROC/AUCmAPNDCG A/B 测试分…...

鸿蒙:实现类似Android.9图的图片资源呈现

问题&#xff1a; 在鸿蒙中&#xff0c;是识别不了.9格式的图片资源的&#xff0c;那么如何实现.9图效果呢。&#xff1f; 解决方案&#xff1a; 首先需要将图片资源转为普通的png格式。如果是背景图的&#xff0c;需要换一种方式来处理&#xff0c;目前我所实现的方案是通过St…...

ros2人脸检测

第一步&#xff1a; 首先在工作空间/src下创建数据结构目录service_interfaces ros2 pkg create service_interfaces --build-type ament_cmake 然后再创建一个srv目录 在里面创建FaceDetect.srv&#xff08;注意&#xff0c;首字母要大写&#xff09; sensor_msgs/Image …...

Pillow:强大的Python图像处理库

目录 一、引言 二、Pillow 库的安装 三、Pillow 库的基本概念 四、图像的读取和保存 五、图像的基本属性 六、图像的裁剪、缩放和旋转 七、图像的颜色调整 八、图像的滤镜效果 九、图像的合成和叠加 十、图像的绘制 十一、示例程序&#xff1a;制作图片水印 十二、…...

微信小程序uni-app+vue3实现局部上下拉刷新和scroll-view动态高度计算

微信小程序uni-appvue3实现局部上下拉刷新和scroll-view动态高度计算 前言 在uni-appvue3项目开发中,经常需要实现列表的局部上下拉刷新功能。由于网上相关教程较少且比较零散,本文将详细介绍如何使用scroll-view组件实现这一功能,包括动态高度计算、下拉刷新、上拉加载等完整…...

为什么类 UNIX 操作系统通常内置编译器?为什么 Windows 更倾向于直接使用二进制文件?

操作系统是否内置编译器&#xff0c;取决于该系统的设计目标、用户群体以及常见的使用场景。以下是内置编译器和直接使用二进制的设计理念和原因的分析&#xff1a; 为什么类 UNIX 操作系统通常内置编译器&#xff1f; 面向开发者的需求&#xff1a; 类 UNIX 系统&#xff08;如…...

吉林大学23级数据结构上机实验(第7周)

A 去火车站 寒假到了&#xff0c;小明准备坐火车回老家&#xff0c;现在他从学校出发去火车站&#xff0c;CC市去火车站有两种方式&#xff1a;轻轨和公交车。小明为了省钱&#xff0c;准备主要以乘坐公交为主。CC市还有一项优惠政策&#xff0c;持学生证可以免费乘坐一站轻轨&…...

实验13 使用预训练resnet18实现CIFAR-10分类

1.数据预处理 首先利用函数transforms.Compose定义了一个预处理函数transform&#xff0c;里面定义了两种操作&#xff0c;一个是将图像转换为Tensor&#xff0c;一个是对图像进行标准化。然后利用函数torchvision.datasets.CIFAR10下载数据集&#xff0c;这个函数有四个常见的…...

【开发文档】资源汇总,持续更新中......

文章目录 AI大模型数据集PytorchPythonUltralyticsOpenCVNetronSklearnCMakeListsNVIDIADocker刷题网站持续更新&#xff0c;欢迎补充 本文汇总了一些常用的开发文档资源&#xff0c;涵盖了常用AI大模型、刷题网站、Python、Pytorch、OpenCV、TensorRT、Docker 等技术栈。通过这…...

【k8s实践】 创建第一个Pod(Nginx)

环境 Rocky Linux9.4 x86_64 VM安装了Microk8s (参考:Microk8s安装方法) 说明: 其他k8s(例如: k3s, kubernetes)创建Pod的方法和Microk8s没啥区别&#xff0c;可以参考本文 目标 创建一个Nginx的Pod&#xff0c;映射宿主机30000端口到Pod容器的80端口&#xff1b;客户端能通…...

盘古大模型实战

0 前言 前一段时间&#xff0c;在学习人工智能的同时&#xff0c;也去了解了一下几乎是作为人工智能在气象上应用的一大里程碑式的研究成果-华为盘古气象大模型。正是盘古大模型的出现&#xff0c;促使天气预报的未来发展方向多了个除天气学方法、统计学方法、数值预报方法之外…...

Python subprocess.run 使用注意事项,避免出现list index out of range

在执行iOS UI 自动化专项测试的时候&#xff0c;在运行第一遍的时候遇到了这样的错误&#xff1a; 2024-12-04 20:22:27 ERROR conftest pytest_runtest_makereport 106 Test test_open_stream.py::TestOpenStream::test_xxx_open_stream[iPhoneX-xxx-1-250] failed with err…...

包管理器npm,cnpm,yarn和pnpm

npm (Node Package Manager) 核心技术与工作原理 依赖解析&#xff1a; 广度优先搜索&#xff08;BFS&#xff09;&#xff1a;npm 使用 BFS 算法来解析依赖树&#xff0c;尽量扁平化 node_modules 目录以减少重复的依赖项。冲突处理&#xff1a;如果两个包需要同一个依赖的不…...

树莓派4B使用opencv读取摄像头配置指南

本文自己记录&#xff0c;给我们lab自己使用&#xff0c;其他朋友们不一定完全适配&#xff0c;请酌情参考。 一. 安装opecnv 我们的树莓派4B默认是armv7l架构&#xff0c;安装的miniconda最新的版本 Miniconda3-latest-Linux-armv7l.sh 仍然是python3.4几乎无法使用&#xff…...

Spring Boot 进阶话题:部署

部署是将应用程序从开发环境移动到可以供用户访问的生产环境的过程。Spring Boot提供了多种部署选项&#xff0c;包括打包为可执行jar文件&#xff0c;使用Docker容器化&#xff0c;以及部署到云平台。 打包Spring Boot应用 Spring Boot应用可以打包为包含所有依赖、类和资源…...