programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
Sheriffs:
Saloon Keepers:
Bartenders:

# java challange

Greenhorn
Posts: 6
So, my java teacher gave us this challenge which I have attached as a screenshot to the thread.

this is what I have done but I cant get it to work...

Screen-Shot-2016-10-29-at-23.59.09.png

Marshal
Posts: 58449
178
welcome to the Ranch

I think you have misunderstood the problem. I think you will only solve it with pencil and paper (and a large eraser, which you will need all the time). Draw a circle of people and count round them; at each round throw the dips rhyme don't alter any of the people, but remove one altogether. You now have a different number to count for the next chant of the rhyme. See if that will give you the algorithm.

Sheriff
Posts: 11747
191
The instructions are ambiguous and open to at least two interpretations. One reasonable interpretation can lead to a solution that doesn't match the given example's results.

The instructions basically are: "Players stand in a circle and chant the rhyme. On each word, point at the next person. When the rhyme finishes, whoever is being pointed at leaves the circle. The last person remaining wins."

The "point at the next person" part is ambiguous and open to interpretation. WHO points at the next person? Since "who" is implied, you have to make your own assumption.  A reasonable assumption might be that whoever is "it" points to the next person, who then becomes the "it" for the next word chanted. Going with this interpretation, it would be reasonable to assume that the first "it" would be Person #1. Another omission is a specific mention of where to start after a person has left the circle. Do you start over with Person 1 or do you continue with the person who is next to whoever leaves the circle as "it"?

Let's say you made an initial interpretation that the game starts with Person 1 as the first "it". You also make the assumption that when someone leaves the circle, whoever was next to him/her would become "it".

We then try to play out the example with six people and the rhyme is "Eenie, Meenie, Mainee, Mo," with four words.

Persons 1, 2, 3, 4, 5, 6 stand in a circle. Everybody faces towards the center of the circle, with Person 2 on the left of Person 1 and Person 6 on the right of Person 1 and the rest positioned similarly so you can count 1, 2, 3, 4, 5, 6 going clockwise around the circle.

The game starts with Person 1 as "it". Chanting begins.

"Eenie" - Person 1 points to Person 2
"Meenie" - Person 2 points to Person 3
"Mainee" - Person 3 points to Person 4
"Mo" - Person 4 points to Person 5

Rhyme ends, person being pointed at is Person 5, who now has to leave the circle. Next round of chanting starts again with Person 6 as "it".

"Eenie" - Person 6 points to Person 1
"Meenie" - Person 1 points to Person 2
"Mainee" - Person 2 points to Person 3
"Mo" - Person 3 points to Person 4

Rhyme ends, Person 4 is "it" and has to leave the circle. Next round starts with Person 6 as "it" (remember, Person 5 already left the circle so Person 6 was standing next to Person 4 in this round).

This obviously does not match the stated expected results.

To get a solution that matches the stated expected results of the example given, you have to make two assumptions.

Assumption #1: There's a phantom "it" who isn't standing in the circle. The phantom "it" does the pointing throughout the entire game. The phantom "it" will start by pointing at nobody in particular. When the chanting starts, the "it" will point to Person 1 first, then Person 2, then Person 3, and so on.

Assumption #2: After a person leaves the circle and the next round of chanting starts, the phantom "it" will start by pointing at the person next to whoever left the circle. So, in the example given, after Person 4 leaves the circle in the first round, the "it" will point to Person 5 when chanting starts back up for the second round with "Eenie".

Alternatively, you can make an adjustment to the game specifications:  On each word, players take turns raising their hand. Players take turns going clockwise, so when one person takes a turn and raises their had, the person on his/her left will have the next turn with the next word of the rhyme. The person who has their hand up when the last word of the rhyme is chanted has to leave the circle. Subsequent rounds start with the player who would have had the next turn raising their hand when the first word of the rhyme is chanted.

With this modification, you'll get the expected results:

"Eenie" - Person 1 raises hand
"Meenie" - Person 2 raises hand
"Mainee" - Person 3 raises hand
"Mo" - Person 4 raises hand

Person 4 has to leave the circle. Person 5 will start the next round, raising his/her hand on "Eenie". If you play it out to the end, this will match the expected results of Person 4, then 2, then 1, then 6 leaving the circle, with 5 being the last one left.

