Logical testing numbers

Thread Starter

Sparky49

Joined Jul 16, 2011
833
Hi all,

I was wondering if you may be able to help me with determining if five numbers in a sequence are the same or not, using C. I've had a go, but it seems terribly long winded and was wondering if there may be another way to accomplish this.

I have represent my numbers with ABCDE, if they are the same then appropriate label is given the value 1. Then by using logic, I have written down all combinations of ABCDE where three are the same. But this is a lot of combinations.

Is there a simpler way to do this in C?

Many thanks for your time,

Sparky
 

MikeML

Joined Oct 2, 2009
5,444
Your problem statement is confusing.

Assume that n is any number, including A-E.
When matching the incoming sequence to the target, does this sequence AnCnE match ABCDE?
So there are 5*4 = 20 places where two ns can be substituted and still match?
And there are 5 place where one n can be substituted and still match?
 

Thread Starter

Sparky49

Joined Jul 16, 2011
833
Sorry for the confusing post.

This is for a game, where five shapes are randomly generated. If three and only three are the same, then the idea is that a player will press their button to score a point.

I am attempting to do this by generating five random numbers, which will each correspond to a shape. If three of the numbers are the same, then the program 'knows' that three shapes are the same. What I am trying to do is create a test to determine if three out of the five numbers are the same.

I hope that is clearer, if not just say and I'll be quick to reply. :)

Many thanks again, Sparky.
 

MikeML

Joined Oct 2, 2009
5,444
You didn't answer the questions I asked in post #2.

But I see that the random number generator can generate only five possible values.
 

Thread Starter

Sparky49

Joined Jul 16, 2011
833
I am sorry Mike, but I'm finding the questions a little confusing. I am unsure why we would want to match a AnCnE with ABCDE? Wouldn't there just be a comparison with ABCDE itself?
Using pseudo code:
Code:
int pass;
int A, B, C, D, E;

generate random int;
put into A;

generate random int;
put into B;

//and so on until random int in A B C D and E

if (only three out of A B C D E are the same)
{ pass=1}

else pass=0;
Sparky
 

GopherT

Joined Nov 23, 2012
8,009
@Sparky49
Use arrays. Load all of your 5 numbers into numArray

They will be accessible as numArray[0] to numArray[4]

Use two more counter variables, arrayIndex and zeroCounter

As psudo-code

Code:
Int ZeroCounter == 0 ; set to zero

For (int n=0, n < 4, n=n+1)
{
     Int  arrayIndex = n
     {
          For (arrayIndex, arrayIndex < 4, arrayIndex = arrayIndex+ 1)
          {
          If (numArray[arrayIndex] - numArray[arrayIndex + 1] == 0)
               {ZeroCounter++
               }
      }
}
If zeroCounter is greater than 2, you passed.
 

djsfantasi

Joined Apr 11, 2010
9,163
GopherT,

I read the problem statement, in post #3, to mean if a randomly generated sequence, out of a set of five different values, has three and exactly three of the same number, then it is a match. For example 1,2,1,4,1 is a match, as is 1,2,,3,3,3 (or using letters as the OP did, ABADA OR ABCCC). I didn't see a requirement that the letters be sequential. The first examples I cited wouldn't get identified in your algorithm.
Code:
{
void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);

int numarray[5]={1,3,1,1,5};  // array of numbers
int countarray[5]={0,0,0,0,0}; // array to count occurrences
int value=-1; //specific value
boolean Found=false; // self-explanatory


// for each number, count the number of occurrences in the set
for(value=0;value<5;value++) {
    for (int arrayindex=0; arrayindex<5; arrayindex++) {
    if (value == numarray[arrayindex]) {
       countarray[value]++;
       }
    }
}
// look through the count of values for 3 occurrences.
for(value=0;value<5;value++) {
//  Serial.println(countarray[value]);
    if (countarray[value]==3) {
       Serial.println("Found");
       Found=true;
       break;
       }
    }

// display result
if (Found) {
  Serial.print ("Value=");
  Serial.println(value);
  }

}


void loop() {
  // put your main code here, to run repeatedly:

}
}
Edit: I see my code suffers from identifying four numbers as a match. I originally did my counting and testing in two separate loops, which didn't suffer from this problem. Mea culpa.
Note: That issue has been fixed. This code has been compiled and tested on an Arduino.
 
