Guessing Game logic (binary search) - java

Working on a problem in which I take a user's input (1-10) and guess what number they are thinking of using binary search, and update the range dependent on their answer (e.g. if it is greater than 5, I update the lowerLimit to 6) but am having trouble with the logic.
I use the middle cell as reference by adding 1 to the middle cell when they say it is greater than it, but I believe this is where I get confused. I can't figure out how to intertwine my if/else statement to update the number correctly.
Main method:
public class Main {
public static void main(String[] args) {
// test your program here
GuessingGame game = new GuessingGame();
game.play(1,10);
}
}
GuessingGame method (play method is the one I'm working with):
import java.util.Scanner;
public class GuessingGame {
private Scanner reader;
public GuessingGame() {
// use only this scanner, othervise the tests do not work
this.reader = new Scanner(System.in);
}
public void play(int LL, int UL) {
instructions(LL, UL);
int limit = howManyTimesHalvable(UL - LL);
int finalNumber = 0;
int midPoint = average(LL, UL);
int avgLL;
int avgUL;
for(int i = 0; i < limit; i++){
if(isGreaterThan(midPoint)){
midPoint++;
LL = midPoint;
midPoint = average(UL,LL);
finalNumber = LL;
}else{
midPoint--;
UL = midPoint;
midPoint = average(UL,LL);
finalNumber = LL;
}
if(UL == LL){
break;
}
}
System.out.println("Your number is : " + finalNumber);
}
public boolean isGreaterThan(int value){
System.out.println("Is your number greater than " + value + "?");
return reader.nextLine().equals("y");
}
public int average(int firstNumber, int secondNumber){
int total = firstNumber + secondNumber ;
return total / 2;
}
public void instructions(int lowerLimit, int upperLimit) {
int maxQuestions = howManyTimesHalvable(upperLimit - lowerLimit);
System.out.println("Think of a number between " + lowerLimit + "..." + upperLimit + ".");
System.out.println("I promise you that I can guess the number you are thinking with " + maxQuestions + " questions.");
System.out.println("");
System.out.println("Next I'll present you a series of questions. Answer them honestly.");
System.out.println("");
}
// a helper method:
public static int howManyTimesHalvable(int number) {
// we create a base two logarithm of the given value
// Below we swap the base number to base two logarithms!
return (int) (Math.log(number) / Math.log(2)) + 1;
}
}
I would like to know how to update the ranges accordingly, when a user says that the number that they've guessed is higher or lower than what is shown to them.
Edit, example entries:
Looking for number 9,
LL: 1
UL: 10
limit:4
finalNumber:0
midPoint:5
i: 0
Is your number greater than 5?
y
LL: 6
UL: 10
limit:4
finalNumber:6
midPoint:8
i: 1
Is your number greater than 8?
LL: 9
UL: 10
limit:4
finalNumber:9
midPoint:9
i: 2
Is your number greater than 9?
n
LL: 9
UL: 8
limit:4
finalNumber:9
midPoint:8
i: 3
Is your number greater than 8?
y
Your number is : 9

You should not have midPoint--;
Since you are asking the question as "is Grater than"? Your new upper limit should be midpoint if the answer is no.

Related

Calculating factorial, where did I go wrong?

This was part of my assignment and was asked to calculate factorial of 5 and 7.
I finished it as below:
import java.util.Scanner;
public class Factorial {
public static void main(String [] args)
{
System.out.println("Please enter a number: ");
Scanner input=new Scanner(System.in);
int number=input.nextInt();
int i,fact=1;
for(i=1;i<=number;i++){
fact=fact*i;
}
System.out.println("Factorial of " + number + " is: " + fact);
}
}
It worked for 5 and 7 (resulting 120 and 5040).
But my professor came over and test it with 20 and 987654321, result returns -2102132736 and 0.
Why is that?
P.S. I thought for the case of 987654321, the result would crush the application or return error since it would be huge.
This code can solve your problem . It is taken from here
class BigFactorial
{
static void factorial(int n)
{
int res[] = new int[300];
// Initialize result
res[0] = 1;
int res_size = 1;
// Apply simple factorial formula n! = 1 * 2 * 3 * 4...*n
for (int x=2; x<=n; x++)
res_size = multiply(x, res, res_size);
System.out.println("Factorial of given number is: ");
for (int i=res_size-1; i>=0; i--)
System.out.print(res[i]);
}
// This function multiplies x with the number represented by res[].
// res_size is size of res[] or number of digits in the number represented
// by res[]. This function uses simple school mathematics for multiplication.
// This function may value of res_size and returns the new value of res_size
static int multiply(int x, int res[], int res_size)
{
int carry = 0; // Initialize carry
// One by one multiply n with individual digits of res[]
for (int i=0; i<res_size; i++)
{
int prod = res[i] * x + carry;
res[i] = prod % 10; // Store last digit of 'prod' in res[]
carry = prod/10; // Put rest in carry
}
// Put carry in res and increase result size
while (carry!=0)
{
res[res_size] = carry%10;
carry = carry/10;
res_size++;
}
return res_size;
}
// Driver program
public static void main(String []args)
{
factorial(100);
}
}
Because 5040! is a very larger number (even long overflows). Use a BigInteger like
System.out.println("Please enter a number: ");
Scanner input = new Scanner(System.in);
int number = input.nextInt();
BigInteger fact = BigInteger.ONE;
for (int i = 2; i <= number; i++) { // <-- x * 1 = x
fact = fact.multiply(BigInteger.valueOf(i));
}
System.out.println("Factorial of " + number + " is: " + fact);
This is because of the fact that the container that you have taken for storing and printing your result does not have the capacity to hold such big integer (I mean factorial of 20). So, you need a bigger container. As others already suggested, you can use BIGINTEGER.

How to return a new number by method

I'm new in java.
I have to write a program that modifies an existing catalog (3-5 digits) number to a new catalog number by adding a number to the left of an existing catalog number according to these conditions:
The new number will be the largest number between the leftmost digit to the rightmost digit.
If leftmost digit equal to the rightmost, the new number will be 9.
The input should be 10 numbers and then to add a new number.
The problem is that, now, the method "newKatalogNumber" get the old catalog number, and return the left digit, i like the method return the new catalog code. for instance, if the method get 1234, she will return 41234, and it will be printed at the end of the main. I have not found a way to do it.
Is anybody have the clue how to do that?
I will be grateful.
This is my code:
import java.util.Scanner; // This program gets an old catalog number between 3 to 5 digits and change it to a new catalog number
// by adding a new digit to the left of the number
public class Number
{
public static int newKatalogNumber(int num)
{
while (num>=10)
{
num /= 10;
}
return num;
}
public static void main(String[] args)
{
Scanner input = new Scanner(System.in);
for (int oldNum=0; oldNum<10; oldNum++)
{
System.out.print("Insert old catalog Number: ");//The user insert the old catalog number
int catalogNum = input.nextInt();
int mostRight = catalogNum % 10;
int mostLeft = newKatalogNumber(catalogNum);
//Adding the new digit according to condition below:
if (mostRight>mostLeft)
{
System.out.println("Old catalog number is:"+catalogNum);
System.out.println("New catalog number is"+mostRight+catalogNum);
}
else if (mostLeft>mostRight)
{
System.out.println("Old catalog number is:"+catalogNum);
System.out.println("New catalog number is"+mostLeft+catalogNum);
}
else
{
System.out.println("Old catalog number is:"+catalogNum);
System.out.println("New catalog number is"+9+catalogNum);
}
}
}
}
If you have a number like 1234and you want to add at the beginning, let's say, a 5 then you should do:
1234 + 5 * 10000
And if you want to add the 5 at the end you should do:
1234 * 10 + 5
Notice in the first case the number of zeroes in 10000 equals the number of digits in the original number.
try this
public static int NewKatatlogNumber (int num)
{
int noOfDigitsInTheNumber = num + "".length();
int[] digitsArray = new int[noOfDigitsInTheNumber];
int index = digitsArray.length - 1;
//Extract digit by digit and populate the digitarray from right to left.
//If your num is 123 your array will [1,2,3]
while (num > 0)
{
int remainder = num % 10;
num = num / 10;
digitsArray[index--] = remainder;
}
//Find the number to add from the digit array.Apply your logic here
int numberToAddToTheLeft = getNumberToAdd(digitsArray);
int newNum = numberToAddToTheLeft;
//Construct the final token by prepending the digit you identified
for (int i = 0; i < digitsArray.length; i++)
{
int j = digitsArray[i];
newNum = newNum * 10 + i;
}
return newNum;
}
Convert the number to a string and then add "n" to the front of it. Here is an example using DrJava's interactions tab:
> Integer.parseInt("5" + Integer.toString(500))
5500
> Integer.parseInt(Integer.toString(5) + Integer.toString(500))
5500
But there is a much more succinct (but less efficient) way since adding "" to an int will convert it to a string:
> Integer.parseInt(5 + "" + 500)
5500
If you need to handle negative numbers you can do:
if (n>0)
System.out.println(Integer.parseInt(p + "" + n));
else
System.out.println(Integer.parseInt("-" + p + "" + -n));

How to match the given output for Java Computer Guess Your Number Game; Binary Search

I have been having a lot of trouble with this and it is due soon, and I was wondering if anyone knows how to fix my problem. I have to create a program where:
"Your task is to implement a number guesser that works on the principle of a binary search. In each step, the computer cuts the query interval in half. When the interval contains a single number, it proclaims the answer. The user of the program selects a number between 1 and 100. The computer is then asked to guess the number."
The sample output goes:
Is your number greater than 50? (computer is asking this)
no (user responds with yes or no)
Is your number greater than 25?
no
Is your number greater than 13?
no
Is your number greater than 7?
yes
Is your number greater than 10?
yes
Is your number greater than 12?
yes
Is your number 13?
yes
13 is the answer. (computer declares final answer)
Thank you for playing the guessing game.
My sample output in contrast goes:
Is your number greater than 50?
no
Is your number greater than 25?
no
Is your number greater than 13?
no
Is your number greater than 7?
yes
Is your number greater than 10?
yes
Is your number greater than 11?
yes
Is your number greater than 12?
yes
Is your number 12?
yes
12 is the answer.
Thank you for playing the guessing game.
with some variation based on what edits I make.
The code is as follows:
//import statements
import java.util.Scanner;
import java.util.ArrayList;
public class Numbers
{
//constant to initialize the ArrayList
private final int AT_MOST = 100;
//anArrayList of type ArrayList<Integer> which is to hold the values from 1 - 100
private ArrayList<Integer> anArrayList;
/**
* Constructor of the Numbers() class which initializes all of the instance fields
*/
public Numbers()
{
anArrayList = new ArrayList<Integer>();
int i =0;
//while loop to initialize anArrayList with values from 1-100
while(i < AT_MOST)
{
anArrayList.add(i+1);
i++;
}
}
public void search()
{
int low = 0;
int high = anArrayList.size();
int i = 0;
int j = 0;
while(low <= high)
{
int mid = (low + high)/2;
mid = anArrayList.get(mid - 1);
Scanner in = new Scanner(System.in);
System.out.println("Is your number greater than " + mid + "?");
String answer = in.nextLine();
if(answer.equalsIgnoreCase("yes"))
{
low = mid + 1;
}
else if (answer.equalsIgnoreCase("no"))
{
high = mid - 1;
low++;
}
if(low == high+1)
{
Scanner in2 = new Scanner(System.in);
System.out.println("Is your number " + mid + "?");
String finalAnswer = in2.nextLine();
if(finalAnswer.equalsIgnoreCase("yes"))
{
System.out.println(mid + " is the answer.");
System.out.println("Thank you for playing the guessing game.");
low = high + 1;;
}
else
{
System.out.println("Please play again, something went wrong!");
low = high + 1;
}
}
}
}
}
Of course this also has a tester class which is relatively short:
public class NumbersGuesser
{
public static void main(String[] args)
{
//creates a new numbers object
Numbers newNumber = new Numbers();
//run method is called, game is played.
newNumber.search();
}
}
Since you made an effort to solve the problem, I went ahead and restructured your Numbers class.
The first thing I did was get rid of the ArrayList. You can just as easily do arithmetic on integers as traverse the ArrayList.
I added a couple of integers, distance and direction. After each guess, the distance is cut in half. The computer guesses high or low until the distance is reduced to zero. At that point, the number is somewhere between the low and the high, inclusive.
The direction just tells us whether we need to guess lower (-1) or higher (+1) for the next guess.
I pulled the high low scanner code into its own method. It looks confusing at first, but all it does is tell us whether to guess higher (true) or lower (false). By moving this code into its own method, I could concentrate on the guessing logic.
Finally, I closed the scanner at the end of the processing.
//import statements
import java.util.Scanner;
public class Numbers {
// constants to start the game
private final int AT_LEAST = 0;
private final int AT_MOST = 100;
/**
* Constructor of the Numbers() class
*/
public Numbers() {
}
public void search() {
int low = AT_LEAST;
int high = AT_MOST;
int guess = (low + high) / 2;
int distance = guess / 2;
int direction = 1;
System.out.println("Guess a number between " + low + " and " + high
+ ".");
Scanner in = new Scanner(System.in);
do {
boolean greaterThan = getHighLowResponse(in, direction, guess);
if (greaterThan) {
low = guess;
guess += distance;
direction = 1;
} else {
high = guess;
guess -= distance;
direction = -1;
}
distance /= 2;
} while (distance != 0);
for (int i = low; i <= high; i++) {
System.out.println("Is your number " + i + "?");
String finalAnswer = in.nextLine().toLowerCase();
if (finalAnswer.equalsIgnoreCase("yes")) {
System.out.println(i + " is the answer.");
System.out.println("Thank you for playing the guessing game.");
break;
}
}
in.close();
}
private boolean getHighLowResponse(Scanner in, int direction, int guess) {
do {
System.out.println("Is your number " + getDirection(direction)
+ " than " + guess + "?");
String answer = in.nextLine().toLowerCase();
if (direction < 0) {
if (answer.equals("yes"))
return false;
if (answer.equals("no"))
return true;
} else {
if (answer.equals("yes"))
return true;
if (answer.equals("no"))
return false;
}
} while (true);
}
private String getDirection(int direction) {
if (direction < 0) {
return "less";
} else {
return "greater";
}
}
}

Fibonacci Homework - java

We had to create a Fibonacci system. Could you tell me what I did wrong? It gives me an error under the while loop but I'm sure it is the way I constructed my variables.
public class Chapter3 {
public static void main (String args[]){
int numFn;//CREATE NUMBER OF FN, SUM OF FN, AND AVERAGE
int average[]=new int [0];
int sumFn []=new int [0];//ARRAY OF SUMFN
numFn = 1;//ASSIGN FN AS 1
int x = 0;//NUMBERIN SIDE FN ARRAY
int Fn []=new int[16];//CREATE FN ARRAY
Fn [0]=0;
while (numFn <15){
Fn[x]= Fn[x]-Fn[x-1];//SET THE CURRENT FN NUMBER
sumFn [x]=sumFn[x]+(sumFn[x-1]+Fn[x]);//SET CURRENT SUMFN NUMBER
average [x]= sumFn[x]/numFn;
System.out.println(numFn +"/t" +Fn+"/t" +sumFn+"/t" +average);
x++;
numFn++;
}
}
}
well i changed it up using youre guys's advice yet the first ouput is 1 then 0 for everything, used this code :
public class Chapter3 {
public static void main (String args[]){
int numFn;//CREATE NUMBER OF FN, SUM OF FN, AND AVERAGE
int average[]=new int [16];
int sumFn []=new int [16];//ARRAY OF SUMFN
numFn = 1;//ASSIGN FN AS 1
int x = 1;//NUMBERIN SIDE FN ARRAY
int Fn []=new int[16];//CREATE FN ARRAY
Fn [0]=0;
while (numFn <15){
Fn[x]= Fn[x]-Fn[x-1];//SET THE CURRENT FN NUMBER
sumFn [x]=sumFn[x]+(sumFn[x-1]+Fn[x]);//SET CURRENT SUMFN NUMBER
average [x]= sumFn[x]/numFn;
System.out.println(numFn +"\t" +Fn[x]+"\t" +sumFn[x]+"\t" +average[x]);
x++;
numFn++;
}
}
}
Several problems :
new int[0] means an empty array, which is not what you
want.
X value is 0 on the first loop execution, so Fn[X-1] is Fn[-1], which
would cause an ArrayOutOfBoundException.
Can you also be more explicit about the error you encounter please?
I think this is what you're after (this code starts with 1 and 1 and prints the first 20 terms)...
public class Fibonacci {
public static void main(String[] args) {
int n0 = 1, n1 = 1, n2;
System.out.print(n0 + " " + n1 + " ");
for (int i = 0; i < 18; i++) { // Loop for the next 18 terms
n2 = n1 + n0; //The next term is the sum of the previous two terms
System.out.print(n2 + " ");
n0 = n1; // The first previous number becomes the second previous number...
n1 = n2; // ...and the current number becomes the previous number
}
System.out.println();
}
}
As for your errors, read the other answers. Their advice is good. :)
Your sumFn array is declared with a length of 0. So any time you try to add any element to it, you will get an ArrayOutOfBoundException.
There are several problems with the code, even after fixing the one that causes the ArrayIndexOutOfBoundsException I doubt it will work. For starters, you must initialize the arrays you're using in the correct size:
int average[]=new int [16];
int sumFn []=new int [16];
The "x" variable should start in 1:
int x = 1;
Also, it's not clear what do you want to print, anyway the println() statement should be fixed
System.out.println(numFn +"\t" +Fn[x]+"\t" +sumFn[x] + "\t" +average[x]);
This was really helpful resolving the Fibonacci sequence exercise. However doesn't print the zero, so I added here...
/*
* FibonacciSequence.java
* ----------------------
* This program displays the values in the Fibonacci sequnece from F0 to F15.
*/
import acm.program.*;
public class FibonacciSequence extends ConsoleProgram{
public void run() {
int n0 = 1;
int n1 = 1;
int n2;
println("0" + "\n" + n0 + "\n" + n1);
for (int i = 0; i < 13; i++) { // Loop for the next 18 terms
n2 = n1 + n0; //The next term is the sum of the previous two terms
println(n2 + " ");
n0 = n1; // The first previous number becomes the second previous number...
n1 = n2; // ...and the current number becomes the previous number
}
println();
}
}

