Stroustrup PPP ch.5 : Bulls and Cows

Hi everyone!

I have no previous programming experience and am currently teaching myself C++ through the Stroustrup beginners book, and hit a bit of a snag.

One of the exercises in chapter 5 describes a game called Bulls & Cows: for those who haven't heard of it, the computer creates a vector of 4 random numbers between 0 and 9, and the user tries to guess the correct numbers in the correct sequence. A "bull" is a guess that's correct and in the right position in sequence, a "cow" is the correct number in the wrong position.

So I came up with something straightforward. Here's the original checking mechanism:

1
2
3
4
5
6
7
for (int i = 0; i < answer.size(); i++) {

     for (int j = 0; j < guess.size(); j++) {
	if (guess[i] == answer [j] && j == i) 		//correct num in right position
		bulls++;
        if (guess[i] == answer [j] && j != i)          //correct num in wrong position
                cows++;


I compiled it, ran it and it seemed absolutely fine after a few tries. I left it for a few days, but then I thought to myself: this chapter is all about errors and how to deal with it. I reread it, and the author suggests an attitude of "come on, let's break this code!" So I went back and had another look at it. I quickly found I had no provision for bad input or integers out of the range of 0-9, but that was quickly fixed. I was pretty satisfied with myself.

Then (the bane of my life!) against a test vector of 1 2 3 4 I tried 1 1 1 1. "You have 1 bull(s) and 3 cow(s)!". Oh, this can't be right, I thought. To cut a long story short, as I got more into the problem I divided the program into functions, so I could more easily focus on the area. I tried for days checking for the number of "bulls" within the loop, but finally realized it's better to do from without. So, my current version is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void check_guess (const std::vector<int>& guess, 
     const std::vector<int>& answer, int& bulls, int& cows)
{
	std::vector<int> bull_check;

	for (int i = 0; i < answer.size(); i++) {			//initial loop to fill
		for (int j = 0; j < 4; j++)				//a third vector checking
			if (guess[i] == answer [j] && i == j)		//number of correct bulls
				bull_check.push_back (answer[i]);
	}
	
	for (int i = 0; i < answer.size(); i++) {			//number of bulls and cows
		
		for (int j = 0; j < guess.size(); j++) {
			if (guess[i] == answer [j] && j == i) //correct num in right position
				bulls++;

			if (guess[i] == answer [j] && j != i){
				if (bull_check.size() == 0) cows++; //no bulls, it's a cow!
				else for (int k = 0; k < bull_check.size(); ++k){//right num, wrong position.
					if (guess [i] == bull_check [k]) break;
					cows++;
				}
			}
		}
	}
}


This gives better, but still in certain conditions problematic output (e.g., input of 9 8 9 8 on 0 9 8 7 gives 2 bulls, 2 cows). I guess my questions would be: is there a simple solution I'm completely missing? The nub of the problem seems to be lines 18-22 and I have a bad feeling I'm horrendously over-complicating things!
Last edited on
A "bull" is a guess that's correct and in the right position in sequence, a "cow" is the correct number in the wrong position.


Then (the bane of my life!) against a test vector of 1 2 3 4 I tried 1 1 1 1. "You have 1 bull(s) and 3 cow(s)!". Oh, this can't be right, I thought.


But, it is right. If a "cow" is a correct number in the wrong position, you have 3 1's that are "correct numbers in the wrong position" and one 1 that is the right number in the right position. 1 bull.


The following refers to your second block of code...
You don't set bulls and cows to 0 at any point. If the calling code fails to do that you're going to have some odd results.

In the first loop you store the values that are bulls in bull_check. Therefore, bull.size() is equal to the number of bulls you found. You don't take advantage of that (and I'm not sure why you're storing them in a vector anyway -- the logic in the second if chain seems confused.)

In short, you fixed a problem you didn't have and now you actually have a problem.




Topic archived. No new replies allowed.