Junilu Lacar
Sheriff
Posts: 11747
191
Solving this challenge using an array and procedural code is not that difficult. If you want a real challenge, try solving this without an array, using pure object-orientation. Your output with six people should look something like this:

Game: 6 people, Rhyme is "Eenie, Meenie, Mainee, Mo"

Round #1
Person 1: "Eenie"
Person 2: "Meenie"
Person 3: "Mainee"
Person 4: "MO, I'm out!"

Round #2
Person 5: "Eenie"
Person 6: "Meenie"
Person 1: "Mainee"
Person 2: "MO, I'm out!"

Round #3
Person 3: "Eenie"
...
Person 1: "MO, I'm out!"

...
Person 6: "MO, I'm out!"

Person 5: "I win!"

This is similar to one of the challenges we had at the recent Global Day of Code Retreat, except we were trying to program Conway's Game of Life without using an array.

Junilu Lacar
Sheriff
Posts: 11747
191
And if you really want to stretch yourself, don't use any classes from the standard Collections API. Write your own ADT (Abstract Data Type).

Junilu Lacar
Sheriff
Posts: 11747
191

- that would be the progression of my reaction to reading this code.

That code is about as opaque as you can write using just single-letter names.  Having comments explaining what those variable names stand for does practically NOTHING to make the readability of the code any better.

Unreadable code is more likely than not to be incorrect code. The problem is that it won't be obviously incorrect, even to the person who wrote it.

Campbell Ritchie
Marshal
Posts: 58449
178

Junilu Lacar wrote:The instructions are ambiguous and open to at least two interpretations.  . . .

Not if you remember it from primary school. It is always the same person who points. After somebody has been pointed to and called not it, the person to their left is the next to be pointed to. There were various rhymes used, including Eeny meeny miney mo … and

Ip Dip,
My llittle Ship,
Sails on the Water Like a Saucer
You—Are—Not—It.

…where the moves to the next person are shown by Capital Letters. By the age of seven, I had come to suspect that the dipping rhymes were actually deterministic and not, as everybody else thought, random, and they would always pick the person standing in a particular position, but didn't destroy centuries' worth of playground games by voicing that suspicion.

Campbell Ritchie
Marshal
Posts: 58449
178

A few minutes ago, I wrote:. . .  Eeny meeny miney mo … . . . .

That rhyme had four lines each with four moves in, so you point from the first person to the sixteenth in one round of that rhyme. Since I don't have Opie as a middle name, shall we stick to the original intent of the question with four words at a time.

Campbell Ritchie
Marshal
Posts: 58449
178
The dipping rhymes were the first stage of a game of tig (pronounced tag in some places) and whoever was IT had to do the chasing first. Whoever IT was would be subject to vicious taunting from the Kensworth girls … at least until they caught one of those girls, who would immediately become IT herself.

Junilu Lacar
Sheriff
Posts: 11747
191

Campbell Ritchie wrote:

Junilu Lacar wrote:The instructions are ambiguous and open to at least two interpretations.  . . .

Not if you remember it from primary school. It is always the same person who points. After somebody has been pointed to and called not it, the person to their left is the next to be pointed to.

Assumptions. Not everybody will have had the same primary school experience. Wrong assumptions almost always lead to bugs and just because you can draw from experience that will lead you to correct assumptions, that doesn't mean everybody else will make those same assumptions. Besides, requirements should be as unambiguous as possible.

Junilu Lacar
Sheriff
Posts: 11747
191
And even when you say "it's always the same person who points" you don't say if that person is in the circle or not. If they're in the circle, what happens when they are out? Do they still keep doing the pointing? I'm just trying to come at it from the point of view of someone who has absolutely no past experience with this kind of game. When you're trying to debug requirements, making no assumptions usually helps you find more gaps and clarifications that need to be addressed.

Zach Stonne
Greenhorn
Posts: 6
guys im only THREE weeks into java ok, im a complete noob, im only going to start OOP next week. now my logic is the following, and if somone could help me replicate this in java and explain what there doing, Id be really thankful:
- create array from 1 to (no. of friends)
- fill array with int 1s
- create a loop which will do the following:
- decrement an int which is equal to (n of friends) stated in the beginning
- replace every "1" with a zero, jumping through the array in the (n of words in the rhyme) stated in the start
-stops when the value being decremented is no longer grater than 1 there for only one array entry is equal to one, thats the last one standing.
- create a loop which will look through the array until it finds the last 1
- prints out the array number of that with that number

