Triangular Random Number Array

Hi, this is for a project I was working on and I've ran into some specific issues with random number and I kind of need help with it

Background: It is supposed to be a card game in while you would type a number in the command line and it would output an array (or pile) of random numbers adding up to the number inputted in the command line. This inital output would go through different iterations or suffles until it was in a sorted descending order of triangular numbers additives(like 1 2 3 or 1 2 3 4 5) if it sorted numbers don't add up to a triangular number it outputs that the number isn't triangular (The first few triangular numbers are 1, 3, 6, 10, 15, 21, 28, 36, 45...)

example output:

./a.out 10 
Number of Cards: 10
8 2
7 2 1
6 3 1
5 3 2
4 3 2 1 
Number of rounds: 5


1. It's going through an argc-argv command line (I don't know how to implement the conversion from string to int for the array though I'm pretty sure it has something to do with stoi).

2. It needs a sorter for the array (I sort of know how to do this but not like this) It is a function that confirms the last iteration or when the array is sorted in order.

3. It needs an isTriangular function but I may have that already just not sure how to implement it.

4. It could be in a vector or array but I just learned about vectors and haven't used them quite yet

Here's what I have so far (it's not quite complete but I'm quite stuck)

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <iostream>
#include <iomanip>
#include <cstdlib>
using namespace std;

/// function prototypes
// bool isTriangular();
void printArray(int randArray[]);


int main(int argc, char const *argv[])
{

    srand(time(nullptr));
    int randomInteger = rand();


    //argc check
    if (argc > 2)
    {
        cout << "Enter no more than 1 argument" << endl;
        exit(0);
    }

    cout << "argc: " << argc << endl;

    for (int i = 0; i < argc; i++)
    {
        string temp = argv[i];
        cout << "Arg " << i << ": " << temp << endl;
    }

    if (isTriangular(n)) {
        cout << "The number is a triangular number";
    }
    else {
        cout << "The number is NOT a triangular number";
    }

    return 0;
} /// main

void printArray(int randArray[], int count)
{
    cout << "Printing array elements:" << endl;
    for (int i = 0; i < count; i++)
    {
        cout << randArray[i] << "\n";
    }
} //Prints elements

bool isTriangular(int num)
{
    // Base case
    if (num < 0)
        return false;

    // A Triangular number must be sum of first n
    // natural numbers
    int sum = 0;
    for (int n = 1; sum <= num; n++)
    {
        sum = sum + n;
        if (sum == num)
            return true;
    }

    return false;
} ///Triangular num function 
Last edited on
Well, x is a triangular number if and only if 1+8x is a perfect square ... which is a bit quicker than whatever you are trying to do.

What's your rule for going from one line to the next? It certainly isn't a "shuffle".


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
#include <cmath>
using namespace std;


bool isTriangular( int n )
{
   int r = sqrt( 1.01 + 8 * n );    // deliberate .01 and int truncation
   return r * r == 1 + 8 * n;
}


int main( int argc, char *argv[] )
{
   int n = atoi( argv[1] );
   cout << n << ( isTriangular( n ) ? " is " : " is not " ) << "triangular\n";
}


test.exe 10
10 is triangular

Last edited on
argv[0] is always present and is the program name. Likewise, argc is always at least 1. If you provide a command line argument, then it will be argv[1] and argc will be 2.
So if you want multiple numbers to be specified on the command line, then you would loop form 1 to < argc.

lastchance on L15 shows one way to convert a numeric argument to a number. This is the simplest. If the string to convert cannot be converted(does not start with a digit), then it returns 0. std::stoi() can also be used eg int n = stoi(argv[1]); . However if no conversion can be made then this will raise an exception.

As well as lastchance's way of determining whether a number is triangular or not, the sum of n natural numbers is n(n + 1) / 2.
seeplus wrote:
As well as lastchance's way of determining whether a number is triangular or not, the sum of n natural numbers is n(n + 1) / 2.


It's not "as well as", it's the reason! Simply set n(n+1)/2=x and solve the resulting quadratic for n by the standard quadratic formula. The fact that 1+8x must be a perfect square is the requisite condition on the discriminant.

The OP simply hasn't given the full details of the problem. I presume that he/she is really trying
https://en.wikipedia.org/wiki/Bulgarian_solitaire
In which case he/she needs to indicate the condition to conclude that it is NOT a triangular number, given that in this case it will reach a limit cycle.
Last edited on
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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>
#include <set>
#include <cstdlib>
#include <ctime>
using namespace std;

using container = multiset<int>;


bool isTriangular( const container &S )
{
   if ( *S.begin() != 1 ) return false;
   int last = 0;
   for ( int e : S ) if ( e != (++last) ) return false;
   return true;
}


