Paul12596
Paul12596

Reputation: 300

Cows and Bulls code - Java

I'm a CS student just starting out and I'm stuck with a Cows and Bulls game. It compiles and runs, but there's an error of some kind somewhere that I'm not seeing that leads to the incorrect number of Cows and Bulls (sample of expected vs. my output).

Explanation of Cows and Bulls: Bulls - the number of correct digits. Cows - the number of digits that would be correct if they were in the right position.

  public class CowsAndBulls{

  //Constants
  public final static int NUM_DIGITS = 4;
  public final static int MAX_VALUE = 9876;
  public final static int MIN_VALUE = 1234;
  public final static int MAX_GUESSES = 10;
  //


  // instances
  private NumberPicker randomNumber;
  private int answer;
  private int guessesCopy;
  private int bullStored;
  private int cowStored;
  //

  public CowsAndBulls(int seed){
        randomNumber = new NumberPicker(seed, MIN_VALUE, MAX_VALUE);
        answer = randomNumber.nextInt();
        guessesCopy = MAX_GUESSES;
        }

  ////////////////////////////////////////////////////////
  //Stuff between the comments is from a previous question that needs to be used in CowsAndBulls (not in a package) - I know it works as it's supposed to.
  public static int[] toArray(int number){

        String numString = Integer.toString(number);
        int[] someArray = new int[numString.length()];

        for (int i = 0; i < numString.length(); i++){
              char c = numString.charAt(i);

              int cVal = Character.getNumericValue(c);

              someArray[i] = cVal;
              }
        return someArray;
              }

  public static int countMatches(int a, int b){ //Bulls

        String stringA = Integer.toString(a);
        int lengthAB = stringA.length();
        int count = 0;

        int[] arrayOutA = toArray(a);
        int[] arrayOutB = toArray(b);

        for (int i = 0; i < lengthAB; i++){
              if (arrayOutA[i] == arrayOutB[i])
                    count += 1;     
                          }                   
        return count;
        } 


  public static int countIntersect(int numA, int numB){ //Cows
        String stringA = Integer.toString(numA);
        int lengthAB = stringA.length();
        int count = 0;

        int[] arrayOutA = toArray(numA);
        int[] arrayOutB = toArray(numB);

        for (int i = 0; i < lengthAB; i++){

              for (int j = 0; j < lengthAB; j++){

                    if ( arrayOutA[i] == arrayOutB[j]){
                             count += 1;
                             }
                          }

                    }
                    return count;
                    } 
  //////////////////////////////////////////////////////////////////                        






  public int guessesRemaining(){
        return guessesCopy;
        }



  public Result guess(int guessNumber){

        int bulls = countMatches(answer, guessNumber);
        bullStored = bulls;
        int cows = countIntersect(answer, guessNumber);
        cowStored = cows;

        guessesCopy--;
        return (new Result(cows, bulls));
        }

  public int giveUp(){
        return (answer);
        }

  public boolean gameOver(){
        if (guessesCopy == 0 || bullStored == 4)
              return true;
        else
              return false;                  
        }

Below are the supplied classes that we're supposed to use and can't edit it any way: NumberPicker, Game, and Result. NumberPicker:

    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    import java.util.Random;
    /**
     * Given a number range, a NumberPicker returns the numbers in the range   in a random order
   */
    public class NumberPicker {

          private List<Integer> numbers;

    /**
      * Create a NumberPicker that uses the given seed value for  randomisation and that 
      * returns the numbers in the range min to max (inclusive) in a random order.
       * /
       public NumberPicker(final int seed, final int min, final int max) {
            numbers = new ArrayList<Integer>();
            final Random random = new Random(seed);
            for(int i = min; i<max+1; i++) {
            numbers.add(i);
                }
            Collections.shuffle(numbers, random);
            }

       /**
        * Determine whether the NumberPicker contains any more numbers..
        */
        public boolean hasNext() { return !numbers.isEmpty(); }

        /**
        * Return a randomly selected number from the range.
        */
      public int nextInt() { return numbers.remove(0); }

    }

Game class:

             import java.util.Scanner;

             public class Game {

             private Game() {}

            public static void main(String[] inputs) {
         Scanner input = new Scanner(System.in);
         System.out.println("Your challenge is to guess a secret " +  CowsAndBulls.NUM_DIGITS + " digit number.");

         System.out.println("Enter randomisation seed value:");
         CowsAndBulls cowsAndBulls = new CowsAndBulls(input.nextInt());

         System.out.println("Make a guess:");
         Result answer = cowsAndBulls.guess(input.nextInt());

        while(!answer.isCorrect()&&cowsAndBulls.guessesRemaining()>0) {

            System.out.println("Sorry that's incorrect.");
            System.out.println("You have "+answer+".");

            System.out.printf("You have %d guesses remaining\n", cowsAndBulls.guessesRemaining());
            System.out.println("Make a guess:");
            answer = cowsAndBulls.guess(input.nextInt());
             }
         if (answer.isCorrect()) {
             System.out.println("Correct !");
             }
         else {
             System.out.println("Sorry, you lose.");
             }
           }
         }

And finally, Result class:

            /**
            * A Result object records the outcome of a guess in the Cows and Bulls guessing game.
            * 
            * 
            */
        public class Result {

            private int cows;
            private int bulls;

      public Result(int cows, int bulls) {
           assert(cows+bulls<=4);
           this.cows=cows;
           this.bulls=bulls;
           }

        public int cows() { return cows; }
        public int bulls() { return bulls; }

        public boolean isCorrect() { return bulls==4; }

        public boolean equals(Object o) {
           if (!(o instanceof Result)) {
                 return false;
                 }
           else {
                Result other = (Result)o;
              return this.cows()==other.cows()&&this.bulls()==other.bulls();
             }
       }

      public String toString() {
          String result = this.cows()+(this.cows()!=1 ? " cows" : " cow");
          result = result+" and "+this.bulls()+(this.bulls()!=1 ? " bulls" : " bull");
          return result;
          }

    }

That's all the code. To reiterate: I can't change any of the classes except CowsAndBulls and I have to use Game, Result, and NumberPicker. Below are expected output vs. what my program is producing...

       Trial 1: Output not correct

       The expected output was:
       10
       false
       8913
       true

       Your program produced:
       10
       false
       7407
       false

       Input supplied to your program:
       construct 3
       guessesRemaining()
       gameOver()
       giveUp()
       gameOver()
       Q

       -------------------------------------
       Trial 2: Output not correct

       The expected output was:
       10
       0 cows and 0 bulls
       9
       1 cow and 0 bulls
       8
       2 cows and 0 bulls
       7
       3 cows and 0 bulls
       6
       4 cows and 0 bulls
       5

       Your program produced:
       10
       1 cow and 0 bulls
       9
       0 cows and 0 bulls
       8
       1 cow and 0 bulls
       7
       2 cows and 0 bulls
       6
       2 cows and 0 bulls
       5

       Input supplied to your program:
       construct 4
       guessesRemaining()
       guess() 2358
       guessesRemaining()
       guess() 1235
       guessesRemaining()
       guess() 1735
       guessesRemaining()
       guess() 1749
       guessesRemaining()
       guess() 1746
       guessesRemaining()
       Q
       ----------------------------------------------
       Trial 3: Output not correct

       The expected output was:
       10
       0 cows and 0 bulls
       9
       0 cows and 1 bull
       8
       0 cows and 2 bulls
       7
       0 cows and 3 bulls
       6
       0 cows and 4 bulls
       5
       true

       Your program produced:
       10
       1 cow and 0 bulls
       9
       1 cow and 0 bulls
       8
       1 cow and 0 bulls
       7
       1 cow and 0 bulls
       6
       1 cow and 0 bulls
       5
       false

       Input supplied to your program:
       construct 8
       guessesRemaining()
       guess() 2358
       guessesRemaining()
       guess() 2758
       guessesRemaining()
       guess() 2748
       guessesRemaining()
       guess() 6748
       guessesRemaining()
       guess() 6741
       guessesRemaining()
       gameOver()
       Q

It might just be something dumb that I'm not seeing, but any help is greatly appreciated. I'm new to S.E (and Java), so the formatting of my code might be weird - if so, I'll edit it. Thanks :).

Upvotes: 2

Views: 2966

Answers (2)

Shaikh Arbaaz
Shaikh Arbaaz

Reputation: 155

Question: First, the system will generate a number (this number will not be shown to the player). Player needs to guess the number and enter it in the input box. Based on the following rules the system will give an answer:

 Input only 4 digits

 All random digits

 Each position is a unique number

 If number and position matches then system counts one COW

 If number matches and position does not then system counts one BULL

 If number and position both do not match then system counts zero of BULL and COW

If the player guesses the correct number, the system will give answer as ALL COW.

Player will win if the system gives answer as All COW. Player has to try keying in number as long as they don’t get an answer as All Cow.

Illustration 1:

Suppose system generates number = 1234

User input = 4321 then system will give answer as 4 bulls 0 cows

User input = 1234 then system will give answer as 4 cows 0 bulls

Game over

Illustration 2:

Suppose system generates number = 1234

User input = 1243 // 2 bulls 2 cows

User input = 5678 // 0 cows 0 bulls

User input = 7599 // 0 cows 0 bulls

Game continues until player inputs the correct number

Instructions for Candidate:

  1. Develop a JavaScript based web page for the game as described above
  2. Page must have provision to key-in the user input
  3. Page should display system output in a prominent way
  4. Candidate is free to use any type of design they want

This solution for javascript with validations

<!DOCTYPE html>
<html lang="en">
   <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>Cow Bull Assignment</title>
      <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
      <style>
         #submitAns{
         margin-top: 10px;
         }
         #result{
         font-size: 22px;
         }
         #message{
         font-size: 19px;
         }
         #last-input{
         font-size: 17px;
         font-weight: bold;
         position: relative;
         top: 4px;
         }
         .panel{
         margin-top: 30px;
         }
      </style>
   </head>
   <body>
      <div class="container">
         <div class="panel panel-info">
            <div class="panel-heading">Cow Bull Game</div>
            <div class="panel-body">
               <form action="" class="form-group">
                  <span><strong>Unique numbers allowed</strong></span><br />
                  <input type="text" class="form-control" maxlength="4" placeholder="Enter 4 digits number"
                     onkeypress="return ristrictNumberLimit(event)" id="input" onkeyup="validateGame(event)">
                  <button type="button" class="btn btn-primary" id='submitAns'>Submit</button> <br />
                  <span id="last-input"></span>
               </form>
            </div>
            <div class="panel-footer">
               <span id="result"></span> <br />
               <span id="message"></span>
            </div>
         </div>
      </div>
      <script>
         var inputValues = [];
         const btn = document.querySelector('#submitAns');
         const input = document.querySelector('#input');
         let randNum = [];
         
         const generateNumber = () => {
             for (let index = 0; index < 10; index++) {
                 let ranNum = String((Math.floor((Math.random() * 9) + 1)));
                 if(randNum.length <= 3){
                     if(!randNum.includes(ranNum)){
                         randNum.push(ranNum);
                     }
                 }
             }
         }
         
         generateNumber();
         
         
         const ristrictNumberLimit = (e) => {
             e = (e) ? e : window.event;
             var charCode = (e.which) ? e.which : e.keyCode;
             if (charCode > 31 && (charCode < 48 || charCode > 57)) {
                 return false;
             }
             return true;
         }
         
         const validateGame = (e) => {
         
             let userInput = e.target.value.split('');
             
             if(inputValues.indexOf(userInput[userInput.length - 1]) === -1){
                 inputValues.splice(0, userInput.length);
                 inputValues = userInput;
             }
         
             inputValues = inputValues.filter(v => v !== undefined);
             inputValues = inputValues.filter((v, i, a) => { return a.indexOf(v) === i} );
             
             let key = e.keyCode || e.charCode;
             let lastNum = (v) => v == userInput[userInput.length - 1];
             e.target.value = '';
         
             if(key == 8 || key == 46){
                 inputValues.splice(userInput.findIndex(lastNum), 1);
             }
         
             inputValues.map(v => {
                 e.target.value += v;
             });
         
         }
         
         btn.addEventListener('click', () => {
             let cow = 0;
             let bull = 0;
             for (let inp = 0; inp < inputValues.length; inp++) {
                 const inpVal = inputValues[inp];
                 for (let ran = 0; ran < randNum.length; ran++) {
                     const ranVal = randNum[ran];
                     if(inpVal == ranVal && inp != ran){
                       bull++;
                     } if(inpVal == ranVal && inp == ran){
                         cow++;
                         if(cow === 4){
                             bull = 0;
                         }
                     }
                 }   
             }
         
             if(cow === 4){
                 document.querySelector('#last-input').innerHTML = '';
                 document.querySelector('#message').innerHTML = 'All Cow <br/> Number Guessed <br /><strong>Game Over</strong>';
                 document.querySelector('#result').innerHTML = '';
                 input.value = '';
                 inputValues.splice(0, inputValues.length);
                 inputValues.splice(0, randNum.length);
                 randNum = [];
                 generateNumber();
             }else{
                 document.querySelector('#last-input').innerHTML = 'Last Input: ' +inputValues;
                 document.querySelector('#result').innerHTML = `Bull: ${bull}, Cow: ${cow}`;
                 document.querySelector('#message').innerHTML = '';
                 console.log(`Input Values: ${inputValues}`);
                 console.log(`Generated Values: ${randNum}`);
                 console.log(`Bull: ${bull}, Cow: ${cow}`);
                 inputValues = [];
                 input.value = '';
             }
         })
         
      </script>
   </body>