Zach Stonne
Greenhorn
Posts: 6
AND ITS QUITE CLEAR THAT IF THE FISRT PERSON TO LEAVE IS NUMBER 4 IN A RYHME WITH FOR NUMBERS ITS TO BE DONE LIKE THAT, NOT THE NEXT.

ITS NOT OPEN TO ANY OTHER INTERPRETATION, I MEAN THEY EVEN GAVE AN EXAMPLE TO EXPLAIN WHAT THEY MENT.

NOW PLEASE GUYS STOP ARGUING, AND STOP COMMENTING ON THE QUESTION AND PLEASE TRY TO ANSWER THE QUESTION AND THEN EXPLAIN THAT ANSWER SO I CAN EVOLVE  AND LEARN FROM THAT.

Junilu Lacar
Sheriff
Posts: 11747
191
Please don't use all caps. I suppose you know that's SHOUTING. Use your inside voice. Also, we're not arguing. We're simply discussing. There's a difference.

You wrote:

This code does not do what you want it to do, obviously.  Think about what happens when Person 5 wins.  That means that Person 1, Person 2, Person 3, ... etc. will be 0.  Will your for loop ever get past f = 0 then?

Junilu Lacar
Sheriff
Posts: 11747
191
And after you figure out how to write the correct logic for that loop, I suggest you try to see if that section of code where you start with the claim
actually does what it claims to do.

Junilu Lacar
Sheriff
Posts: 11747
191

Zach Stonne wrote:
- create a loop which will do the following:
- decrement an int which is equal to (n of friends) stated in the beginning
- replace every "1" with a zero, jumping through the array in the (n of words in the rhyme) stated in the start
-stops when the value being decremented is no longer grater than 1 there for only one array entry is equal to one, thats the last one standing.

This part of your interpretation of what needs to be done doesn't look right. Like Campbell was saying, you should try to walk through the process manually yourself to see if the instructions you want to give the computer make sense and will actually get you the results you need.

Junilu Lacar
Sheriff
Posts: 11747
191

Zach Stonne wrote:ITS NOT OPEN TO ANY OTHER INTERPRETATION, I MEAN THEY EVEN GAVE AN EXAMPLE TO EXPLAIN WHAT THEY MENT.

Without the example to clarify what they meant, the original statement of the game rules are absolutely open to interpretation. That's no excuse for sloppy requirements.  The part that says "Then they start again, pointing where they left off."  Well, where they left off is now an empty spot in the circle. So, it's really more accurate to say "pointing to the person next to whoever left the circle."  All my comments about the requirements may seem smart-alecky and dumb but I've been in this business long enough to know that if there's a wrong way to interpret ambiguous requirements, that's the way a lot of programmers will interpret them.

Zach Stonne
Greenhorn
Posts: 6
Ok, so now I have this which is almost working but it wont print out correctly, its only leaving number 1 out,  but other print outs of the looping array suggest that its doing it correcly

Here is the newer program:
/*
Estevao van Zeller
challange 02
#attempt 3
*/

import java.io.*;
import java.util.*;

public class elerningChalange02 {
public static void main(String[] args)
{
//user input number of friends (int a)
Scanner friendsScanner = new Scanner(System.in);
System.out.println("Enter the number of friends: ");
int a = friendsScanner.nextInt();

//user input words in rhyme (int b)
Scanner wordsScanner = new Scanner(System.in);
System.out.println("Enter the number of words in the rhyme: ");
int b = wordsScanner.nextInt();

// establish an array from 1 to x
int z = 1;
int [] arrayA = new int[a+1];
for (;z < arrayA.length;z++)
{
arrayA[z] = z+1;
System.out.println("array z" + arrayA[z]);
}

// c = curent freind, to be eliminated
int c = 0;
// d = active friends
int d = a;
// e = controling var (0)
int e = 0;
// f = scaning for the remaning number
int f = 0;

// here wer going to replace the 1s in the array until only one 1 is left
for (;d>1;)
{
for(;e<b;)
{
c=c+1;
if (c>a)
{
c = c - a;
}
if (arrayA[c]>0)
{
e = e + 1; }
}
arrayA[c] = 0;
d=d-1;
System.out.println("array c" + arrayA[c]);
}

//here we search for that remaining 1 and we output the number of the array its stored in

for(;arrayA[f] < 1;)
{
f=f+1;
System.out.println("array f" + arrayA[f]);
}
System.out.println("number "+f+" is left");
}
}