Last edited:

Thread Starter

Sparky49

Joined Jul 16, 2011
833
Thanks guys, djsfantasi especially.

Makes sense to use arrays, rather than a bunch of logic - would make it easier to expand on if I wanted, say, six or ten shapes, or a different number to match.

Many thanks again,

Sparky
 

GopherT

Joined Nov 23, 2012
8,009
GopherT,

I read the problem statement, in post #3, to mean if a randomly generated sequence, out of a set of five different values, has three and exactly three of the same number, then it is a match. For example 1,2,1,4,1 is a match, as is 1,2,,3,3,3 (or using letters as the OP did, ABADA OR ABCCC). I didn't see a requirement that the letters be sequential. The first examples I cited wouldn't get identified in your algorithm.
If it is limited in that way, it was not my intention.
The two For loops were to test, for the five numbers,
A, B, C, D, E

A TEST
B, C, D, E (add 1 to ZeroCounter if any difference is zero (iE.they are equal)

Then, B test
C, D, E

Then C test
D, E

Then D test
E


By that time, all combinations are tested and. None thing requires consecutive numbers be equal.
 

darrough

Joined Jan 18, 2015
86
Here is a small function you might experiment with. This is just something to experiment with. I don't know if it could be made to work or not.

public static void main(String[] args) {

System.out.println("\n1 integer");
System.out.println(countUniqueIntegers(1));

System.out.println("\n2 integers");
System.out.println(countUniqueIntegers(1, 2));
System.out.println(countUniqueIntegers(1, 1));

System.out.println("\n3 integers");
System.out.println(countUniqueIntegers(1, 2, 3));
System.out.println(countUniqueIntegers(1, 3, 3));
System.out.println(countUniqueIntegers(3, 3, 3));

System.out.println("\n4 integers");
System.out.println(countUniqueIntegers(1, 2, 3, 4));
System.out.println(countUniqueIntegers(1, 2, 4, 4));
System.out.println(countUniqueIntegers(1, 4, 4, 4));
System.out.println(countUniqueIntegers(4, 4, 4, 4));​

System.out.println("\n5 integers");
System.out.println(countUniqueIntegers(1, 2, 3, 4, 5));
System.out.println(countUniqueIntegers(1, 2, 3, 5, 5));
System.out.println(countUniqueIntegers(1, 2, 5, 5, 5));
System.out.println(countUniqueIntegers(1, 5, 5, 5, 5));
System.out.println(countUniqueIntegers(5, 5, 5, 5, 5));​

return;​
}


public static int countUniqueIntegers(int ... integers) {

int count = 0;

for(int i0 = 0; i0 < integers.length; i0++) {
for(int i1 = 0; i1 < integers.length; i1++) {
if(integers[i0] - integers[i1] != 0) count = count + 1;​
}​
}

return count;​
}
 

kubeek

Joined Sep 20, 2005
5,795
It would be less computational intesive for large array if you do it like this:
The number of steps is N+M, instead of N*N, where N is the number of integers and M is the range of the numbers inputted.
Code:
N=5, M=5;
int[N] inputIntegers;
int[M] count;
int result;
for(int i=0;i<N;i++)
{
  count[inputIntegers[i]]++;
}
for(int i=0;i<M;i++)
  if(count[i]== 3)...;//match found
}
 
Last edited:

Thread Starter

Sparky49

Joined Jul 16, 2011
833
Thanks guys, I'll have a play with those examples tonight. May need a couple of modifications as this is for pic based C (my compiler doesn't like declaring variables in for loops, for example).

Many thanks again.
 

darrough

Joined Jan 18, 2015
86
Kubeek, that would work well, provided you you know the upper and lower bounds of the set in advance, and the upper bound were small enough and the lower bound >= 0.

If the set had other properties, like it was powers of two, or all prime numbers, there might be some way to write a function that returned the number unique integers in the set.

Actually though, the OP said "If three and only three are the same, then the idea is that a player will press their button to score a point.". In other words, it is not the number of unique numbers, but the number of duplicates.

For example
1 1 2 3 3 - 3 unique numbers but not 3 duplicates
1 1 1 2 2 - 2 unique numbers but 3 duplicates
1 1 1 2 3 - 3 unique numbers and 3 duplicates