int main( int argc, char *argv[] )
{
   if ( argc != 2 )
   {
      cerr << "Correct usage is progname.exe n \n";
      exit(1);
   }
   int n = atoi( argv[1] );
   cout << n << '\n';
   
   srand( time( 0 ) );
   int round = 1;
   int r = 1 + rand() % ( n - 1 );
   container S{ n - r, r };
   
   bool ok = false;
   while ( round < 2 * n + 1 )         // upper bound (I think)
   {
      for ( auto it = S.rbegin(); it != S.rend(); it++ ) cout << *it << " ";
      cout << '\n';
      if ( isTriangular( S ) ) 
      {
          ok = true;
          break;
      }
      else
      {
          container temp;
          for ( int e : S ) if ( e != 1 ) temp.insert( e - 1 );
          temp.insert( S.size() );
          S = temp;
          round++;
      }   
   }
   
   if ( ok ) cout << "Triangular number in " << round << " rounds\n";
   else      cout << "Not a triangular number\n";
}



temp.exe 10
10
9 1 
8 2 
7 2 1 
6 3 1 
5 3 2 
4 3 2 1 
Triangular number in 6 rounds


temp.exe 11
11
9 2 
8 2 1 
7 3 1 
6 3 2 
5 3 2 1 
4 4 2 1 
4 3 3 1 
4 3 2 2 
4 3 2 1 1 
5 3 2 1 
4 4 2 1 
4 3 3 1 
4 3 2 2 
4 3 2 1 1 
5 3 2 1 
4 4 2 1 
4 3 3 1 
4 3 2 2 
4 3 2 1 1 
5 3 2 1 
4 4 2 1 
4 3 3 1 
Not a triangular number

Last edited on
The OP simply hasn't given the full details of the problem.


Here are the full details:

The Game:
You will start the game with an n value (default 45) for the number of cards. Divide the cards
into a random number of piles.

Playing the game (Assuming n = 45):
Each round, take one card from each pile and create a new pile. Repeat the process until you
have 9 piles of sizes 1, 2, 3, 4, 5, 6, 7, 8, and 9.
For example, if you start with 4 piles of 20, 15, 6, and 4, they would be transformed into
19, 14, 5, 3, and 4, etc.

Simulator:
The C++ program simulates the game. Your program must obtain the number of cards
(n) from the command line (see below). Assume the number of cards will never exceed 500. If
the number is not provided, then use 45 as the default value of n. If the user, enters more
than one value, print an error message and quit the program (return 0).
Start by producing a random number of piles. Make sure the total is n. Apply the steps
outlined above repeatedly until the final configuration is reached. At each step, print the
number of cards in each of the piles. The final configuration is reached when the number of
cards in the piles are in sequence: 1, 2, 3, 4, 5, 6, 7, etc. Display the number of
steps it took to reach the final configuration.

Functions:

Write a function (isTriangular) that returns true if a number n is a triangular
number, false otherwise.

Write a function to print all the elements of the array

Write a function that checks if the game is done by confirming the last sequence. You
may want to sort the values to make it easier to check. <--- This is the main problem

Thanks lastchance for the alternative function

Something worth noting:
What I've mentioned above the three (isTriangular) (printArray) (sequenceCheck) have to be functions

Also I just started to learn about vectors and arrays so my knowledge is limited
Last edited on
New code (still wip but getting there)
It still needs to print the values/iterations of each array. Can anyone help?

ex:

./a.exe 10
8 2
7 2 1
6 3 1
5 3 2
4 3 2 1
Number of iterations: 5


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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include <iostream>
#include <iomanip>
#include <cstdlib>
using namespace std;

/// function prototypes
bool isTriangular(int num);
void printArray(int array[], int count);
int randomNumber(int cards);

int main(int argc, char const *argv[])
{

    srand(time(nullptr));
    int n = atoi(argv[1]);
    int array[500];

    // argc check
    if (argc > 2)
    {
        cout << "Enter no more than 1 argument" << endl;
        exit(0);
    }

    randomNumber(n);

    printArray(array ,n);

    if (isTriangular(n))
    {
        cout << "The number is a triangular number";
    }
    else
    {
        cout << "The number is NOT a triangular number";
    }

    return 0;
} /// main

int randomNumber(int cards)
{
    int randomNumber = rand();

    randomNumber = randomNumber % cards + 1;

    return randomNumber;
}

void printArray(int array[], int count) ///Prints Array
{
    for (int i = 0; i < count; i++)
    {
        for (int j = i + 1; j < count; j++)
        {
            if (array[i] < array[j])
            {
                int temp = array[i];
                array[i] = array[j];
                array[j] = temp;
            }
        }
    }
} // Prints elements