And here is the output:

Enter the number of friends:
4
Enter the number of words in the rhyme:
4
array z2
array z3
array z4
array z5
array c0
array c0
array c0
array f2
number 1 is left

Zach Stonne
Greenhorn
Posts: 6
Sorry, that was an older version, here is a newer one:

Here is the newer program:
/*
Estevao van Zeller
challange 02
#attempt 3
*/

import java.io.*;
import java.util.*;

public class elerningChalange02 {
public static void main(String[] args)
{
//user input number of friends (int a)
Scanner friendsScanner = new Scanner(System.in);
System.out.println("Enter the number of friends: ");
int a = friendsScanner.nextInt();

//user input words in rhyme (int b)
Scanner wordsScanner = new Scanner(System.in);
System.out.println("Enter the number of words in the rhyme: ");
int b = wordsScanner.nextInt();

// establish an array from 1 to x
int z = 1;
int [] arrayA = new int[a+1];
for (;z < arrayA.length;z++)
{
arrayA[z] = 1;
System.out.println("array z" + arrayA[z]);
}

// c = curent freind, to be eliminated
int c = 0;
// d = active friends
int d = a;
// e = controling var (0)
int e = 0;
// f = scaning for the remaning number
int f = 0;

// here wer going to replace the 1s in the array until only one 1 is left
for (;d>1;)
{
for(;e<b;)
{
c=c+1;
if (c>a)
{
c = c - a;
}
if (arrayA[c]>0)
{
e = e + 1; }
}
arrayA[c] = 0;
d=d-1;
System.out.println("array c" + arrayA[c]);
}

//here we search for that remaining 1 and we output the number of the array its stored in

for(;arrayA[f] < 1;)
{
f=f+1;
System.out.println("array f" + arrayA[f]);
}
System.out.println("number "+f+" is left");
}
}

output:

And here is the output:

Enter the number of friends:
4
Enter the number of words in the rhyme:
4
array z1
array z1
array z1
array z1
array c0
array c0
array c0
array f1
number 1 is left

Junilu Lacar
Sheriff
Posts: 11747
191
I don't see how that output suggests that your code is working correctly.

Zach Stonne
Greenhorn
Posts: 6
I ask for an array with four enties, all with an int of 1
I put a print out in that loop, which shows that it has done what I asked:

"array z1
array z1
array z1
array z1 "

then its going to do that whole thing where it replaces each number 1 with a 0 with that pattern mentioned earlier until only one entry in the array has a 1

again I print this out in the loop and it only shows 3 out of for print outs with a zero meaning one of them is still a one, exactly as I want it

"array c0
array c0
array c0 "

now the part which I can't get to work I think is the end , where its supposed to increment a value starting at 0 (f) while the array entry==0, when it reaches a one, the loop stops and it should output the incremented value , in this case its supposed to print something like this out:

"array f0
arrayf1
number 2 is left"

but its outputting this:

"array f1
number 1 is left"

which makes no sense.

Junilu Lacar
Sheriff
Posts: 11747
191
No, it doesn't make sense to me either. That's largely because I can't follow the logic in your code more than anything else.  Compare what I wrote:

And here's the output of the program:

In the circle: [Player 1, Player 2, Player 3, Player 4, Player 5, Player 6]
Player 1 <- Eenie,
Player 2 <- Meenie,
Player 3 <- Mainee,
Player 4 <- Mo
Player 4 is out!

In the circle: [Player 1, Player 2, Player 3, Player 5, Player 6]
Player 5 <- Eenie,
Player 6 <- Meenie,
Player 1 <- Mainee,
Player 2 <- Mo
Player 2 is out!

In the circle: [Player 1, Player 3, Player 5, Player 6]
Player 3 <- Eenie,
Player 5 <- Meenie,
Player 6 <- Mainee,
Player 1 <- Mo
Player 1 is out!