</html>

Upvotes: 0

user254948
user254948

Reputation: 1056

   The expected output was:
   10
   false
   8913
   true

   Your program produced:
   10
   false
   7407
   false

   Input supplied to your program:
   construct 3
   guessesRemaining()
   gameOver()
   giveUp()
   gameOver()
   Q

As far as I can tell it is telling you the number it expects from giveUp() is incorrect. This indicates your program is somehow generating the numbers differently (7404 vs 8913). This could be due to your MIN_VALUE and/or MAX_VALUE?

public static int countIntersect(int numA, int numB) { //Cows
    String stringA = Integer.toString(numA);
    int lengthAB = stringA.length();
    int count = 0;

    int[] arrayOutA = toArray(numA);
    int[] arrayOutB = toArray(numB);

    for (int i = 0; i < lengthAB; i++) {

        for (int j = 0; j < lengthAB; j++) {

            if (arrayOutA[i] == arrayOutB[j]) {
                count += 1;
            }
        }

    }
    return count;
}

I don't think this is what you want. For example countIntersect(1111,1111) would return 16, I would expect this to be 4 or 0?

As for your coding here is some minor feedback:

In the function giveUp you do not need the ( and ) at the return statement.

// Original
public int giveUp() {
    return (answer);
}

// Suggested
public int giveUp() {
    return answer;
}