bool isTriangular(int num)
{
    // Base case
    if (num < 0)
        return false;

    // A Triangular number must be sum of first n
    // natural numbers
    int sum = 0;
    for (int n = 1; sum <= num; n++)
    {
        sum = sum + n;
        if (sum == num)
            return true;
    }

    return false;
} /// Triangular num function 
L25 ?? the returned value isn't used??

printArray() - doesn't print but sorts the array?? If you want to sort, use std::sort()

isTriangular() - lastchance provided a non-loop version of this above:

1
2
3
4
5
bool isTriangular( int n )
{
   int r = sqrt( 1.01 + 8 * n );    // deliberate .01 and int truncation
   return r * r == 1 + 8 * n;
}


What's array[] used for? It starts with undefined values (as it's not initialised) which are then sorted??

I suggest that before you code much further, you first design the program. What is the algorithm you are going to use? How would this be done using paper/pen? What instructions would you give someone to do this without them knowing anything else?

Only once you have this clear, would I suggest you start coding from the design.

It's usually bad to start coding from the requirement without first having a program design.
What's array[] used for? It starts with undefined values


I'm not sure what to define it with and though lastchance's program is what I am aiming for the problem is I'm trying to use an array for the random numbers. I need to sort said random numbers in the same way as this output.

./a.exe 10
Number of cards: 10
9 1 
8 2 
7 2 1 
6 3 1 
5 3 2 
4 3 2 1 
Triangular number in 6 rounds


Highlighted in bold
Last edited on
Also the program cannot use

using container = multiset<int>;
or
#include <set>
Just plodding my way through step by step it ends up as the following ... and of course this can be refined but hardly worth it. Can even use <vector>s

There doesn't appear to be anything in the problem description that says anything about sorting the array. Also no square roots necessary unless you wanted to generate triangular numbers to test the program.

I can't be bothered with the extra few lines in converting and adding the check suggested so it can be run in the Terminal or whatever PC systems currently call it.

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include <iostream>
#include <ctime>
#include <iomanip>

int main()
{
    srand(time(nullptr));
    
    int no_of_cards{10};        // must be a triangular number
    int MAX_NO_CARDS = 500;
    int current_no_piles = 2;   // for arguments sake
    int MAX_NO_TRIALS = 200;    // for arguments sake
    
    // SETUP AVAILABLE PILES
    int* pile = new int[MAX_NO_CARDS]{}; // allow enough space for all cards
    
    // DISTRIBUTE CARDS IN FIRST PILES
    // CALCULATE PROPORTION
    double* proportion = new double[current_no_piles]{};
    int total{0};
    for(int i = 0; i < current_no_piles; i++)
    {
        proportion[i] = rand() % current_no_piles + 1;
        total += proportion[i];
    }
    
    for(int i = 0; i < current_no_piles; i++)
        proportion[i] /= total;
    
    // SETUP THE STARTING PILES
    int sum_of_piles{0};
    for(int i = 0; i < current_no_piles - 1; i++)
    {
        pile[i] = proportion[i] * no_of_cards;
        sum_of_piles += pile[i];
    }
    pile[current_no_piles - 1] = no_of_cards - sum_of_piles;
    
    for(int i = 0; i < current_no_piles; i++)
        std::cout <<  '#' << i << '=' << pile[i] << ' ';
    std::cout << '\n';
    
    // TAKE A CARD FROM EACH PILE
    for(int trial = 0; trial < MAX_NO_TRIALS; trial++)
    {
        int no_cards_taken{0};
        for(int i = 0; i < current_no_piles; i++)
        {
            if(pile[i] != 0)
            {
                pile[i]--;
                no_cards_taken++;
            }
        }
        pile[current_no_piles] = no_cards_taken;
        current_no_piles++;
        
        // CHECK FOR TRIANGULAR SEQUENCE
        int counter{1};
        bool triangular{true};
        
        for(int i = 0; i < MAX_NO_CARDS; i++)
        {
            if(pile[i] != 0)
            {
                if(pile[i] == counter)
                    counter++;
                else
                    triangular = false;
            }
        }
        
        std::cout << "Trial #:" << std::setw(3) << trial << ' ' << std::boolalpha << triangular;
        for(int i = 0; i < MAX_NO_CARDS - 1; i++)
        {
            if(pile[i] != 0)
                std::cout << ' ' << std::setw(2) <<  pile[i] << ' ';
        }
        
        if (triangular == true)
        {
            std::cout << " That's the one\n";
            return 0;
        }
        else
            std::cout << '\n';
    }
    
    return 0;
}

#0=6 #1=4 
Trial #:  0 false  5   3   2 
Trial #:  1 false  4   2   1   3 
Trial #:  2 false  3   1   2   4 
Trial #:  3 false  2   1   3   4 
Trial #:  4 true  1   2   3   4  That's the one
Program ended with exit code: 0

Last edited on
Topic archived. No new replies allowed.