作者:米哈乌·波瓦瓦
来源存储库:二人英雄战斗模拟
二人英雄战斗模拟
该存储库包含以不同方式处理的给定任务(本文件下方)的解决方案。每种方法(已完成)都有自己的分支和标签。应用程序可以通过 cli 运行。
该存储库的目的(对我来说)是练习干净的代码和一些良好的代码设计,如下所示:
- OOP 的四大支柱(对我来说,如果你专注于 SOLID,它们就会自行出现)
- 坚实的原则
- 单一职责(我的每个班级都有自己独特的任务)
- 开放/封闭(当我开始尝试不同的方法时,我的大部分内部结构都没有受到影响,只需要添加新功能)
- 里氏替换原则(我的代码在需要时使用抽象,并且不知道底层实现;例如查看 Unit 和 Colleague 类)
- 接口隔离原则(多个小接口而不是一个大接口)
- 依赖倒置原则(实例化类的唯一地方是 run.php 脚本和工厂,看看 Randomizer - 它可以被嘲笑!我不在任何类中直接使用 rand() )
- 设计模式
- 装饰器(src/修饰符)
- 工厂方法
- 观察者模式(真分支)
- 中介者模式(适当的分支)
- DDD 战术模式
- 值对象(src/属性)
- 聚合(src/Unit - 这里可以封装的所有逻辑都在这里)
- 域服务(TurnService)
- 应用服务(GamePlayService)
- 工厂(工厂)
- 事件(src/Event)(是的,我可以使用事件总线代替)
- 松耦合(源自 SOLID)
操作/事件记录器、错误记录器、打印机(读取器)和核心逻辑彼此松散耦合 - 时分双工
老实说,这不是纯粹的 TDD,首先实现失败的测试,然后在测试通过后源代码(我认为这不切实际),但是在我创建了一些抽象级别或类之后,我立即对其进行了测试并修复了所有小错误,如果我没有考虑到的必要错误或逻辑错误。这就是为什么当我实现 run.php 脚本(这是应用程序的入口点)并且我将其作为最后一步时,代码起作用了!我认为这已经足够好了,不需要纯粹的 TDD。
如何跑
- 运行 docer:
docker-compose up -d
- 运行应用程序:
docker-compose exec cli php run.php
- 运行单元测试
docker-compose exec cli vendor/bin/phpunit tests/
任务
创建Orderus和野兽之间的战斗模拟。每次战斗开始时,野兽和秩序都会生成不同的统计数据,遵循以下规则:
- 订单:
- 生命值:70 - 100
- 强度:70 - 80
- 防御:45 – 55
- 速度:40 – 50
- 运气:10% - 30%(0%表示没有运气,100%一直是幸运)
- 额外技能:
- 快速出击:轮到自己攻击时连击两次;每次攻击时有10%的几率使用该技能
- 魔法护盾:敌人攻击时仅承受普通伤害的一半;每次防守时他都会使用这个技能,有 20% 的变化
- 兽:
- 健康:60 - 90
- 强度:60 - 90
- 防御:40 – 60
- 速度:40 – 60
- 运气:25% - 40%
游戏规则:
- 第一次攻击由速度较高的玩家完成。如果两个玩家的速度相同,则由运气最高的玩家进行攻击。
- 攻击后,玩家交换角色:攻击者现在防守,防御者现在攻击。
- 攻击者造成的伤害计算公式如下:
Damage = Attacker strength – Defender defence
- 伤害将从防御者的生命值中扣除。如果防御者在该回合运气好的话,攻击者可能会错过攻击并且不会造成任何伤害。
- 奥德鲁斯的技能是根据机会随机出现的,因此每回合都要考虑到它们。
- 当其中一名玩家没有生命值或回合数达到 20 时,游戏结束。
- 应用程序必须每回合输出结果:发生了什么、使用了哪些技能(如果有)、造成的伤害、防御者剩余的生命值。
- 如果在达到最大轮数之前我们有获胜者,则必须宣布获胜者。
分支和标签
- 分支:基地;标签: 基础运行应用程序:
包含尚不支持 printig 的基本解决方案(核心功能、单元测试) - 分支:观察者模式;标签:运行应用程序观察者模式:
包含来自base
分支的所有代码,并使用观察者模式通过打印和日志记录来扩展它 - 分支:中介模式;标签:运行应用程序中介模式:
包含来自base
分支的所有代码,并使用调解器模式通过打印和日志记录来扩展它
待添加更多分支和方法...
当前分支:基地
解释的话
最简单和最“网络应用程序”的解决方案是使用一些外部或自制的事件总线,但我只想使用设计模式(有一天我可能会添加该解决方案)。
待办事项
- 忘记实施未命中能力...
- 修复 MagicShield 装饰器中不存在的委托