運用指令模式編寫個小游戲突硝,巫師打架
首先介紹下劇情
有兩個巫師测摔,巫師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")));
}
}