In the circle: [Player 3, Player 5, Player 6]
Player 3 <- Eenie,
Player 5 <- Meenie,
Player 6 <- Mainee,
Player 3 <- Mo
Player 3 is out!

In the circle: [Player 5, Player 6]
Player 5 <- Eenie,
Player 6 <- Meenie,
Player 5 <- Mainee,
Player 6 <- Mo
Player 6 is out!

In the circle: [Player 5]
Player 5 wins!

See how good names can support comprehension of the program and can help verify its correctness?

Junilu Lacar
Sheriff
Posts: 11747
191
And in case you're curious about the Rhyme class, this is all it is:

This class is in the same source file as my public CircleGame class.  In my CircleGame class:

I've elided some of the details in that code but if you look at the choice of names, you might see that they really help clearly express what the code is doing. And that method actually is only 8 lines long.

Junilu Lacar
Sheriff
Posts: 11747
191
Alternatively, the Rhyme class can be written like this:

I like this version better because it makes a defensive copy of the array of the words array. I wasn't sure if Arrays.asList() returned an immutable list but a quick check of the API documentation shows that it doesn't since changes to the returned list "write through" to the array. That's generally not a good thing. This version is better encapsulated.

Junilu Lacar
Sheriff
Posts: 11747
191
The code I showed you demonstrates a couple of key concepts/practices for writing good programs:

1. Choose names that help clearly express and explain what the code is doing.

2. Break down the problem into smaller tasks.  Put the code for each small task into a method by itself and use a name for that method that clearly expresses what that task/method does or the idea that it represents.

Junilu Lacar
Sheriff
Posts: 11747
191
Testing for the case where # of Players = 7 and # words = 3, I realized that there was a bug in that code that I showed.

This was the problematic part:

That part of the code took me the longest time to tweak and it was the one line that I understood the least, even though I wrote it.  As I said before, code that you don't fully understand is more likely than not to have bugs in it and further testing proved that to be true yet again.

The red flag should have been the --whosNext parameter. In hindsight, I should have asked why I needed it to have a side-effect only to overwrite the same variable with the whereWeLeftOff() method's return value.

The fix was a small tweak to the whereWeLeftOff() method (3 lines of code) and removing the pre-decrement operator on whosNext in the parameter.

After that fix, the other test case passed:

In the circle: [Player 1, Player 2, Player 3, Player 4, Player 5, Player 6, Player 7]
Player 1 <- Bata
Player 2 <- Batuta
Player 3 <- Bulaga
Player 3 is out!

...

Next round starts with Player 4
In the circle: [Player 4]
Player 4 wins!

To make debugging the code a little easier, I had added a statement to show who would be the first person pointed to in the next round.

Junilu Lacar
Sheriff
Posts: 11747
191
That bug also demonstrates why/how comments are a code smell.  I strongly advocate preferring to write more expressive code instead of writing comments. When you use comments sparingly this way, the sections of code that you *do* write comments for tend to stand out more and attract attention. The commented code will usually be tricky, less understood, or something that whoever added the comment wasn't very comfortable with or confident about. That was the case for that line of code that I had commented.

Mitigating the commented code smell simply involves replacing comments with more expressive code. If after doing that you still feel a need for a comment, the comment should explain WHY you're doing something. The code itself should explain the WHAT and HOW that something is done.

Junilu Lacar
Sheriff
Posts: 11747
191
This is the final version of the play() method where I ended my ruthless refactoring efforts:

To me, this code told the story of what it was doing well enough that I felt like I could leave it alone for a while, come back to it after some time and still be able to understand what it was doing.

Junilu Lacar
Sheriff
Posts: 11747
191
To give you an idea of how I implemented that tightenUp() method:

My scheme is to put all the player names into the array that represents the circle of players.  Then I calculate who gets pointed last when you do one round of chanting the words in the rhyme by calling the playOneRound method. To tighten up the circle and essentially kick the last pointed player out of it, I just move everyone who comes after that lastPointed position down by one element in the array. Then I return an array that's one element shorter than before. So, if I were to write a JavaDoc comment for that method, it would be something like this:

I don't usually write JavaDoc comments for private methods but that's how I'd do it if it were required for some reason.