This problem requires more thinking.
 

djsfantasi

Joined Apr 11, 2010
9,163
...This problem requires more thinking.
Ok, it may be inefficient, but is efficiency a requirement of the problem statement? Way back in the thread is a complete program, compiled and tested. It's only five numbers.

"Perfect is the enemy of good enough" - Eric Johns
 

darrough

Joined Jan 18, 2015
86
Try this. I think it works.

Code:
// true iff the input set has any value with exactly matchingDupCount duplicates.
public static boolean countDuplicates(int matchingDupCount, int ... numbers) {

int setsize = numbers.length;

// have to have at least three numbers to have three duplicates.if(setsize < 3) return false;

int[] counts = new int[setsize];
int[] values = new int[setsize];
int valndx = 0;

// iterate the input set, numbers
next_number: for(int i = 0; i < setsize; i++) {
// compare each number to numbers found on prior iterations.
for(int j = 0; j < valndx; j++) {

// if this number matches a prior number then increment the count for that number
 if(numbers[i] == values[j]) {
counts[j]++;
continue next_number;
}
}

// number matched any prior number would have continued to next_number.
// therefore this number is unique. add it to the list of numbers found
// during prior iterations.
values[valndx] = numbers[i];
counts[valndx] = 1;
valndx++;  
}

// valndx is now the number of unique numbers in the input set.

for(int i = 0; i < valndx; i++) {
if(counts[i] == matchingDupCount) return true;
 }

return false;
 }
Something is not working with indentation. I dont get it.
 
Last edited:

WBahn

Joined Mar 31, 2012
30,086
Ok, it may be inefficient, but is efficiency a requirement of the problem statement? Way back in the thread is a complete program, compiled and tested. It's only five numbers.

"Perfect is the enemy of good enough" - Eric Johns
But it seems that your approach is assuming that there are only five possible shapes, numbered 0 through 4. I don't see that this is a requirement of the problem statement, so what if there are 10 possible shapes and, from that pool, five a chosen randomly (with replacement)? So the values might be {2, 7, 6, 7, 7}.
 

darrough

Joined Jan 18, 2015
86
djsfantasi, your solution works as long as the set is always five numbers and the numbers in the set are all 1 2 3 4 or 5. It would not work, for example with -12, 292, 292, -12, 292, 19, 74.

The OP does say that there are 5 numbers in the sequence, but he never said that they are in the range 1 <= X <= 5.
 

djsfantasi

Joined Apr 11, 2010
9,163
Fair enough. Since the example given had five values, I did make that assumption. But the algorithm still holds and unless we are talking about a pool of values whose ordinality is orders of magnitude greater, it still is a "good enough" solution. IMHO
 

WBahn

Joined Mar 31, 2012
30,086
As with most things, what is "good enough" depends on the constraints. If this is in an extremely resource-starved micro, like some of the small PICs, then using an array to store the counts might be too expensive, while simply going through the loop and counting things might be more than fast enough. Consider the following:

Code:
#define SHAPES (5) // Sets the size of the array of integers.
#define TOKEN (-1)  // Set to a value that can be represented but that is NOT a valid shape number.
#define CRITERION (3) // How many of the of the same shape is required for a match.

int HitButton(int shapes[SHAPES])
{
   int index, j;
   int count, found;

   for (index = 0, found = 0; index < SHAPES; index++)
   {
      if (TOKEN != shapes[index])
      {
         for (j = index+1, count = 1; j < shapes; j++)
         {
            if (shapes[j] == shapes[index])
            {
               count++;
               shapes[j] = TOKEN;
            }
         }
         if (CRITERION == count) return 1;
      }
   }
   return 0;
}
NOTE: This code has NOT been compiled or tested.
 

RamaD

Joined Dec 4, 2009
328
GopherT's initial program itself can be modified to suit the clarified requirement.

Code:
for(i=0; i < 3; i++)
{
   zeroctr = 0;
   for(j=i+1; j < 5; j++)
   {
      if(NumArray[i] == NumArray[j]) ++zeroctr;
   }
   if(zeroctr == 3)
   {
      // 3 & Only 3 Matches occurred. Do whatever required.
   }
}
 
Top