Download Solutions

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
Solutions to DIT948 Re-exam from 2014-08-18
Cezar Ionescu
READ ME
These solutions of the exercises set on 2014-08-18 for the DIT948 (Introduction to Java Programming) re-exam have been written for the benefit of
the students taking future exams and re-exams in the same style.
As such, they are didactical, rather than elegant. I have tried to explain
the answers and how a reasonably well prepared student might have arrived
at them.
They are NOT meant to be a model to be slavishly imitated. In particular, please consider that brevity is a virtue, and do not repeat for my benefit
all the explanations I have given here for your benefit.
Solutions to DIT948 Re-exam from 2014-08-18
1. [10pts] Consider the class:
package MyRobot;
public class Robot {
public int street;
public int avenue;
public int direction;
private double speed;
protected String name;
double stepSize;
public final String getName() {
return name;
}
private void flip() {
direction = - direction;
}
protected double time(double distance){
return distance / stepSize;
}
}
Class TestRobot is a subclass of Robot:
1
2
3
4
5
6
7
8
9
10
11
12
13
package MyRobot;
public class TestRobot extends Robot {
public void test() {
System.out.println(street);
System.out.println(avenue);
System.out.println(direction);
System.out.println(speed);
System.out.println(name);
System.out.println(stepSize);
System.out.println(getName());
flip();
System.out.println(time(123.75));
2
Solutions to DIT948 Re-exam from 2014-08-18
14
15
}
}
Which of the lines 5–13 will cause a compilation error and why? How
does the answer change if TestRobot is in a different package from
Robot (for example, if we replace the first line with import MyRobot.Robot;)?
Solution:
If we have an instance x of type T, then a field (or method) f of class
T is in scope in a subclass of T if:
1) the access modifier of f is public;
2) the access modifier is protected;
3) the access modifier is the default one (no keyword) and the subclass
is in the same package as T;
If none of these three conditions are met, then f is not in scope in the
subclass, and attempting to use it will generate a compiler error.
Therefore:
(a) lines 5, 6, 7, and 11 do not cause a compiler error since rule 1)
applies;
(b) lines 9 and 13 do not cause a compiler error since rule 2) applies;
(c) line 10 does not cause a compiler error since rule 3) applies.
No rules apply to lines 8 and 12. Therefore, lines 8 and 12 generate a
compiler error.
If the subclass is in a different package, then rule 3) no longer applies to
line 10. Therefore, line 10 will also (in addition to 8 and 12) generate
a compiler error in this case.
2. [10pts] Your boss wrote a method that was supposed to count the
number of strictly positive integers in a given array (that is, integers
that are > 0).
Thus, if myArray = -1, 5, 0, 7, -2, then there are two strictly positive integers in myArray, namely 5 and 7, and countPositive(myArray)
should therefore return 2.
Unfortunately, things didn’t really work out that way: in fact, the
method doesn’t even compile! Still, it’s your boss’s program, you can’t
just throw it away and write a new one. Make the changes necessary
for the method to compile and return the correct result.
3
Solutions to DIT948 Re-exam from 2014-08-18
public static int countPositive(int[] a) {
int length = a.length;
for (int i = 0; i <= length; i++) {
if (a > 0) {
count++;
} else {
count--;
}
}
return length;
}
Solution:
We have:
(a) The variable count used in the for loop is not initialized. Since
it is used for counting the number of positive elements found, it
should be of type integer and initialized to zero.
(b) The for loop should examine each element of the array and not
go beyond the array length. The test should therefore be i <
length, not i <= length.
(c) The variable to be examined in the loop at step i should be a[i].
Instead, the entire array a is compared with 0, which causes a
compiler error. To correct this, replace a with a[i].
(d) There is no reason to decrement count if a non-positive array element is found. The simplest way to correct this error is to comment out the decrementing instruction. One can also comment
out the entire else branch of the conditional.
(e) Finally, instead of returning count, the length of the array is returned. To repair this, replace length with count.
The corrected code is:
public static int countPositive(int[] a) {
int length = a.length;
int count = 0;
4
Solutions to DIT948 Re-exam from 2014-08-18
for (int i = 0; i < length; i++) {
if (a[i] > 0) {
count++;
} else {
// count--;
}
}
return count;
}
3. [10pts] Class B is a subclass of class A, and class C is a subclass of class
B. Which of the following assignments are incorrect and why?
1
2
3
4
5
6
7
8
9
10
A
B
C
a
b
c
a
b
a
c
a
b
c
=
=
=
=
=
=
=
= new A() ;
= new B() ;
= new C();
b ;
a ;
a;
c;
new A() ;
new C() ;
new A() ;
Solution:
In general, we can assign to a variable of type T only a value which “is
a” T. If a class ST extends a class T, then a value of type ST “is a” T,
whereas a value of type T is not an ST. Accordingly, we have:
(a) Lines 1–3 are correct: we are introducing variables of type A, B,
C and initializing them with values of type A, B, C respectively.
(b) In line 4, we are assigning to the variable a of type A an expression,
b, which is of type B. Since B extends A, we have that b “is an” A,
therefore the assignment is correct.
(c) In line 5, we are assigning to the variable b of type B an expression,
a, which is of type A. But A does not extend B, therefore a is not
a B, therefore the assignment is incorrect.
5
Solutions to DIT948 Re-exam from 2014-08-18
(d) In line 6, we are assigning to the variable c of type C an expression,
a, which is of type A. But A does not extend C, therefore a is not
a C, therefore the assignment is incorrect.
(e) In line 7, we are assigning to the variable a of type A an expression,
c, which is of type C. Since C extends B, any instance of C “is a”
B. But B extends A, therefore any value which “is a” B “is an” A
as well. Therefore, the assignment is correct.
(f) In line 8, we are assigning to the variable b of type B an expression,
new A(), which is of type A. But A does not extend B, therefore
new A() is not a B, therefore the assignment is incorrect.
(g) In line 9, we are assigning to the variable a of type A an expression,
new C(), which is of type C. Since C extends B, any instance of C
“is a” B. But B extends A, therefore any value which “is a” B “is
an” A as well. Therefore, the assignment is correct.
(h)
(i) In line 10, we are assigning to the variable c of type C an expression, new A(), which is of type A. But A does not extend C,
therefore new A() is not a C, therefore the assignment is incorrect.
[30pts] Consider the following very simple game, played by two players
with a dice (or “die”). First, one of the players decides whether they
will play for “high” or for “low”. Then they both roll the dice. If the
decision was “high”, the player who has decided wins only if his roll is
strictly higher than his opponent’s, otherwise the latter wins. Similarly,
if the decision was “low”, the player who has decided wins only if his
roll is strictly lower than his opponent’s, who wins otherwise.
In the following, you will implement several classes to represent this
game. You will do this by “filling in” the data and method definitions.
You don’t need to do any error checking or write comments.
Do not write “between the lines”! On your paper, clearly mark out
which code is supposed to go where. For example, the code supposed
to fill in the block A, the member variables of the class Race, should
appear as
4.
+--------- A -------------------+
|
private Random rand;
|
+-------------------------------+
and not squeezed on the page with the exam subjects!
6
Solutions to DIT948 Re-exam from 2014-08-18
Remark: Since block A has been filled in for you above, there are ten
blocks left for you to fill in for this exercise: B, C, D, E, F, G, H, I, J,
K. In general, a correct answer will bring three points. The blocks are
usually one or two lines long. End of remark.
The first class is used to represent the dice.
import java.util.Random;
public
//
//
//
class Dice {
Block A:
Declare here a private member variable:
the random number generator
public
//
//
//
}
Dice() {
Block B:
Here you should initialize
the random number generator
// One
public
//
//
//
//
//
//
}
roll of the dice
int roll() {
Block C:
Here, you should use the
random number generator
to return a number between 1 and 6
Recall that nextInt(n) returns a
number between 0 and n-1.
}
The second class represents a generic player. It is an abstract class,
not meant to be instantiated. All players share the roll method, but
differ in how they make their decision.
public
//
//
//
//
//
abstract class Player {
There is no generic way to decide
whether to play "high" or "low".
The decision will be represented by
a boolean: true for "high",
false for "low"
7
Solutions to DIT948 Re-exam from 2014-08-18
public abstract boolean decide();
public
//
//
//
}
int roll(Dice dice) {
Block D:
Here, you should roll the dice
and return the result
}
The next two classes represent concrete players. The first player takes
decisions randomly.
import java.util.Random;
public
//
//
//
//
class RandomPlayer extends Player {
Block E:
Here, you should declare a private member variable:
the random number generator to use
when taking decisions
public RandomPlayer() {
// Block F:
// Initialize the member variable here
}
public
//
//
//
//
//
}
boolean decide() {
Block G:
Use the member variable here
to return a boolean decision.
Recall that instances of Random
have a nextBoolean() method.
}
The next class represents a player who always does the opposite of what
he did last:
import java.util.Random;
public class AlternatingPlayer extends Player {
8
Solutions to DIT948 Re-exam from 2014-08-18
// Block H:
// Declare here a private member variable to
// store the previous decision
AlternatingPlayer() {
// Block I:
// Introduce and initialize here a local
// random number generator
//
//
//
//
//
Block J:
Now use here this local random number generator
to initialize the member variable
(The decision is random because in the
very beginning there is no "previous decision")
}
public
//
//
//
//
}
boolean decide() {
Block K:
Change here the member variable
to its opposite,
and return the result
}
Solution:
In Block B, we need to initialize the random number generator member
variable declared in Block A. We obtain a suitable value of type Random
using the constructor of the Random class.
+----------B-----------+
| rand = new Random(); |
+----------------------+
To fill in Block C, we note that nextInt(n) returns n possible results
between 0 and n − 1. We need six results, therefore we must use
nextInt(6). To obtain results in the range 1–6, we need to add one
to the values obtained by calling nextInt(6).
+--------------C--------------+
| return rand.nextInt(6) + 1; |
+-----------------------------+
9
Solutions to DIT948 Re-exam from 2014-08-18
In Block D, we use the roll method of the class Dice to return the
result.
+----------D----------+
| return dice.roll(); |
+---------------------+
Block E, just like Block A, declares a private member variable of type
Random. We can use the same code, unchanged.
+--------- E -------------------+
|
private Random rand;
|
+-------------------------------+
Similarly, Block F does the same initialization as Block B:
+----------F-----------+
| rand = new Random(); |
+----------------------+
In Block G, we need to return a random value of type boolean, therefore we just return the result of rand.nextBoolean():
+--------------G-------------+
| return rand.nextBoolean(); |
+----------------------------+
The AlternatingPlayer needs to “remember” its previous decision,
which is a boolean variable. Therefore, in Block H we need to declare
a boolean variable.
+---------------H---------------+
| private boolean prevDecision; |
+-------------------------------+
In Block I, we need to introduce a new variable of type Random and
perform the same initialization as in blocks B and F.
10
Solutions to DIT948 Re-exam from 2014-08-18
+-------------I---------------+
| Random rand = new Random(); |
+-----------------------------+
In Block J, the private member variable prevDecision has to be initialized with a random boolean value. The expression to use in the
initialization is the same one used in block G.
+------------------J-----------------+
| prevDecision = rand.nextBoolean(); |
+------------------------------------+
In Block K, we change the member variable to its opposite using the !
operator (“not”), and then return the result.
+---------------K---------------+
| prevDecision = !prevDecision; |
| return prevDecision;
|
+-------------------------------+
5. [20pts] In this exercise, we refer to the classes from above, but do not
require you to have implemented them (only that you understand how
to create and use instances of them).
Write a main method in which you
(a) create a new instance of AlternatingPlayer, call it alt;
(b) create a new instance of RandomPlayer, call it ran;
(c) create a new dice;
(d) initialize a boolean variable with alt’s decision;
(e) get the result of alt’s roll;
(f) get the result of ran’s roll;
(g) find out who has won and print an appropriate message. If alt’s
decision was true, he wins only if his roll is strictly larger than
ran’s. If alt’s decision was false, he wins only if his roll is strictly
smaller than ran’s.
Every item except the last is worth two points, the last one is worth
eight.
Solution:
11
Solutions to DIT948 Re-exam from 2014-08-18
public static void main(String[] args) {
// For a), b), and c) we use the constructors
// provided by the respective classes.
AlternatingPlayer alt = new AlternatingPlayer();
RandomPlayer ran = new RandomPlayer();
Dice dice = new Dice();
// For d), we need to introduce a new boolean variable
// and intialize it with alt’s decision by calling the
// "decide" method.
boolean altDecision = alt.decide();
// Since we’ll need to compare the results of the rolls,
// we need to introduce two new integer variables and
// initialize them using the "roll" method of the players
// with the argument being the "dice".
// (points f) and g) of the problem).
int altRoll = alt.roll(dice);
int ranRoll = ran.roll(dice);
// alt wins if:
//
the decision was "high" (true) and he rolled more than ran
// or
//
the decision was "low" (false) and he rolled less than ran
// otherwise ran wins.
// The following conditional, implementing g), has exactly this form.
if ((altDecision && (altRoll > ranRoll)) ||
(!altDecision && (altRoll < ranRoll)))
System.out.println("Alternating Player has won.");
else
System.out.println("Random Player has won.");
}
6. [20pts] An adjacent pair in an array a is a pair (a[i], a[i+1]) of
consecutive elements. For example, the adjacent pairs of a = {0, 1,
2, 3} are (0, 1), (1, 2), (2, 3). A value n is in all adjacent pairs
of an array of integers a, if for any pair (a[i], a[i+1]) one of the
elements of the pair is equal to n.
Implement a subroutine with the signature
boolean isInAllAdjPairs(int n, int[] a)
which tests if n is in all adjacent pairs of a. The function should return
12
Solutions to DIT948 Re-exam from 2014-08-18
false if there exists an adjacent pair in the array which does not
contain n, otherwise it should return true. For example:
n
1
2
5
7
a
{1, 2, 3}
{1, 2, 3, 2}
{5, 0, 0, 5}
empty
isInAllAdjPairs(n, a)
false
true
false
true
because
1 is in (1, 2) but not in (2, 3)
2 is in (1, 2), (2, 3), (3, 2)
5 is not in (0, 0)
there is no adjacent pair in the array
which does not contain 7
Make sure to consider the corner cases!
Solution:
We begin by considering the obvious corner cases. The return value for
the empty array is specified: true. Indeed, we need to return false
only if we find a pair in a in which both elements differ from n. But
in the case of the empty array we cannot find such a pair: indeed, we
cannot find any pairs at all. Therefore, we cannot return false, and
return true instead. Similar arguments apply to the one-element case,
for which we shall also return true.
We now consider the general case in which we have at least two elements. We need to examine the pairs in the array, one by one, but we
only need to do so until we find one pair which doesn’t contain n (or
until we run out of pairs). The exact number of pairs we have to go
through isn’t known beforehand, therefore we probably shouldn’t use a
for loop. Since we need to examine at least one pair (remember that
we have at least two elements in the array) we can first try a do-while
loop.
With these considerations, we can take a first cut at a pseudocode
solution:
if a.length < 2 return true
done = false // in the beginning we’re not done
do
if current pair doesn’t contain n
isInAll = false
done = true
if we still have pairs to examine
go to next pair
else
13
Solutions to DIT948 Re-exam from 2014-08-18
done = true
while (! done)
return isInAll
Further, we observe that we only set isInAll to false, therefore its
initial value must be true (otherwise it would never be possible to
return true at all). The most important question is how to examine the
current pair, and how to “go to the next pair”. Since an adjacent pair
is of the form (a[i], a[i+1]), we see that we only have to keep track
of the index i, which in the beginning should be 0. To go to the next
pair, we increment i. This only makes sense if the new, incremented
value, is still such that we can examine elements a[i] and a[i+1], that
is, such that i+1 < a.length, or i < a.length-1. Otherwise, we’re
done.
Now we can refine the pseudocode, obtaining:
if a.length < 2 return true
done = false // in the beginning we’re not done
isInAll = true
i = 0
do
if a[i] != n and a[i+1] != n
isInAll = false
done = true
i++
if i >= a.length - 1
done = true
while (! done)
return isInAll
The pseudocode is close enough to Java that a direct translation poses
no problems:
boolean isInAllAdjPairs(int n, int[] a) {
if (a.length < 2)
return true;
boolean done = false;
boolean isInAll = true;
int i = 0;
14
Solutions to DIT948 Re-exam from 2014-08-18
do {
if (a[i] != n && a[i+1] != n) {
isInAll = false;
done = true;
}
i++;
if (i >= a.length - 1)
done = true;
}
while (! done);
return isInAll;
}
While the code is correct, there are still some improvements, as we see
if we review the implementation. For example, we can see that we are
done if either isInAll is false or i >= a.length-1 after incrementing, or both. But then, that means that we only keep on going as long
as isInAll is true and i < a.length-1, which allows us to eliminate
the variable done and the second conditional by writing
boolean isInAllAdjPairs(int n, int[] a) {
if (a.length < 2)
return true;
boolean isInAll =
int i = 0;
do {
if (a[i] != n
isInAll =
}
i++;
}
while (isInAll &&
return isInAll;
true;
&& a[i+1] != n) {
false;
i < a.length-1);
}
Other improvements are possible, for example we can eliminate the
separate treatment of the corner cases by using a while loop (exercise!).
15