From a7182ed402f665bbbafa3c6addb055b880f2e803 Mon Sep 17 00:00:00 2001
From: journich <70119791+journich@users.noreply.github.com>
Date: Wed, 24 Feb 2021 11:48:12 +1030
Subject: [PATCH] Java version of the Bug Basic game
---
16 Bug/java/src/Bug.java | 254 +++++++++++++++++++++
16 Bug/java/src/BugGame.java | 10 +
16 Bug/java/src/ComputerBug.java | 15 ++
16 Bug/java/src/Insect.java | 363 +++++++++++++++++++++++++++++++
16 Bug/java/src/PlayerBug.java | 18 ++
5 files changed, 660 insertions(+)
create mode 100644 16 Bug/java/src/Bug.java
create mode 100644 16 Bug/java/src/BugGame.java
create mode 100644 16 Bug/java/src/ComputerBug.java
create mode 100644 16 Bug/java/src/Insect.java
create mode 100644 16 Bug/java/src/PlayerBug.java
diff --git a/16 Bug/java/src/Bug.java b/16 Bug/java/src/Bug.java
new file mode 100644
index 00000000..626615de
--- /dev/null
+++ b/16 Bug/java/src/Bug.java
@@ -0,0 +1,254 @@
+import java.util.ArrayList;
+import java.util.Scanner;
+
+/**
+ * Game of Bug
+ *
+ * Based on the Basic game of Bug here
+ * https://github.com/coding-horror/basic-computer-games/blob/main/16%20Bug/bug.bas
+ *
+ * Note: The idea was to create a version of the 1970's Basic game in Java, without introducing
+ * new features - no additional text, error checking, etc has been added.
+ */
+public class Bug {
+
+ // Dice roll
+ public static final int SIX = 6;
+
+ private enum GAME_STATE {
+ START,
+ PLAYER_TURN,
+ COMPUTER_TURN,
+ CHECK_FOR_WINNER,
+ GAME_OVER
+ }
+
+ // Used for keyboard input
+ private final Scanner kbScanner;
+
+ // Current game state
+ private GAME_STATE gameState;
+
+
+ private final Insect playersBug;
+
+ private final Insect computersBug;
+
+ // Used to show the result of dice roll.
+ private final String[] ROLLS = new String[]{"BODY", "NECK", "HEAD", "FEELERS", "TAIL", "LEGS"};
+
+ public Bug() {
+
+ playersBug = new PlayerBug();
+ computersBug = new ComputerBug();
+
+ gameState = GAME_STATE.START;
+
+ // Initialise kb scanner
+ kbScanner = new Scanner(System.in);
+ }
+
+ /**
+ * Main game loop
+ */
+ public void play() {
+
+ do {
+ switch (gameState) {
+
+ // Show an introduction the first time the game is played.
+ // And optionally instructions.
+ case START:
+ intro();
+ if (!noEntered(displayTextAndGetInput("DO YOU WANT INSTRUCTIONS? "))) {
+ instructions();
+ }
+
+ gameState = GAME_STATE.PLAYER_TURN;
+ break;
+
+ case PLAYER_TURN:
+ int playersRoll = randomNumber();
+ System.out.println("YOU ROLLED A " + playersRoll + "=" + ROLLS[playersRoll - 1]);
+ switch (playersRoll) {
+ case 1:
+ System.out.println(playersBug.addBody());
+ break;
+ case 2:
+ System.out.println(playersBug.addNeck());
+ break;
+ case 3:
+ System.out.println(playersBug.addHead());
+ break;
+ case 4:
+ System.out.println(playersBug.addFeelers());
+ break;
+ case 5:
+ System.out.println(playersBug.addTail());
+ break;
+ case 6:
+ System.out.println(playersBug.addLeg());
+ break;
+ }
+
+ gameState = GAME_STATE.COMPUTER_TURN;
+ break;
+
+ case COMPUTER_TURN:
+ int computersRoll = randomNumber();
+ System.out.println("I ROLLED A " + computersRoll + "=" + ROLLS[computersRoll - 1]);
+ switch (computersRoll) {
+ case 1:
+ System.out.println(computersBug.addBody());
+ break;
+ case 2:
+ System.out.println(computersBug.addNeck());
+ break;
+ case 3:
+ System.out.println(computersBug.addHead());
+ break;
+ case 4:
+ System.out.println(computersBug.addFeelers());
+ break;
+ case 5:
+ System.out.println(computersBug.addTail());
+ break;
+ case 6:
+ System.out.println(computersBug.addLeg());
+ break;
+ }
+
+ gameState = GAME_STATE.CHECK_FOR_WINNER;
+ break;
+
+ case CHECK_FOR_WINNER:
+ boolean gameOver = false;
+
+ if (playersBug.complete()) {
+ System.out.println("YOUR BUG IS FINISHED.");
+ gameOver = true;
+ } else if (computersBug.complete()) {
+ System.out.println("MY BUG IS FINISHED.");
+ gameOver = true;
+ }
+
+ if (noEntered(displayTextAndGetInput("DO YOU WANT THE PICTURES? "))) {
+ gameState = GAME_STATE.PLAYER_TURN;
+ } else {
+ System.out.println("*****YOUR BUG*****");
+ System.out.println();
+ draw(playersBug);
+
+ System.out.println();
+ System.out.println("*****MY BUG*****");
+ System.out.println();
+ draw(computersBug);
+ gameState = GAME_STATE.PLAYER_TURN;
+
+ if (gameOver) {
+ System.out.println("I HOPE YOU ENJOYED THE GAME, PLAY IT AGAIN SOON!!");
+ gameState = GAME_STATE.GAME_OVER;
+ }
+ }
+ }
+ } while (gameState != GAME_STATE.GAME_OVER);
+ }
+
+ /**
+ * Draw the bug (player or computer) based on what has
+ * already been added to it.
+ *
+ * @param bug The bug to be drawn.
+ */
+ private void draw(Insect bug) {
+ ArrayList insectOutput = bug.draw();
+ for (String s : insectOutput) {
+ System.out.println(s);
+ }
+ }
+
+ /**
+ * Display an intro
+ */
+ private void intro() {
+ System.out.println("BUG");
+ System.out.println("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY");
+ System.out.println();
+ System.out.println("THE GAME BUG");
+ System.out.println("I HOPE YOU ENJOY THIS GAME.");
+ }
+
+ private void instructions() {
+ System.out.println("THE OBJECT OF BUG IS TO FINISH YOUR BUG BEFORE I FINISH");
+ System.out.println("MINE. EACH NUMBER STANDS FOR A PART OF THE BUG BODY.");
+ System.out.println("I WILL ROLL THE DIE FOR YOU, TELL YOU WHAT I ROLLED FOR YOU");
+ System.out.println("WHAT THE NUMBER STANDS FOR, AND IF YOU CAN GET THE PART.");
+ System.out.println("IF YOU CAN GET THE PART I WILL GIVE IT TO YOU.");
+ System.out.println("THE SAME WILL HAPPEN ON MY TURN.");
+ System.out.println("IF THERE IS A CHANGE IN EITHER BUG I WILL GIVE YOU THE");
+ System.out.println("OPTION OF SEEING THE PICTURES OF THE BUGS.");
+ System.out.println("THE NUMBERS STAND FOR PARTS AS FOLLOWS:");
+ System.out.println("NUMBER\tPART\tNUMBER OF PART NEEDED");
+ System.out.println("1\tBODY\t1");
+ System.out.println("2\tNECK\t1");
+ System.out.println("3\tHEAD\t1");
+ System.out.println("4\tFEELERS\t2");
+ System.out.println("5\tTAIL\t1");
+ System.out.println("6\tLEGS\t6");
+ System.out.println();
+
+ }
+
+ /**
+ * Checks whether player entered N or NO to a question.
+ *
+ * @param text player string from kb
+ * @return true if N or NO was entered, otherwise false
+ */
+ private boolean noEntered(String text) {
+ return stringIsAnyValue(text, "N", "NO");
+ }
+
+ /**
+ * Check whether a string equals one of a variable number of values
+ * Useful to check for Y or YES for example
+ * Comparison is case insensitive.
+ *
+ * @param text source string
+ * @param values a range of values to compare against the source string
+ * @return true if a comparison was found in one of the variable number of strings passed
+ */
+ private boolean stringIsAnyValue(String text, String... values) {
+
+ // Cycle through the variable number of values and test each
+ for (String val : values) {
+ if (text.equalsIgnoreCase(val)) {
+ return true;
+ }
+ }
+
+ // no matches
+ return false;
+ }
+
+ /*
+ * Print a message on the screen, then accept input from Keyboard.
+ *
+ * @param text message to be displayed on screen.
+ * @return what was typed by the player.
+ */
+ private String displayTextAndGetInput(String text) {
+ System.out.print(text);
+ return kbScanner.next();
+ }
+
+ /**
+ * Generate random number
+ *
+ * @return random number
+ */
+ private int randomNumber() {
+ return (int) (Math.random()
+ * (SIX) + 1);
+ }
+}
\ No newline at end of file
diff --git a/16 Bug/java/src/BugGame.java b/16 Bug/java/src/BugGame.java
new file mode 100644
index 00000000..074ff45e
--- /dev/null
+++ b/16 Bug/java/src/BugGame.java
@@ -0,0 +1,10 @@
+
+
+public class BugGame {
+
+ public static void main(String[] args) {
+
+ Bug bug = new Bug();
+ bug.play();
+ }
+}
diff --git a/16 Bug/java/src/ComputerBug.java b/16 Bug/java/src/ComputerBug.java
new file mode 100644
index 00000000..fe232364
--- /dev/null
+++ b/16 Bug/java/src/ComputerBug.java
@@ -0,0 +1,15 @@
+public class ComputerBug extends Insect {
+
+ // Create messages specific to the computer player.
+
+ public ComputerBug() {
+ // Call superclass constructor for initialization.
+ super();
+ addMessages(new String[]{"I GET A FEELER.", "I HAVE " + MAX_FEELERS + " FEELERS ALREADY.", "I DO NOT HAVE A HEAD."}, PARTS.FEELERS);
+ addMessages(new String[]{"I NEEDED A HEAD.", "I DO NOT NEED A HEAD.", "I DO NOT HAVE A NECK."}, PARTS.HEAD);
+ addMessages(new String[]{"I NOW HAVE A NECK.", "I DO NOT NEED A NECK.", "I DO NOT HAVE A BODY."}, PARTS.NECK);
+ addMessages(new String[]{"I NOW HAVE A BODY.", "I DO NOT NEED A BODY."}, PARTS.BODY);
+ addMessages(new String[]{"I NOW HAVE A TAIL.", "I DO NOT NEED A TAIL.", "I DO NOT HAVE A BODY."}, PARTS.TAIL);
+ addMessages(new String[]{"I NOW HAVE ^^^" + " LEG", "I HAVE " + MAX_LEGS + " FEET.", "I DO NOT HAVE A BODY."}, PARTS.LEGS);
+ }
+}
diff --git a/16 Bug/java/src/Insect.java b/16 Bug/java/src/Insect.java
new file mode 100644
index 00000000..08e9414f
--- /dev/null
+++ b/16 Bug/java/src/Insect.java
@@ -0,0 +1,363 @@
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * This tracks the insect (bug) and has methods to
+ * add body parts, create an array of output so it
+ * can be drawn and to determine if a bug is complete.
+ * N.B. This is a super class for ComputerBug and PlayerBug
+ */
+public class Insect {
+
+ public static final int MAX_FEELERS = 2;
+ public static final int MAX_LEGS = 6;
+
+ public static final int ADDED = 0;
+ public static final int NOT_ADDED = 1;
+ public static final int MISSING = 2;
+
+ // Various parts of the bug
+ public enum PARTS {
+ FEELERS,
+ HEAD,
+ NECK,
+ BODY,
+ TAIL,
+ LEGS
+ }
+
+ // Tracks what parts of the bug have been added
+ private boolean body;
+ private boolean neck;
+ private boolean head;
+ private int feelers;
+ private boolean tail;
+ private int legs;
+
+ // Messages about for various body parts
+ // These are set in the subclass ComputerBug or PlayerBug
+ private String[] bodyMessages;
+ private String[] neckMessages;
+ private String[] headMessages;
+ private String[] feelerMessages;
+ private String[] tailMessages;
+ private String[] legMessages;
+
+ public Insect() {
+ init();
+ }
+
+ /**
+ * Add a body to the bug if there is not one already added.
+ *
+ * @return return an appropriate message about the status of the operation.
+ */
+ public String addBody() {
+
+ boolean currentState = false;
+
+ if (!body) {
+ body = true;
+ currentState = true;
+ }
+
+ return addBodyMessage(currentState);
+ }
+
+ /**
+ * Create output based on adding the body or it being already added previously
+ *
+ * @return contains the output message
+ */
+
+ private String addBodyMessage(boolean wasAdded) {
+
+ // Return the appropriate message depending on whether the
+ // body was added or not.
+ if (wasAdded) {
+ return bodyMessages[ADDED];
+ } else {
+ return bodyMessages[NOT_ADDED];
+ }
+ }
+
+ /**
+ * Add a neck if a) a body has previously been added and
+ * b) a neck has not previously been added.
+ *
+ * @return text containing the status of the operation
+ */
+ public String addNeck() {
+
+ int status = NOT_ADDED; // Default is not added
+
+ if (!body) {
+ // No body, cannot add a neck
+ status = MISSING;
+ } else if (!neck) {
+ neck = true;
+ status = ADDED;
+ }
+
+ return neckMessages[status];
+ }
+
+ /**
+ * Add a head to the bug if a) there already exists a neck and
+ * b) a head has not previously been added
+ *
+ * @return text outlining the success of the operation
+ */
+ public String addHead() {
+
+ int status = NOT_ADDED; // Default is not added
+
+ if (!neck) {
+ // No neck, cannot add a head
+ status = MISSING;
+ } else if (!head) {
+ head = true;
+ status = ADDED;
+ }
+
+ return headMessages[status];
+ }
+
+ /**
+ * Add a feeler to the head if a) there has been a head added to
+ * the bug previously, and b) there are not already 2 (MAX_FEELERS)
+ * feelers previously added to the bug.
+ *
+ * @return text outlining the status of the operation
+ */
+ public String addFeelers() {
+
+ int status = NOT_ADDED; // Default is not added
+
+ if (!head) {
+ // No head, cannot add a feeler
+ status = MISSING;
+ } else if (feelers < MAX_FEELERS) {
+ feelers++;
+ status = ADDED;
+ }
+
+ return feelerMessages[status];
+ }
+
+ /**
+ * Add a tail to the bug if a) there is already a body previously added
+ * to the bug and b) there is not already a tail added.
+ *
+ * @return text outlining the status of the operation.
+ */
+ public String addTail() {
+
+ int status = NOT_ADDED; // Default is not added
+
+ if (!body) {
+ // No body, cannot add a tail
+ status = MISSING;
+ } else if (!tail) {
+ tail = true;
+ status = ADDED;
+ }
+
+ return tailMessages[status];
+ }
+
+ /**
+ * Add a leg to the bug if a) there is already a body previously added
+ * b) there are less than 6 (MAX_LEGS) previously added.
+ *
+ * @return text outlining status of the operation.
+ */
+ public String addLeg() {
+
+ int status = NOT_ADDED; // Default is not added
+
+ if (!body) {
+ // No body, cannot add a leg
+ status = MISSING;
+ } else if (legs < MAX_LEGS) {
+ legs++;
+ status = ADDED;
+ }
+
+ String message = "";
+
+ // Create a string showing the result of the operation
+
+ switch(status) {
+ case ADDED:
+ // Replace # with number of legs
+ message = legMessages[status].replace("^^^", String.valueOf(legs));
+ // Add text S. if >1 leg, or just . if one leg.
+ if (legs > 1) {
+ message += "S.";
+ } else {
+ message += ".";
+ }
+ break;
+
+ case NOT_ADDED:
+
+ // Deliberate fall through to next case as its the
+ // same code to be executed
+ case MISSING:
+ message = legMessages[status];
+ break;
+ }
+
+ return message;
+ }
+
+ /**
+ * Initialise
+ */
+ public void init() {
+ body = false;
+ neck = false;
+ head = false;
+ feelers = 0;
+ tail = false;
+ legs = 0;
+ }
+
+ /**
+ * Add unique messages depending on type of player
+ * A subclass of this class calls this method
+ * e.g. See ComputerBug or PlayerBug classes
+ *
+ * @param messages an array of messages
+ * @param bodyPart the bodypart the messages relate to.
+ */
+ public void addMessages(String[] messages, PARTS bodyPart) {
+
+ switch (bodyPart) {
+ case FEELERS:
+ feelerMessages = messages;
+ break;
+
+ case HEAD:
+ headMessages = messages;
+ break;
+
+ case NECK:
+ neckMessages = messages;
+ break;
+
+ case BODY:
+ bodyMessages = messages;
+ break;
+
+ case TAIL:
+ tailMessages = messages;
+ break;
+
+ case LEGS:
+ legMessages = messages;
+ break;
+ }
+ }
+
+ /**
+ * Returns a string array containing
+ * the "bug" that can be output to console
+ *
+ * @return the bug ready to draw
+ */
+ public ArrayList draw() {
+ ArrayList bug = new ArrayList<>();
+ StringBuilder lineOutput;
+
+ // Feelers
+ if (feelers > 0) {
+ for (int i = 0; i < 4; i++) {
+ lineOutput = new StringBuilder(addSpaces(10));
+ for (int j = 0; j < feelers; j++) {
+ lineOutput.append("A ");
+ }
+ bug.add(lineOutput.toString());
+ }
+ }
+
+ if (head) {
+ lineOutput = new StringBuilder(addSpaces(8) + "HHHHHHH");
+ bug.add(lineOutput.toString());
+ lineOutput = new StringBuilder(addSpaces(8) + "H" + addSpaces(5) + "H");
+ bug.add(lineOutput.toString());
+ lineOutput = new StringBuilder(addSpaces(8) + "H O O H");
+ bug.add(lineOutput.toString());
+ lineOutput = new StringBuilder(addSpaces(8) + "H" + addSpaces(5) + "H");
+ bug.add(lineOutput.toString());
+ lineOutput = new StringBuilder(addSpaces(8) + "H" + addSpaces(2) + "V" + addSpaces(2) + "H");
+ bug.add(lineOutput.toString());
+ lineOutput = new StringBuilder(addSpaces(8) + "HHHHHHH");
+ bug.add(lineOutput.toString());
+ }
+
+ if (neck) {
+ for (int i = 0; i < 2; i++) {
+ lineOutput = new StringBuilder(addSpaces(10) + "N N");
+ bug.add(lineOutput.toString());
+ }
+ }
+
+ if (body) {
+ lineOutput = new StringBuilder(addSpaces(5) + "BBBBBBBBBBBB");
+ bug.add(lineOutput.toString());
+ for (int i = 0; i < 2; i++) {
+ lineOutput = new StringBuilder(addSpaces(5) + "B" + addSpaces(10) + "B");
+ bug.add(lineOutput.toString());
+ }
+ if (tail) {
+ lineOutput = new StringBuilder("TTTTTB" + addSpaces(10) + "B");
+ bug.add(lineOutput.toString());
+ }
+ lineOutput = new StringBuilder(addSpaces(5) + "BBBBBBBBBBBB");
+ bug.add(lineOutput.toString());
+ }
+
+ if (legs > 0) {
+ for (int i = 0; i < 2; i++) {
+ lineOutput = new StringBuilder(addSpaces(5));
+ for (int j = 0; j < legs; j++) {
+ lineOutput.append(" L");
+ }
+ bug.add(lineOutput.toString());
+ }
+ }
+
+ return bug;
+ }
+
+ /**
+ * Check if the bug is complete i.e. it has
+ * 2 (MAX_FEELERS) feelers, a head, a neck, a body
+ * a tail and 6 (MAX_FEET) feet.
+ *
+ * @return true if complete.
+ */
+ public boolean complete() {
+ return (feelers == MAX_FEELERS)
+ && head
+ && neck
+ && body
+ && tail
+ && (legs == MAX_LEGS);
+ }
+
+ /**
+ * Simulate tabs be creating a string of X spaces.
+ *
+ * @param number contains number of spaces needed.
+ * @return a String containing the spaces
+ */
+ private String addSpaces(int number) {
+ char[] spaces = new char[number];
+ Arrays.fill(spaces, ' ');
+ return new String(spaces);
+
+ }
+}
\ No newline at end of file
diff --git a/16 Bug/java/src/PlayerBug.java b/16 Bug/java/src/PlayerBug.java
new file mode 100644
index 00000000..1a82e8b3
--- /dev/null
+++ b/16 Bug/java/src/PlayerBug.java
@@ -0,0 +1,18 @@
+public class PlayerBug extends Insect {
+
+ // Create messages specific to the player.
+
+ public PlayerBug() {
+ // Call superclass constructor for initialization.
+ super();
+ addMessages(new String[]{"I NOW GIVE YOU A FEELER.", "YOU HAVE " + MAX_FEELERS + " FEELERS ALREADY.", "YOU DO NOT HAVE A HEAD."}, PARTS.FEELERS);
+ addMessages(new String[]{"YOU NEEDED A HEAD.", "YOU HAVE A HEAD.", "YOU DO NOT HAVE A NECK."}, PARTS.HEAD);
+ addMessages(new String[]{"YOU NOW HAVE A NECK.", "YOU DO NOT NEED A NECK.", "YOU DO NOT HAVE A BODY."}, PARTS.NECK);
+ addMessages(new String[]{"YOU NOW HAVE A BODY.", "YOU DO NOT NEED A BODY."}, PARTS.BODY);
+ addMessages(new String[]{"I NOW GIVE YOU A TAIL.", "YOU ALREADY HAVE A TAIL.", "YOU DO NOT HAVE A BODY."}, PARTS.TAIL);
+ addMessages(new String[]{"YOU NOW HAVE ^^^ LEG", "YOU HAVE " + MAX_LEGS + " FEET ALREADY.", "YOU DO NOT HAVE A BODY."}, PARTS.LEGS);
+ }
+
+
+}
+