With this scheme, the winner always ends up in the first position (index == 0) of the array of players.

Campbell Ritchie
Marshal
Posts: 58449
178

Junilu Lacar wrote:And even when you say "it's always the same person who points" you don't say if that person is in the circle or not. If they're in the circle, what happens when they are out? Do they still keep doing the pointing? . . . .

Yes, They continue chanting the rhyme until only one person is left. You end up with whoever is chanting pointing across at two people, going back and forth until only one person is not eliminated.

It would make no difference to the order of elimination if different people chant the rhyme, as long as pointing starts one place after the person eliminated most recently.

Junilu Lacar
Sheriff
Posts: 11747
191
Campbell, the questions were largely meant to be rhetorical. I was just making the point that someone who wasn't all too familiar with the game from past experience might have questions about what the requirements really mean. Examples are great when they reinforce what the requirements say. However, when examples are necessary to avoid misunderstanding of the requirements, that to me means the requirements need some debugging. It's very similar to how comments can be an indicator of unclear and buggy code; examples can be symptoms of unclear and ambiguous requirements.

Junilu Lacar
Sheriff
Posts: 11747
191
Just when I thought I was done with ruthless refactoring...

I woke up this morning and realized that this code

really wanted to say this

With that change, I was able to reduce the whereWeLeftOff() method to what it was really supposed to be: 1 line of code to wrap the value around to the first position if IT's position goes past the last player's position.

Now I can confidently say that I fully understand what this code is doing and don't really need a comment for this section.

Junilu Lacar
Sheriff
Posts: 11747
191
Having well-factored code also allowed me to enhance the program to give it a quiet mode to facilitate automated testing. The enhancement took only a few minutes to code up:

I had one bug after making these changes. It was caused by a line that was changing the program state in a display statement (Beware of side-effects, bad coder!). When I added the guard clause, the display statement didn't execute so the state change side-effect didn't happen. Because the code in that method was so small, however, I was able to find the problem within a minute.

This exercise really brought home for me the importance of ruthless refactoring and how much time and grief it can save you in the long term.

Junilu Lacar
Sheriff
Posts: 11747
191
And one last 15-minute round of refactoring to 1) eliminate the stillStanding temporary variable, 2) promote the playersInCircle local variable to a field, and 3) extract method, the play() method is boiled down even more to this:

That refactorings significantly cleaned up the parameter clutter that was created by constantly passing around the local String[] playersInCircle and stillStanding variables between various methods.  The automated tests made refactoring a breeze because I could constantly check that I hadn't broken anything every time I made a small change.

Rancher
Posts: 2460
80
In Junilu's massive refactoring, beautiful as it is, there was one thing that bothered me, namely the olympiad was closed yesterday. The thoughts I had this evening concentrated on two aspects: we only need actually only two central methods, namely the plain old modulo function and a function that wraps the outcomes 0, 1, 2, ... n-1 of this modulo function to the outcomes n - 1, 0, 1, 2, ..., n-2, and the fact that I wanted the program to be finished within 45 minutes. enough to make a chance at the real olympiad. So I used the minimum refactoring, just enough to make clear what is happening; at least, that was what I aimed for.

Suppose the list of persons is 6 long, and that the rhyme is 3 words long, and that we start from index 0. The rawEndingIndex is simply (nrOfWords + startingIndex) % list.size();
In this case we get the outcome of 0. However, the real index that we should use is the wrapped index, 6 - 1 = 5. So, having found the rawIndex, we transform it to the leavingIndex, one of the methods I mentioned in the beginning. If the list of Persons is 6 long, and the number of words is 2, with a starting index of 3, we get: rawIndex = (2 + 3) % 6 = 5.  However, if you count it on papaer, you see that we actually need leavingIndex = 4.
I called this function 'wrappedIndex'.

As said, with all these thoughts, I managed to get this program running within 45 minutes, albeit that I had some experience in this area. That helped a lot. One remaining problem: back in 2001 we did not have generics, of course, so I imagne the candidates either used an array or a Vector, or something completely different than java, Basic maybe?

Here is my version

Junilu Lacar
Sheriff
Posts: 11747
191
Thanks for sharing your solution, Piet. I have to pop out to a neighbor's Halloween/Birthday Party but I'll try to give some feedback when I get back later. Have a great evening!