設(shè)計模式之指令模式——巫師打架

運用指令模式編寫個小游戲突硝,巫師打架

首先介紹下劇情
有兩個巫師测摔,巫師0和巫師1,打架解恰,打架前他們指定了如下的規(guī)則:
游戲規(guī)則
怒吼一次 對方生命值 -5
打槍一次 對方生命值 -10
雙方的初始生命值是100避咆。

實現(xiàn)之后的運行結(jié)果
16:52:04.665 [main] INFO App - 巫師 A 沖 B 大吼一聲
16:52:04.709 [main] INFO App - 巫師 B 沖 A 大吼一聲
16:52:04.709 [main] INFO App - 巫師 B 向 A 施法 纏繞
16:52:04.710 [main] INFO App - 巫師 B 向 A 施法 纏繞
16:52:04.710 [main] INFO App - 巫師 B 沖 A 大吼一聲
16:52:04.710 [main] INFO App - 巫師 A 向 B 施法 寄生
16:52:04.710 [main] INFO App - 巫師 B 沖 A 大吼一聲
16:52:04.711 [main] INFO App - 巫師 A 沖 B 大吼一聲
16:52:04.711 [main] INFO App - 巫師 A 沖 B 大吼一聲
16:52:04.711 [main] INFO App - 巫師 A 沖 B 大吼一聲
16:52:04.711 [main] INFO App - 巫師 A 向 B 施法 寄生
16:52:04.711 [main] INFO App - 巫師 B 向 A 施法 纏繞
16:52:04.712 [main] INFO App - 巫師 A 沖 B 大吼一聲
16:52:04.712 [main] INFO App - 巫師 B 向 A 施法 纏繞
16:52:04.712 [main] INFO App - 巫師 B 向 A 施法 纏繞
16:52:04.712 [main] INFO App - 巫師 B 沖 A 大吼一聲
16:52:04.713 [main] INFO App - 巫師 A 向 B 施法 寄生
16:52:04.713 [main] INFO App - 巫師 B 向 A 施法 纏繞
16:52:04.713 [main] INFO App - 巫師 B 向 A 施法 纏繞
16:52:04.713 [main] INFO App - 巫師 B 向 A 施法 纏繞
16:52:04.713 [main] INFO App - Game over~! 1 win
16:52:04.714 [main] INFO App - 0 wizard's health is : 0
16:52:04.715 [main] INFO App - 1 wizard's health is : 45

設(shè)計實現(xiàn)

該實現(xiàn)模擬計虛擬機及虛擬機應用的關(guān)系;講述app發(fā)送動作到虛擬機修噪,虛擬機解釋執(zhí)行操作的過程,在虛擬機中路媚,引入了一個經(jīng)典變量stack黄琼,指令模擬計算機指令。
指令是由虛擬機定義并解釋執(zhí)行整慎,觸發(fā)方是其身上部署的虛擬機應用脏款。

指令集定義了可以執(zhí)行的低級操作。 一系列指令被編碼為字節(jié)序列裤园。 虛擬機一次一條地執(zhí)行這些指令撤师,將堆棧用于中間值。 通過組合指令拧揽,可以定義復雜的高級行為剃盾。

項目講解

@AllArgsConstructor
@Getter
public enum Instruction {
  LITERAL(1),         // e.g. "LITERAL 0" , push 0 to stack ,將命令后面的參數(shù)推入到棧中
  SET_HEALTH(2),      // e.g. "SET_HEALTH" , 依次在stack彈出 health 值,和 wizard 值淤袜,然后往對應的對象中進行屬性設(shè)置操作
  SET_WISDOM(3),      // e.g. "SET_WISDOM" 痒谴, 依次在stack彈出 wisdom 值,和 wizard 值铡羡,然后往對應的對象中進行屬性設(shè)置操作
  SET_AGILITY(4),     // e.g. "SET_AGILITY" 积蔚, 依次在stack彈出 agility 值,和 wizard 值烦周,然后往對應的對象中進行屬性設(shè)置操作
  PLAY_SOUND(5),      // e.g. "PLAY_SOUND" 尽爆,
  SPAWN_PARTICLES(6),
  GET_HEALTH(7),
  GET_AGILITY(8),
  GET_WISDOM(9),
  ADD(10),
  DIVIDE(11),
  REDUCE(12);

  private final int intValue;

  public static Instruction getInstruction (int value) {
    return Arrays.stream(values()).filter(i -> i.getIntValue() == value).findAny().orElse(null);
  }
}

虛擬機的實際實現(xiàn)如下:

import java.util.Stack;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import lombok.var;

import java.util.concurrent.ThreadLocalRandom;


@Slf4j
@Getter
public class VirtualMachine {