Does Java's Random Object create random numbers through equal opportunity?

I'm trying to write a short program that plays a dice game (normal 6 sided dice) for me. The first roll's number is added to the score. After the first roll, if I roll a 6 then the game stops and the score is recorded (without adding the 6). If a 6 is rolled on the first roll, that's fine and it's added like any other number 1 through 5. I'm trying to run a bunch of iterations of this game such that I have a long list of scores pre-bust (a bust being a rolled 6). I rearrange those scores to be in order from smallest to largest and then find the median of the list which is the score at which it is optimal to stop.
For some reason I keep getting 13 when I run the program but I know for a fact that the answer should be 15. Would using Random in Java would have some sort of effect on the median? I don't exactly know how Random generates the numbers and whether it creates them with equal opportunity. Also, is there anything that just pops out that shouldn't work?
import java.util.*;
public class DiceRoller {
private static Random r = new Random();
private static final int games = 10001;
private static int[] totalScores = new int[games];
private static int index = 0;
public static void main(String[] args) {
int score = 0; boolean firstRoll = true;
while (index < games) {
int roll = roll();
if (firstRoll) {
score += roll;
firstRoll = false;
} else {
if (roll == 6) {
totalScores[index] = score;
index++;
score = 0; firstRoll = true;
} else {
score += roll;
}
}
}
System.out.println("The median is " + median() + ".");
}
public static int roll() {
return r.nextInt(6) + 1;
}
public static int median() {
Arrays.sort(totalScores);
int temp = totalScores[games / 2];
return temp;
}
}
You get 13 because that's the correct result. A little mathematics: if S is the random variable representing the score of any one of these games, then you can consider the Probability generating function f(z) of S. From the description of the game, this probability generating function satisfies the equation:
f(z) = (z + z^2 + z^3 + z^4 + z^5 + z^6) / 36 + f(z)(z + z^2 + z^3 + z^4 + z^5) / 6
This takes a bit of thought, or familiarity with this sort of construction: the left-hand term on the right-hand side takes account of the probabilities of getting 1 through 6 in a simple 2-roll game; the right-hand term involving f(z) takes account of games involving 3 or more rolls, expressing them in terms of the final pre-6 roll (which must be in the range 1 through 5) and the preceding rolls, whose probabilities we can express recursively using f again.
Anyway, after getting this far, one can rearrange to describe f as a rational function of z, and then expand as a power series, which begins:
f(z) = 1/36*z + 7/216*z^2 + 49/1296*z^3 + 343/7776*z^4 + 2401/46656*z^5 + 16807/279936*z^6 + 63217/1679616*z^7 + 388087/10077696*z^8 + 2335585/60466176*z^9 + 13681927/362797056*z^10 + 77103313/2176782336*z^11 + 409031959/13060694016*z^12 + 2371648321/78364164096*z^13 + 13583773735/470184984576*z^14 + ...
(I used Pari/GP to get this.)
The coefficient of z^k then describes the probability of the value of the game being k; thus there's a 1 in 36 chance of the score being 1, a 7 in 216 chance of getting 2, and so on. The sum of the first 12 coefficients is 0.472828864487196328..., while the sum of the first 13 coefficients is 0.5030933144224321950968.... So the median is indeed 13.
To provide an independent check, I wrote a quick Python program:
from __future__ import division
import random
def roll():
return random.randint(1, 6)
def play():
score = roll()
while True:
throw = roll()
if throw == 6:
break
score += throw
return score
all_scores = sorted(play() for _ in xrange(1000001))
print "median is: ",all_scores[len(all_scores) // 2]
print "fraction of scores <= 12: ",all_scores.index(13) / len(all_scores)
print "fraction of scores <= 13: ",all_scores.index(14) / len(all_scores)
Sure enough, here are the results:
iwasawa:~ mdickinson$ python dice_game.py
median is: 13
fraction of scores <= 12: 0.472811527188
fraction of scores <= 13: 0.502863497137
So to answer your question, the results you're seeing are not evidence of any sort of weakness in Java's random number generation.
Random is not perfectly random and has some deficiencies. However for this use case you are very unlikely to notice the difference. You can assume every value 1 to 6 is equally likely.
For comparison here is another solution which counts the number of occurrences of a total rather than recording every value. As you can see this performs well even if you have 1000x more games. This works best when you have a small number of outcomes and a high number duplicates. It is naturally sorted.
import java.util.Random;
public class DiceRoller {
private static final int MAX_VALUE = 300; // assume at most this total
private static final int GAMES = 10000001;
public static void main(String... args) {
int[] count = new int[MAX_VALUE];
Random rand = new Random();
for (int i = 0; i < GAMES; i++)
count[totalScore(rand)]++;
System.out.println("The median is " + median(count, GAMES) + ".");
}
private static int median(int[] count, int games) {
int findTotal = games/2;
for (int i = 0; i < count.length; i++) {
findTotal -= count[i];
if (findTotal <= 0) return i;
}
throw new AssertionError();
}
private static int totalScore(Random rand) {
int total = rand.nextInt(6) + 1;
for(int n;(n = rand.nextInt(6) + 1) != 6;)
total += n;
return total;
}
}
Here is some code that shows you the distribution of the results. It doesn't really answer the question, but maybe it helps you in your research.
package so7297660;
import java.util.Random;
public class DiceRoller {
private static final int N = 10000000;
private static final Random r = new Random();
private static final int[] result = new int[100];
public static int roll() {
return r.nextInt(6) + 1;
}
private static int singleGame() {
int score = roll();
while (true) {
int roll = roll();
if (roll == 6) {
return score;
} else {
score += roll;
}
}
}
private static int median() {
int n = 0;
for (int i = 0; i < result.length; i++) {
if (n + result[i] >= N / 2) {
return i;
}
n += result[i];
}
throw new IllegalStateException();
}
public static void main(String[] args) {
for (int i = 0; i < N; i++) {
int score = singleGame();
int index = Math.min(score, result.length - 1);
result[index]++;
}
for (int i = 0; i < result.length; i++) {
System.out.println(i + "\t" + result[i]);
}
System.out.println("median\t" + median());
}
}

Categories

Resources