• Tidak ada hasil yang ditemukan

Drills in Addition

Dalam dokumen Pelajari tentang Advanced topics in Java (Halaman 171-176)

Random Numbers, Games, and Simulation

6.5 Drills in Addition

We want to write a program to drill a user in simple arithmetic problems (Program P6.3). More specifically, we want to write a program to create addition problems for a user to solve. The problems will involve the addition of two numbers. But where do the numbers come from? We will let the computer “think” of the two numbers. By now, you should know that, in order to do this, the computer will generate two random numbers.

We also need to decide what size of numbers to use in the problems. This will determine, to some extent, how difficult the problems are going to be. We will use two-digit numbers, that is, numbers from 10 to 99. The program can be easily modified to handle numbers in a different range.

The program will begin by asking the user how many problems he wants to be given. The user will type the number required. He will then be asked how many attempts he wants to be given for each problem. He will enter this number. The program then proceeds to give him the requested number of problems.

The following is a sample run of the program. Underlined items are typed by the user; everything else is typed by the computer.

Welcome to Problems in Addition How many problems would you like? 3 Maximum tries per problem? 2 Problem 1, Try 1 of 2 80 + 75 = 155 Correct, well done!

Problem 2, Try 1 of 2 17 + 29 = 36 Incorrect, try again Problem 2, Try 2 of 2 17 + 29 = 46 Correct, well done!

Problem 3, Try 1 of 2 83 + 87 = 160 Incorrect, try again Problem 3, Try 2 of 2 83 + 87 = 180 Sorry, answer is 170

Thank you for playing. Bye...

All the details are shown in Program P6.3. In the interest of brevity, we have not validated the input provided by the user. However, it is strongly recommended that all user input be validated to ensure that your programs are as robust as possible.

Program P6.3

import java.util.*;