  private final Stack<Integer> stack = new Stack<>();
  /**
   * 一個虛擬機里兩個 向?qū)?   */
  private final Wizard[] wizards = new Wizard[2];

  public VirtualMachine () {
    wizards[0] = new Wizard(randomInt(3, 32), randomInt(3, 32), randomInt(3, 32), 0, 0);
    wizards[1] = new Wizard(randomInt(3, 32), randomInt(3, 32), randomInt(3, 32), 0, 0);
  }

  public VirtualMachine (Wizard wizard1, Wizard wizard2) {
    wizards[0] = wizard1;
    wizards[1] = wizard2;
  }

  public void execute (int[] bytecodes) {
    for (int i = 0; i < bytecodes.length; i++) {
      Instruction instruction = Instruction.getInstruction(bytecodes[i]);
      if (null == instruction) {
        continue;
      }
      switch (instruction) {
        case LITERAL:
          var value = bytecodes[++i];
          stack.push(value);
          break;
        case SET_AGILITY:
          var amount = stack.pop();
          var wizard = stack.pop();
          setAgility(wizard, amount);
          break;
        case SET_WISDOM:
          amount = stack.pop();
          wizard = stack.pop();
          setWisdom(wizard, amount);
          break;
        case SET_HEALTH:
          amount = stack.pop();
          wizard = stack.pop();
          setHealth(wizard, amount);
          break;
        case GET_HEALTH:
          wizard = stack.pop();
          stack.push(getHealth(wizard));
          break;
        case GET_AGILITY:
          wizard = stack.pop();
          stack.push(getAgility(wizard));
          break;
        case ADD:
          var a = stack.pop();
          var b = stack.pop();
          stack.push(a + b);
          break;
        case DIVIDE:
          a = stack.pop();
          b = stack.pop();
          stack.push(b / a);
          break;
        case PLAY_SOUND:
          wizard = stack.pop();
          getWizards()[wizard].playSound();
          break;
        case SPAWN_PARTICLES:
          wizard = stack.pop();
          getWizards()[wizard].spawnParticles();
          break;
        case REDUCE:
          a = stack.pop();
          b = stack.pop();
          stack.push(b - a);
          break;
        default:
          throw new IllegalArgumentException("Invalid instruction value");
      }
      log.trace("Executed {} ,Stack contains {}", instruction.name(), getStack());
    }
  }

  private Integer getAgility (Integer wizard) {
    return wizards[wizard].getAgility();
  }

  private Integer getHealth (Integer wizard) {
    return wizards[wizard].getHealth();
  }

  private void setHealth (Integer wizard, Integer amount) {
    wizards[wizard].setHealth(amount);
  }

  private void setWisdom (Integer wizard, Integer amount) {
    wizards[wizard].setWisdom(amount);
  }


  public void setAgility (int wizard, int amount) {
    wizards[wizard].setAgility(amount);
  }

  private int randomInt (int min, int max) {
    return ThreadLocalRandom.current().nextInt(min, max + 1);
  }
}

app的設(shè)計實現(xiàn)如下:

import lombok.extern.slf4j.Slf4j;
import lombok.var;

@Slf4j
public class App {

  /**
   * 系統(tǒng)指令怎顾,是由字母組合 + 數(shù)組構(gòu)成的
   */
  private static final String LITERAL_0 = "LITERAL 0";
  private static final String HEALTH_PATTERN = "%s_HEALTH";
  private static final String GET_AGILITY = "GET_AGILITY";
  private static final String GET_WISDOM = "GET_WISDOM";
  private static final String ADD = "ADD";
  private static final String REDUCE = "REDUCE";
  private static final String LITERAL_1 = "LITERAL 1";
  private static final String LITERAL_5 = "LITERAL 5";
  private static final String LITERAL_10 = "LITERAL 10";
  private static final String DIVIDE = "DIVIDE";

  public static void main (String[] args) {
    var vm = new VirtualMachine(new Wizard(100, 100, 100, 0, 0), new Wizard(100, 100, 100, 0, 0));
    Script script = new Script();
    do {
      switch (script.action()) {
        case Script.A:
          aPlaySound(vm);
          break;
        case Script.B:
          bPlaySound(vm);
          break;
        case Script.C:
          aPawnedParticles(vm);
          break;
        case Script.D:
          bPawnedParticles(vm);
          break;
      }
    } while (vm.getWizards()[0].getHealth() > 0 && vm.getWizards()[1].getHealth() > 0);
    log.info("Game over~! {} win ", vm.getWizards()[0].getHealth() > vm.getWizards()[1].getHealth() ? 0 : 1);
    log.info("0 wizard's health is : {}", vm.getWizards()[0].getHealth());
    log.info("1 wizard's health is : {}", vm.getWizards()[1].getHealth());
  }


