diff --git a/bytecode/README.md b/bytecode/README.md
new file mode 100644
index 000000000..d2fc45e1e
--- /dev/null
+++ b/bytecode/README.md
@@ -0,0 +1,25 @@
+---
+layout: pattern
+title: Bytecode
+folder: bytecode
+permalink: /patterns/bytecode/
+categories: Behavioral
+tags:
+ - Java
+ - Difficulty-Beginner
+---
+
+## Intent
+Allows to encode behaviour as instructions for virtual machine.
+
+## Applicability
+Use the Bytecode pattern when you have a lot of behavior you need to define and your
+game’s implementation language isn’t a good fit because:
+
+* it’s too low-level, making it tedious or error-prone to program in.
+* iterating on it takes too long due to slow compile times or other tooling issues.
+* it has too much trust. If you want to ensure the behavior being defined can’t break the game, you need to sandbox it from the rest of the codebase.
+
+## Credits
+
+* [Game programming patterns](http://gameprogrammingpatterns.com/bytecode.html)
diff --git a/bytecode/etc/bytecode.png b/bytecode/etc/bytecode.png
new file mode 100644
index 000000000..31b6bc6ed
Binary files /dev/null and b/bytecode/etc/bytecode.png differ
diff --git a/bytecode/etc/bytecode.ucls b/bytecode/etc/bytecode.ucls
new file mode 100644
index 000000000..3ec390458
--- /dev/null
+++ b/bytecode/etc/bytecode.ucls
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/bytecode/pom.xml b/bytecode/pom.xml
new file mode 100644
index 000000000..e9e6247f8
--- /dev/null
+++ b/bytecode/pom.xml
@@ -0,0 +1,45 @@
+
+
+
+
+ java-design-patterns
+ com.iluwatar
+ 1.21.0-SNAPSHOT
+
+ 4.0.0
+
+ bytecode
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+
+
\ No newline at end of file
diff --git a/bytecode/src/main/java/com/iluwatar/bytecode/App.java b/bytecode/src/main/java/com/iluwatar/bytecode/App.java
new file mode 100644
index 000000000..90b97bd33
--- /dev/null
+++ b/bytecode/src/main/java/com/iluwatar/bytecode/App.java
@@ -0,0 +1,79 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.bytecode;
+
+import com.iluwatar.bytecode.util.InstructionConverterUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The intention of Bytecode pattern is to give behavior the flexibility of data by encoding it as instructions
+ * for a virtual machine.
+ * An instruction set defines the low-level operations that can be performed. A series of instructions is encoded as
+ * a sequence of bytes. A virtual machine executes these instructions one at a time,
+ * using a stack for intermediate values. By combining instructions, complex high-level behavior can be defined.
+ *
+ * This pattern should be used when there is a need to define high number of behaviours and implementation engine
+ * is not a good choice because
+ * It is too lowe level
+ * Iterating on it takes too long due to slow compile times or other tooling issues.
+ * It has too much trust. If you want to ensure the behavior being defined can’t break the game,
+ * you need to sandbox it from the rest of the codebase.
+ *
+ */
+public class App {
+ private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
+
+ /**
+ * Main app method
+ * @param args command line args
+ */
+ public static void main(String[] args) {
+ VirtualMachine vm = new VirtualMachine();
+
+ Wizard wizard = new Wizard();
+ wizard.setHealth(45);
+ wizard.setAgility(7);
+ wizard.setWisdom(11);
+ vm.getWizards()[0] = wizard;
+
+ interpretInstruction("LITERAL 0", vm);
+ interpretInstruction( "LITERAL 0", vm);
+ interpretInstruction( "GET_HEALTH", vm);
+ interpretInstruction( "LITERAL 0", vm);
+ interpretInstruction( "GET_AGILITY", vm);
+ interpretInstruction( "LITERAL 0", vm);
+ interpretInstruction( "GET_WISDOM ", vm);
+ interpretInstruction( "ADD", vm);
+ interpretInstruction( "LITERAL 2", vm);
+ interpretInstruction( "DIVIDE", vm);
+ interpretInstruction( "ADD", vm);
+ interpretInstruction( "SET_HEALTH", vm);
+ }
+
+ private static void interpretInstruction(String instruction, VirtualMachine vm) {
+ InstructionConverterUtil converter = new InstructionConverterUtil();
+ vm.execute(converter.convertToByteCode(instruction));
+ LOGGER.info(instruction + String.format("%" + (12 - instruction.length()) + "s", "" ) + vm.getStack());
+ }
+}
diff --git a/bytecode/src/main/java/com/iluwatar/bytecode/Instruction.java b/bytecode/src/main/java/com/iluwatar/bytecode/Instruction.java
new file mode 100644
index 000000000..2ceb66e3b
--- /dev/null
+++ b/bytecode/src/main/java/com/iluwatar/bytecode/Instruction.java
@@ -0,0 +1,65 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.bytecode;
+
+/**
+ * Representation of instructions understandable by virtual machine
+ */
+public enum Instruction {
+
+ LITERAL(1),
+ SET_HEALTH(2),
+ SET_WISDOM (3),
+ SET_AGILITY(4),
+ PLAY_SOUND(5),
+ SPAWN_PARTICLES(6),
+ GET_HEALTH(7),
+ GET_AGILITY(8),
+ GET_WISDOM(9),
+ ADD(10),
+ DIVIDE (11);
+
+ private int value;
+
+ Instruction(int value) {
+ this.value = value;
+ }
+
+ public int getIntValue() {
+ return value;
+ }
+
+ /**
+ * Converts integer value to Instruction
+ * @param value value of instruction
+ * @return representation of the instruction
+ */
+ public static Instruction getInstruction(int value) {
+ for (int i = 0; i < Instruction.values().length; i++) {
+ if (Instruction.values()[i].getIntValue() == value) {
+ return Instruction.values()[i];
+ }
+ }
+ throw new IllegalArgumentException("Invalid instruction value");
+ }
+}
diff --git a/bytecode/src/main/java/com/iluwatar/bytecode/VirtualMachine.java b/bytecode/src/main/java/com/iluwatar/bytecode/VirtualMachine.java
new file mode 100644
index 000000000..aedafe514
--- /dev/null
+++ b/bytecode/src/main/java/com/iluwatar/bytecode/VirtualMachine.java
@@ -0,0 +1,142 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.bytecode;
+
+import java.util.Stack;
+
+/**
+ * Implementation of virtual machine
+ */
+public class VirtualMachine {
+
+ private Stack stack = new Stack();
+
+ private Wizard[] wizards = new Wizard[2];
+
+ /**
+ * Constructor
+ */
+ public VirtualMachine() {
+ for (int i = 0; i < wizards.length; i++) {
+ wizards[i] = new Wizard();
+ }
+ }
+
+ /**
+ * Executes provided bytecode
+ * @param bytecode to execute
+ */
+ public void execute(int[] bytecode) {
+ for (int i = 0; i < bytecode.length; i++) {
+ Instruction instruction = Instruction.getInstruction(bytecode[i]);
+ int wizard;
+ int amount;
+ switch (instruction) {
+ case LITERAL:
+ // Read the next byte from the bytecode.
+ int value = bytecode[++i];
+ stack.push(value);
+ break;
+ case SET_AGILITY:
+ amount = stack.pop();
+ 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 GET_WISDOM:
+ wizard = stack.pop();
+ stack.push(getWisdom(wizard));
+ break;
+ case ADD:
+ int a = stack.pop();
+ int 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;
+ default:
+ throw new IllegalArgumentException("Invalid instruction value");
+ }
+ }
+ }
+
+ public Stack getStack() {
+ return stack;
+ }
+
+ public void setHealth(int wizard, int amount) {
+ wizards[wizard].setHealth(amount);
+ }
+
+ public void setWisdom(int wizard, int amount) {
+ wizards[wizard].setWisdom(amount);
+ }
+
+ public void setAgility(int wizard, int amount) {
+ wizards[wizard].setAgility(amount);
+ }
+
+ public int getHealth(int wizard) {
+ return wizards[wizard].getHealth();
+ }
+
+ public int getWisdom(int wizard) {
+ return wizards[wizard].getWisdom();
+ }
+
+ public int getAgility(int wizard) {
+ return wizards[wizard].getAgility();
+ }
+
+ public Wizard[] getWizards() {
+ return wizards;
+ }
+}
diff --git a/bytecode/src/main/java/com/iluwatar/bytecode/Wizard.java b/bytecode/src/main/java/com/iluwatar/bytecode/Wizard.java
new file mode 100644
index 000000000..ca47fd28f
--- /dev/null
+++ b/bytecode/src/main/java/com/iluwatar/bytecode/Wizard.java
@@ -0,0 +1,83 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.bytecode;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class represent game objects which properties can be changed by instructions interpreted by virtual machine
+ */
+public class Wizard {
+ private static final Logger LOGGER = LoggerFactory.getLogger(Wizard.class);
+
+ private int health;
+
+ private int agility;
+ private int wisdom;
+
+ private int numberOfPlayedSounds;
+ private int numberOfSpawnedParticles;
+
+ public int getHealth() {
+ return health;
+ }
+
+ public void setHealth(int health) {
+ this.health = health;
+ }
+
+ public int getAgility() {
+ return agility;
+ }
+
+ public void setAgility(int agility) {
+ this.agility = agility;
+ }
+
+ public int getWisdom() {
+ return wisdom;
+ }
+
+ public void setWisdom(int wisdom) {
+ this.wisdom = wisdom;
+ }
+
+ public void playSound() {
+ LOGGER.info("Playing sound");
+ numberOfPlayedSounds++;
+ }
+
+ public void spawnParticles() {
+ LOGGER.info("Spawning particles");
+ numberOfSpawnedParticles++;
+ }
+
+ public int getNumberOfPlayedSounds() {
+ return numberOfPlayedSounds;
+ }
+
+ public int getNumberOfSpawnedParticles() {
+ return numberOfSpawnedParticles;
+ }
+}
diff --git a/bytecode/src/main/java/com/iluwatar/bytecode/util/InstructionConverterUtil.java b/bytecode/src/main/java/com/iluwatar/bytecode/util/InstructionConverterUtil.java
new file mode 100644
index 000000000..202784d5a
--- /dev/null
+++ b/bytecode/src/main/java/com/iluwatar/bytecode/util/InstructionConverterUtil.java
@@ -0,0 +1,76 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.bytecode.util;
+
+import com.iluwatar.bytecode.Instruction;
+
+/**
+ * Utility class used for instruction validation and conversion
+ */
+public class InstructionConverterUtil {
+ /**
+ * Converts instructions represented as String
+ *
+ * @param instructions to convert
+ * @return array of int representing bytecode
+ */
+ public static int[] convertToByteCode(String instructions) {
+ if (instructions == null || instructions.trim().length() == 0) {
+ return new int[0];
+ }
+
+ String[] splitedInstructions = instructions.trim().split(" ");
+ int[] bytecode = new int[splitedInstructions.length];
+ for (int i = 0; i < splitedInstructions.length; i++) {
+ if (isValidInstruction(splitedInstructions[i])) {
+ bytecode[i] = Instruction.valueOf(splitedInstructions[i]).getIntValue();
+ } else if (isValidInt(splitedInstructions[i])) {
+ bytecode[i] = Integer.valueOf(splitedInstructions[i]);
+ } else {
+ throw new IllegalArgumentException("Invalid instruction or number: " + splitedInstructions[i]);
+ }
+ }
+
+ return bytecode;
+ }
+
+ private static boolean isValidInstruction(String instruction) {
+ try {
+ Instruction.valueOf(instruction);
+ return true;
+ } catch (IllegalArgumentException e) {
+ return false;
+ }
+ }
+
+ private static boolean isValidInt(String value) {
+ try {
+ Integer.parseInt(value);
+ return true;
+ } catch (NumberFormatException e) {
+ return false;
+ }
+ }
+
+
+}
diff --git a/bytecode/src/test/java/com/iluwatar/bytecode/AppTest.java b/bytecode/src/test/java/com/iluwatar/bytecode/AppTest.java
new file mode 100644
index 000000000..014ec7875
--- /dev/null
+++ b/bytecode/src/test/java/com/iluwatar/bytecode/AppTest.java
@@ -0,0 +1,37 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.bytecode;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Application test
+ */
+public class AppTest {
+
+ @Test
+ public void test() {
+ String[] args = {};
+ App.main(args);
+ }
+}
diff --git a/bytecode/src/test/java/com/iluwatar/bytecode/VirtualMachineTest.java b/bytecode/src/test/java/com/iluwatar/bytecode/VirtualMachineTest.java
new file mode 100644
index 000000000..e4379c9ed
--- /dev/null
+++ b/bytecode/src/test/java/com/iluwatar/bytecode/VirtualMachineTest.java
@@ -0,0 +1,154 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.bytecode;
+
+import org.junit.jupiter.api.Test;
+
+import static com.iluwatar.bytecode.Instruction.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/**
+ * Test for {@Link VirtualMachine}
+ */
+public class VirtualMachineTest {
+
+ @Test
+ public void testLiteral() {
+ int[] bytecode = new int[2];
+ bytecode[0] = LITERAL.getIntValue();
+ bytecode[1] = 10;
+
+ VirtualMachine vm = new VirtualMachine();
+ vm.execute(bytecode);
+
+ assertEquals(1, vm.getStack().size());
+ assertEquals(Integer.valueOf(10), vm.getStack().pop());
+ }
+
+ @Test
+ public void testSetHealth() {
+ int wizardNumber = 0;
+ int[] bytecode = new int[5];
+ bytecode[0] = LITERAL.getIntValue();
+ bytecode[1] = wizardNumber;
+ bytecode[2] = LITERAL.getIntValue();
+ bytecode[3] = 50; // health amount
+ bytecode[4] = SET_HEALTH.getIntValue();
+
+ VirtualMachine vm = new VirtualMachine();
+ vm.execute(bytecode);
+
+ assertEquals(50, vm.getWizards()[wizardNumber].getHealth());
+ }
+
+ @Test
+ public void testSetAgility() {
+ int wizardNumber = 0;
+ int[] bytecode = new int[5];
+ bytecode[0] = LITERAL.getIntValue();
+ bytecode[1] = wizardNumber;
+ bytecode[2] = LITERAL.getIntValue();
+ bytecode[3] = 50; // agility amount
+ bytecode[4] = SET_AGILITY.getIntValue();
+
+ VirtualMachine vm = new VirtualMachine();
+ vm.execute(bytecode);
+
+ assertEquals(50, vm.getWizards()[wizardNumber].getAgility());
+ }
+
+ @Test
+ public void testSetWisdom() {
+ int wizardNumber = 0;
+ int[] bytecode = new int[5];
+ bytecode[0] = LITERAL.getIntValue();
+ bytecode[1] = wizardNumber;
+ bytecode[2] = LITERAL.getIntValue();
+ bytecode[3] = 50; // wisdom amount
+ bytecode[4] = SET_WISDOM.getIntValue();
+
+ VirtualMachine vm = new VirtualMachine();
+ vm.execute(bytecode);
+
+ assertEquals(50, vm.getWizards()[wizardNumber].getWisdom());
+ }
+
+ @Test
+ public void testGetHealth() {
+ int wizardNumber = 0;
+ int[] bytecode = new int[8];
+ bytecode[0] = LITERAL.getIntValue();
+ bytecode[1] = wizardNumber;
+ bytecode[2] = LITERAL.getIntValue();
+ bytecode[3] = 50; // health amount
+ bytecode[4] = SET_HEALTH.getIntValue();
+ bytecode[5] = LITERAL.getIntValue();;
+ bytecode[6] = wizardNumber;
+ bytecode[7] = GET_HEALTH.getIntValue();
+
+ VirtualMachine vm = new VirtualMachine();
+ vm.execute(bytecode);
+
+ assertEquals(Integer.valueOf(50), vm.getStack().pop());
+ }
+
+ @Test
+ public void testPlaySound() {
+ int wizardNumber = 0;
+ int[] bytecode = new int[3];
+ bytecode[0] = LITERAL.getIntValue();
+ bytecode[1] = wizardNumber;
+ bytecode[2] = PLAY_SOUND.getIntValue();
+
+ VirtualMachine vm = new VirtualMachine();
+ vm.execute(bytecode);
+
+ assertEquals(0, vm.getStack().size());
+ assertEquals(1, vm.getWizards()[0].getNumberOfPlayedSounds());
+ }
+
+ @Test
+ public void testSpawnParticles() {
+ int wizardNumber = 0;
+ int[] bytecode = new int[3];
+ bytecode[0] = LITERAL.getIntValue();
+ bytecode[1] = wizardNumber;
+ bytecode[2] = SPAWN_PARTICLES.getIntValue();
+
+ VirtualMachine vm = new VirtualMachine();
+ vm.execute(bytecode);
+
+ assertEquals(0, vm.getStack().size());
+ assertEquals(1, vm.getWizards()[0].getNumberOfSpawnedParticles());
+ }
+
+ @Test
+ public void testInvalidInstruction() {
+ int[] bytecode = new int[1];
+ bytecode[0] = 999;
+ VirtualMachine vm = new VirtualMachine();
+
+ assertThrows(IllegalArgumentException.class, () -> vm.execute(bytecode));
+ }
+}
diff --git a/bytecode/src/test/java/com/iluwatar/bytecode/util/InstructionConverterUtilTest.java b/bytecode/src/test/java/com/iluwatar/bytecode/util/InstructionConverterUtilTest.java
new file mode 100644
index 000000000..4743ac109
--- /dev/null
+++ b/bytecode/src/test/java/com/iluwatar/bytecode/util/InstructionConverterUtilTest.java
@@ -0,0 +1,63 @@
+/**
+ * The MIT License
+ * Copyright (c) 2014 Ilkka Seppälä
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.iluwatar.bytecode.util;
+
+import com.iluwatar.bytecode.Instruction;
+import com.iluwatar.bytecode.util.InstructionConverterUtil;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Test for {@Link InstructionConverterUtil}
+ */
+public class InstructionConverterUtilTest {
+ @Test
+ public void testEmptyInstruction() {
+ String instruction = "";
+
+ int[] bytecode = InstructionConverterUtil.convertToByteCode(instruction);
+
+ Assertions.assertEquals(0, bytecode.length);
+ }
+
+ @Test
+ public void testInstructions() {
+ String instructions =
+ "LITERAL 35 SET_HEALTH SET_WISDOM SET_AGILITY PLAY_SOUND SPAWN_PARTICLES GET_HEALTH ADD DIVIDE";
+
+ int[] bytecode = InstructionConverterUtil.convertToByteCode(instructions);
+
+ Assertions.assertEquals(10, bytecode.length);
+ Assertions.assertEquals(Instruction.LITERAL.getIntValue(), bytecode[0]);
+ Assertions.assertEquals(35, bytecode[1]);
+ Assertions.assertEquals(Instruction.SET_HEALTH.getIntValue(), bytecode[2]);
+ Assertions.assertEquals(Instruction.SET_WISDOM.getIntValue(), bytecode[3]);
+ Assertions.assertEquals(Instruction.SET_AGILITY.getIntValue(), bytecode[4]);
+ Assertions.assertEquals(Instruction.PLAY_SOUND.getIntValue(), bytecode[5]);
+ Assertions.assertEquals(Instruction.SPAWN_PARTICLES.getIntValue(), bytecode[6]);
+ Assertions.assertEquals(Instruction.GET_HEALTH.getIntValue(), bytecode[7]);
+ Assertions.assertEquals(Instruction.ADD.getIntValue(), bytecode[8]);
+ Assertions.assertEquals(Instruction.DIVIDE.getIntValue(), bytecode[9]);
+ }
+
+}
diff --git a/pom.xml b/pom.xml
index f305e97d9..c55ed6492 100644
--- a/pom.xml
+++ b/pom.xml
@@ -171,6 +171,7 @@
priority-queue
commander
typeobjectpattern
+ bytecode