public class Arithmetic {

public static void main(String[] args) { Scanner in = new Scanner(System.in);

System.out.printf("\nWelcome to Problems in Addition\n\n");

System.out.printf("How many problems would you like? ");

int numProblems = in.nextInt();

System.out.printf("Maximum tries per problem? ");

int maxTries = in.nextInt();

giveProblems(in, numProblems, maxTries);

System.out.printf("\nThank you for playing. Bye...\n");

} //end main

public static void giveProblems(Scanner in, int amount, int maxTries) {

int num1, num2, answer, response, tri; //'tri' since 'try' is a reserved word for (int h = 1; h <= amount; h++) {

num1 = random(10, 99);

num2 = random(10, 99);

answer = num1 + num2;

for (tri = 1; tri <= maxTries; tri ++) {

System.out.printf("\nProblem %d, Try %d of %d\n", h, tri, maxTries);

System.out.printf("%5d + %2d = ", num1, num2);

response = in.nextInt();

if (response == answer) {

System.out.printf("Correct, well done!\n");

break;

}

if (tri < maxTries) System.out.printf("Incorrect, try again\n");

else System.out.printf("Sorry, answer is %d\n", answer);

} //end for tri } //end for h } //end giveProblems

public static int random(int m, int n) {

//returns a random integer from m to n, inclusive return (int) (Math.random() * (n - m + 1)) + m;

} //end random } //end class Arithmetic

6.6 Nim

One version of the game called Nim is played between two people, A and B, say. Initially, there is a known number of matches (startAmount, say) on the table. Each player, in turn, is allowed to pick up any number of matches from 1 to some agreed maximum (maxPick, say). The player who picks up the last match loses the game.

For example, if startAmount is 20 and maxPick is 3, the game may proceed as follows:

A picks up 2, leaving 18 on the table.

B picks up 1, leaving 17 on the table.

A picks up 3, leaving 14 on the table.

B picks up 1, leaving 13 on the table.

A picks up 2, leaving 11 on the table.

B picks up 2, leaving 9 on the table.

A picks up 1, leaving 8 on the table.

B picks up 3, leaving 5 on the table.

A picks up 1, leaving 4 on the table.

B picks up 3, leaving 1 on the table.

A is forced to pick up the last match and, therefore, loses the game.

What is the best way to play the game? Obviously, the goal should be to leave your opponent with one match remaining on the table. Let’s call this a losing position. The next question to answer is, how many matches must you leave so that, no matter how many he picks up (within the rules of the game), you can leave him with one?

In this example, the answer is 5. Whether he picks up 1, 2, or 3, you can always leave him with 1. If he picks up 1, you pick up 3; if he picks up 2, you pick up 2; if he picks up 3, you pick up 1. So, therefore, 5 is the next losing position.

The next question is, how many matches must you leave so that, no matter how many he picks up (within the rules of the game), you can leave him with 5? The answer is 9. Try it!

And so on. Reasoning this way, we discover that 1, 5, 9, 13, 17, and so on, are all losing positions. In other words, if you can leave your opponent with any of these number of matches, you can force a win.

In this example, the moment B left A with 17 matches, B was in a position from which he could not lose, unless he became careless.

In general, losing positions are obtained by adding 1 to multiples of maxPick+1. If maxPick is 3, multiples of 4 are 4, 8, 12, 16, and so on. Adding 1 gives the losing positions 5, 9, 13, 17, and so on.

We will write a program in which the computer plays the best possible game of Nim. If it can force the user into a losing position, it will. If the user has forced it into a losing position, it will pick up a random number of matches and hope that the user makes a mistake.

If remain is the number of matches remaining on the table, how can the computer determine what is the best move to make?

If remain is less than or equal to maxPick, the computer picks up remain-1 matches, leaving the user with 1.

Otherwise, we perform this calculation:

r = remain % (maxPick + 1)

If r is 0, remain is a multiple of maxPick+1; the computer picks up maxPick matches, leaving the user in a losing position. In this example, if remain is 16 (a multiple of 4), the computer picks up 3, leaving the user with 13—a losing position.

If r is 1, the computer is in a losing position and picks up a random number of matches.

Otherwise, the computer picks up r-1 matches, leaving the user in a losing position. In this example, if remain is 18, r would be 2. The computer picks up 1, leaving the user with 17—a losing position.

This strategy is implemented in the function bestPick, part of Program P6.4, which pits the computer against a user in our version of Nim.

Program P6.4

import java.util.*;

public class Nim {

public static void main(String[] args) { Scanner in = new Scanner(System.in);

System.out.printf("\nNumber of matches on the table? ");

int remain = in.nextInt();

System.out.printf("Maximum pickup per turn? ");

int maxPick = in.nextInt();

playGame(in, remain, maxPick);

} //end main

public static void playGame(Scanner in, int remain, int maxPick) { int userPick;

System.out.printf("\nMatches remaining: %d\n", remain);

while (true) { //do forever...well, until the game ends do {

System.out.printf("Your turn: ");

userPick = in.nextInt();

if (userPick > remain)

System.out.printf("Cannot pick up more than %d\n", Math.min(remain, maxPick));

else if (userPick < 1 || userPick > maxPick)

System.out.printf("Invalid: must be between 1 and %d\n", maxPick);

} while (userPick > remain || userPick < 1 || userPick > maxPick);

remain = remain - userPick;

System.out.printf("Matches remaining: %d\n", remain);

if (remain == 0) {

System.out.printf("You lose!!\n"); return;

}

if (remain == 1) {

System.out.printf("You win!!\n"); return;

}

int compPick = bestPick(remain, maxPick);

System.out.printf("I pick up %d\n", compPick);

remain = remain - compPick;

System.out.printf("Matches remaining: %d\n", remain);

if (remain == 0) {

System.out.printf("You win!!\n");

return;

}

if (remain == 1) {

System.out.printf("I win!!\n");

return;

}

} //end while (true) } //end playGame

public static int bestPick(int remain, int maxPick) {

if (remain <= maxPick) return remain - 1; //put user in losing position int r = remain % (maxPick + 1);

if (r == 0) return maxPick; //put user in losing position if (r == 1) return random(1, maxPick); //computer in losing position return r - 1; //put user in losing position } //end bestPick

public static int random(int m, int n) {

//returns a random integer from m to n, inclusive return (int) (Math.random() * (n - m + 1)) + m;

} //end random } //end class Nim

Note the use of the do...while statement for getting and validating the user’s play. The general form is as follows:

do <statement> while (<expression>);

As usual, <statement> can be simple (one-line) or compound (enclosed in braces). The words do and while and the brackets and semicolon are required. The programmer supplies <statement> and <expression>. A do...while is executed as follows:

1. <statement> is executed.

2. <expression> is then evaluated; if it is true, repeat from step 1. If it is false, execution continues with the statement, if any, after the semicolon.

As long as <expression> is true, <statement> is executed. It is important to note that because of the nature of the construct, <statement> is always executed at least once. This is particularly useful in a situation where we want

<statement> to be executed at least once. In this example, we need to prompt the user at least once for his play, hence the reason for do...while.

The following is a sample run of Program P6.4:

Number of matches on the table? 30 Maximum pickup per turn? 5

Matches remaining: 30 Your turn: 2

Matches remaining: 28 I pick up 3

Matches remaining: 25 Your turn: 3

Matches remaining: 22 I pick up 3

Matches remaining: 19 Your turn: 6

Invalid: must be between 1 and 5 Your turn: 1

Matches remaining: 18 I pick up 5

Matches remaining: 13

Your turn: 4

Matches remaining: 9 I pick up 2

Matches remaining: 7 Your turn: 9

Cannot pick up more than 5 Your turn: 2

Matches remaining: 5 I pick up 4

Matches remaining: 1 I win!!

We note, in passing, that it would be useful to provide instructions for the game when it is run.

Dalam dokumen Pelajari tentang Advanced topics in Java (Halaman 171-176)