  private static void aPlaySound (VirtualMachine vm) {
    log.info("巫師 A 沖 B 大吼一聲");
    // 給1號巫師減5分
    doHealth(vm, LITERAL_1, LITERAL_5);
  }

  private static void bPlaySound (VirtualMachine vm) {
    log.info("巫師 B 沖 A 大吼一聲");
    // 給0號巫師減5分
    doHealth(vm, LITERAL_0, LITERAL_5);
  }

  private static void bPawnedParticles (VirtualMachine vm) {
    // 給0號巫師減5分
    log.info("巫師 B 向 A 施法 纏繞");
    doHealth(vm, LITERAL_0, LITERAL_10);
  }

  private static void aPawnedParticles (VirtualMachine vm) {
    // 給1號巫師減5分
    log.info("巫師 A 向 B 施法 寄生");
    doHealth(vm, LITERAL_1, LITERAL_10);
  }

  private static void doHealth (VirtualMachine vm, String wizard, String reduceHealth) {
    vm.execute(InstructionConverterUtil.convertToByteCode(wizard));
    vm.execute(InstructionConverterUtil.convertToByteCode(wizard));
    vm.execute(InstructionConverterUtil.convertToByteCode(String.format(HEALTH_PATTERN, "GET")));
    vm.execute(InstructionConverterUtil.convertToByteCode(reduceHealth));
    vm.execute(InstructionConverterUtil.convertToByteCode(REDUCE));
    vm.execute(InstructionConverterUtil.convertToByteCode(String.format(HEALTH_PATTERN, "SET")));
  }
}

項目源碼

魔改前原始地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市漱贱,隨后出現(xiàn)的幾起案子槐雾,更是在濱河造成了極大的恐慌,老刑警劉巖饱亿,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蚜退,死亡現(xiàn)場離奇詭異,居然都是意外死亡彪笼,警方通過查閱死者的電腦和手機钻注,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來配猫,“玉大人幅恋,你說我怎么就攤上這事”靡蓿” “怎么了捆交?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長腐巢。 經(jīng)常有香客問我品追,道長,這世上最難降的妖魔是什么冯丙? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任肉瓦,我火速辦了婚禮,結(jié)果婚禮上胃惜,老公的妹妹穿的比我還像新娘泞莉。我一直安慰自己,他們只是感情好船殉,可當我...
    茶點故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布鲫趁。 她就那樣靜靜地躺著,像睡著了一般利虫。 火紅的嫁衣襯著肌膚如雪挨厚。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天糠惫,我揣著相機與錄音幽崩,去河邊找鬼。 笑死寞钥,一個胖子當著我的面吹牛慌申,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蹄溉,長吁一口氣:“原來是場噩夢啊……” “哼咨油!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起柒爵,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤役电,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后棉胀,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體法瑟,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年唁奢,在試婚紗的時候發(fā)現(xiàn)自己被綠了霎挟。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡麻掸,死狀恐怖酥夭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情脊奋,我是刑警寧澤熬北,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站诚隙,受9級特大地震影響讶隐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜久又,卻給世界環(huán)境...
    茶點故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一整份、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧籽孙,春花似錦、人聲如沸火俄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽瓜客。三九已至适瓦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間谱仪,已是汗流浹背玻熙。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留疯攒,地道東北人嗦随。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親枚尼。 傳聞我的和親對象是個殘疾皇子贴浙,可洞房花燭夜當晚...
    茶點故事閱讀 44,652評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Docker 簡介與概述1.Docker 是一個開源的應用容器引擎,基于 Go 語言 并遵從 Apache2.0 ...
    滔滔逐浪閱讀 323評論 0 0
  • 仿真器是一種很酷的技術(shù)署恍,允許用戶在另一個系統(tǒng)之上運行完全不同的系統(tǒng)崎溃。 模擬器有廣泛的應用程序,例如在ARM設(shè)備上運...
    大前端奕辰閱讀 1,279評論 0 1
  • 1:什么是云計算盯质? 云計算是一種按量付費的模式袁串!云計算的底層是通過虛擬化技術(shù)來實現(xiàn)的! KVM + opensta...
    陪伴是最長情的告白閱讀 119評論 0 0
  • 1.什么是容器 我們在生活中容器有很多,比如盤子,碗,一個桶都可以理解為一個容器 而在Linux中容器就是在隔離的...
    張桐隨寫閱讀 202評論 0 0
  • 馮諾依曼結(jié)構(gòu) 從20世紀初,物理學和電子學科學家們就在爭論制造可以進行數(shù)值計算的機器應該采用什么樣的結(jié)構(gòu)朵逝。人們被十...
    流年_5b31閱讀 142評論 0 0