Search code examples
clogiccombinations

Having a hard time creating a function that displays all different combinations of n numbers (0<n<10)by ascending order


I'm having difficulty finding the underlying logic for this. I know recursion would help however I don't know how to approach it. My difficulty lies when get dealing with sending/ printing the array on the base case. Everything I do I can only iterate the last digit and don't know how to go about the others.

If n is 2:

$>./a.out | cat -e

01, 02, 03, ..., 09, 12, ..., 79, 89$

If n is 3 things get harder:

012, 013, 014, ..., 123, 124, ..., 134, 135,... 234, ..., 789$

My code is far from working

#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>

void    ft_putchar(char c)
{
    write(1, &c, 1);
}

bool is_consecutive(int arr[], int n)
{
    int last_value = 9;
    if ( n <= 0 )
        return false;
    while ( --n ) {
        if ( arr[n] != last_value-- )
            return false;
    }
    return true;
}

void    ft_print_screen(int *t, int size)
{
        int i;
    
    i = 0;
        while (i < size)
    {
                ft_putchar(t[i] + '0');
        i++;
    }
        if (is_consecutive(t, size) != true)
        {
            ft_putchar(',');
            ft_putchar(' ');
        }
}

void    ft_print_combn(int n)
{
        int i;
        int tab[n];

        i = 0;
        if (n == 1)
                while (i < 10)
        {
                        ft_putchar(i + '0');
            i++;
        }
        while (i < n)
    {
                tab[i] = 0;
        i++;
    }
        while (tab[0] <= (10 - n) && n > 1)
        {
                ft_print_screen(tab, n);
                tab[n - 1]++;
                i = n;
                while (i && n > 1)
                {
                        i--;
                        if (tab[i] > 9)
                        {
                                tab[i - 1]++;
                                tab[i] = 0;
                        }
                }
        }
}

void main(int argc, char *argv[])
{
    int x = atoi(argv[1]);
    ft_print_combn(x);
}

Solution

  • Here's a solution that you should be able to adapt to your needs. The code is conditionalized to use either stdio or bare write calls. Just change the definition of USE_STDIO to #define USE_STDIO 0 to make it use bare write calls (or simply remove the conditionlization).

    Note that I used int rather than size_t for the string lengths, since they will never be larger than the character set size (i.e. 10), but you could of course use size_t if you prefer.

    #include <stdbool.h>
    #include <string.h>
    #include <unistd.h>
    #include <stdio.h>
    
    #define USE_STDIO   1
    
    void my_write(int len, char buf[len])
    {
    #if USE_STDIO
        printf("%.*s", len, buf);
    #else
        write(1, buf, len);
    #endif
    }
    
    void my_write_s(char *buf)
    {
        my_write(strlen(buf), buf);
    }
    
    void show(bool first, int len, char buf[len])
    {
        if (! first) {
            my_write_s(", ");
        }
        my_write(len, buf);
    }
    
    void end(void)
    {
        my_write_s("$\n");
    }
    
    void gen_combs2(bool first, char *buf, int off, int m, char chars[m], int n)
    {
        if (n == 0) {
            show(first, off, buf);
            return;
        }
    
        for (int i = 0; i < m + 1 - n ; i++) {
            buf[off] = chars[i];
            gen_combs2(first, buf, off + 1, m - i - 1, chars + i + 1, n - 1);
            first = false;
        }
    }
    
    void gen_combs(char *chars, int n)
    {
        int m = strlen(chars);
        char buf[n];
    
        gen_combs2(true, buf, 0, m, chars, n);
        end();
    }
    
    int main(void)
    {
        gen_combs("0123456789", 1);
        gen_combs("0123456789", 2);
        gen_combs("0123456789", 3);
    
        return 0;
    }