In your guess function you do not need to hold it in a local int first. Also the ( and ) again.

// Original
public Result guess(int guessNumber) {

    int bulls = countMatches(answer, guessNumber);
    bullStored = bulls;
    int cows = countIntersect(answer, guessNumber);
    cowStored = cows;

    guessesCopy--;
    return (new Result(cows, bulls));
}

// Suggested
public Result guess(int guessNumber) {
    bullStored = countMatches(answer, guessNumber);
    cowStored = countIntersect(answer, guessNumber);
    guessesCopy--;
    return new Result(cowStored, bullStored);
}

In your method countIntersect there is not really a reason to use a special int[] array. A character array would do just as well. In addition lengthAB could be replaced by the .length property of one of the 2 arrays.

// Original
public static int countIntersect(int numA, int numB) { //Cows
    String stringA = Integer.toString(numA);
    int lengthAB = stringA.length();
    int count = 0;

    int[] arrayOutA = toArray(numA);
    int[] arrayOutB = toArray(numB);

    for (int i = 0; i < lengthAB; i++) {
        for (int j = 0; j < lengthAB; j++) {
            if (arrayOutA[i] == arrayOutB[j]) {
                count += 1;
            }
        }
    }
    return count;
}

// Suggested
public static int countIntersect(int numA, int numB) { //Cows
    int count = 0;

    char[] arrayA = Integer.toString(numA).toCharArray();
    char[] arrayB = Integer.toString(numB).toCharArray();

    for (int i = 0; i < arrayA.length; i++) {
        for (int j = i; j < arrayB.length; j++) {
            if (arrayA[i] == arrayB[j]) {
               if(i != j) {
                   count++;
               }
               break;
            }
        }
    }
    return count;
}

The same kind of goes for countMatches.

// Original
public static int countMatches(int a, int b){ //Bulls

    String stringA = Integer.toString(a);
    int lengthAB = stringA.length();
    int count = 0;

    int[] arrayOutA = toArray(a);
    int[] arrayOutB = toArray(b);

    for (int i = 0; i < lengthAB; i++){
        if (arrayOutA[i] == arrayOutB[i])
            count += 1;
    }
    return count;
}

// Suggested
public static int countMatches(int a, int b) { //Bulls
    int count = 0;

    char[] arrayA = Integer.toString(a).toCharArray();
    char[] arrayB = Integer.toString(b).toCharArray();

    for (int i = 0; i < Math.min(arrayA.length,arrayB.length); i++) {
        if (arrayA[i] == arrayB[i])
            count += 1;
    }
    return count;
}

Finally your gameOver could be written much simpler.

//Original
public boolean gameOver() {
    if (guessesCopy == 0 || bullStored == 4)
        return true;
    else
        return false;
}

// Suggested
public boolean gameOver() {
    return guessesCopy == 0 || bullStored == 4;
}

Upvotes: 2

Related Questions