#!/usr/bin/perl

use 5.040.3;
# use utf8;

my $DEBUG = 0;

my $version = 0.03;

if ( @ARGV < 3 || $ARGV[0] =~ /h/i) {
    say "Usage: $0 <numT> <numM> <opt>";
    say "";
    say "Round numbers...";
    say "";
    say "The algo search for numTotal - numMayor = numMinor\n";
    say "all the possible natural numbers additions that reach";
    say "numMinor with the <opt> options needed to simplify";
    say "<[repe|norepe|stairs|num]>, meaning";
    say "repetitions \/ not repetitions \/ a stair level of numbers";    
    say "default is stairs, not elevator \:\-\)\n";
    say "If opt is numeric n, then it uses it to show only combinations";
    say "up to n (a round number, from 2) terms to add up to numMinor";
    say "What to do with the rests, is a matter of discussion, but";
    say "this is version $version at most";
    exit -1;
}

say 1 if $DEBUG;

die "Error: not numeric" if (0+$ARGV[0] ne $ARGV[0]);
die "Not a round number" unless (int($ARGV[0]) == $ARGV[0]);
die "Error: not numeric" if (0+$ARGV[1] ne $ARGV[1]);
die "Not a round number" unless (int($ARGV[1]) == $ARGV[1]);

say 2 if $DEBUG;

my $opt;
unless ($ARGV[2] =~ /^repe/i ||
    $ARGV[2] =~ /no/i ||
    $ARGV[2] =~ /stair/i ||
    $ARGV[2] =~ /\d+/ ) {
	
	say "Something wrong about $ARGV[2]";
	say "Info: check options <[repe|norepe|stairs|num]>";
	exit -3;
	
	if ($ARGV[2] =~ /(\d+)/){
	    $opt = $1;
	    if (defined $opt){
		say "$opt seems not numeric", exit -4 if ($opt =~ /\D/);  
		say "$opt seems not to be a round number", exit -5 if (int($opt) != $opt);
		say "$opt must be more or equal than 2", exit -6 if ($opt < 2);
	    }
	}
    }


say 3 if $DEBUG;

my $numT = $ARGV[0];
my $numM = $ARGV[1];
($numT, $numM) = ($numM, $numT) if ($numT < $numM);
die "Error: a zero or negative number used" if $numM <= 0;
$opt //= $ARGV[2];

die "Error: options not defined" unless (defined $opt);

my $numprob = $numT - $numM;
die "Error: $numT - $numM = $numprob < 2" if $numprob < 2;

my ($new, $rest, $i, $j);

say 4 if $DEBUG;

### lun 09 feb 2026 00:25:43 CET

say "Empezó" if $DEBUG;

if ($opt =~ /repe/i && $opt !~ /no/i ){            # debería ser la opción más generosa en posibilidades
    
    $new = 0;
    say "Entró" if $DEBUG;
    
    while ( $new < $numprob ){
	
	$new++;

	print "Option: repetitions; For $new disadder: ";
	print "$numT - $numM = $numprob = ";
	$rest = $numprob;

        while ($rest > 0){
	    if ($rest > $new){
		$rest -= $new;
		print "\+$new ";
	    }else{
		while ($rest > 0){ 
		    $j=1;                                # se opta por lo largo
		    $rest -= $j;
		    print "\+$j " if $rest >= 0;
		    last if $rest == 0;
		}
	    }
	}
	print "\n";	
    }
    
}elsif ( $opt =~ /no/i ){
    
    say "no" if $DEBUG;

    my @list;
    for my $i (1 .. $numprob){
	push @list, $i;
    }
    @list = reverse @list;
    my %hh;
    my $string;
    while ( scalar(@list) ){

	my $c = $numprob ** 2;
	my $sum; 
	my $flag;
	my %h;
        while ($c > 0) {
	    $rest = $numprob;
	    $sum = 0;
	    $string = "";
	    $flag = 0;
	    for my $j (@list){ 
		if ($flag == 0) { $flag = $j; }
		next if $j > $flag;
		if (defined $h{$j}){
		    next if $h{$j} > $j;
		}
		$rest -= $j;
		if ($rest < 0){ 
		    $rest += $j;
		}else{
		    $string .= "\+$j ";
		    $sum += $j;
		    $h{$j}++;
		}
		last if $rest == 0;
	    }
	    if (++$hh{$string} == 1 && $sum == $numprob){
		print "Option: no repetitions; $numT - $numM = $numprob = ";
		say $string;
#		last;
	    }
	    $c--;
	}
	shift @list;
    }
        
}elsif ( $opt =~ /stair/i ) {        # default, in steps

    say "nop" if $DEBUG;
    
    $i = 1;
    print "Option: stairs (one possibility); For $i disadder: ";
    print "$numT - $numM = $numprob = ";
    $rest = $numprob;
    my $jant = 0;
	
    while ($rest > 0){                                       # escalera de subida
	if ($rest >= $i){
	    $rest -= $i;
	    print "\+$i ";
	    $i++;             # No repeticiones pero no escalera
	}else{
	    $jant = $rest;  # por si fuese resto de bajada
	    $j = 1;                                      # de subida, el resto	    
	    while ($rest > 0){ 
		$rest -= $j;
		if ($rest >= 0){
		    print "\+$j ";
		}else{
		    $rest += $j;        # deshacer
		}
		$j++;
		last if $rest == 0;
	    }
	}
    }
    say "";
    
}else{                       # $opt == number of principal terms
    
    say "nope" if $DEBUG;

    if ($opt > $numprob){
	say "Warning: $opt is higher than $numprob";
	$opt = $numprob;
    }
    if ($opt < 2){
	$opt = 2;
    }
    
    # mar 03 mar 2026 20:01:15 CET  Esto funcionaba y ahora no
    
    # partes principales
    my $ii = int($numprob / $opt); 
    if ($ii <= 0) { $ii = 1; }
    
    for (my $i = $opt; $i > 1; $i--){
	    
	$rest = $numprob;
	print "Option: parts = $opt; $numT - $numM = $numprob = ";	
	$rest -= $i * $ii;
	print ("\+$i " x $ii);
	
	if ($rest >= 1){
	    $j = int($rest / 2);     # partes secundarias, el resto
	    if ($j >= 1){
		$rest -= $j * 2;
		print ("\+$j " x 2);
	    }
	
	    if ($rest >= 1){
		my $k = int($rest/2);  # partes terciarias
		if ($k >= 1){
		    $rest -= $k * 2;
		    print ("\+$k " x 2);
		}
		
		if ($rest >= 1){                     # esto debe sobrar, puede que sea divisible
		    print "\+$rest ";
		}
	    }
	}    
	say "";
    }
    
}
     
# }else{
#    die "Error in $opt";
# }
    
exit 3;


__END__
  
Como primera versión as of lun 09 feb 2026 22:18:47 CET
  no todas las combinaciones se muestran. Sólo se intenta
  ayudar a problemas de reparto.
  Otros trabajo tengo publicado sobre el problema de las
  particiones de elementos + - indivisibles.
Básicamente se tienen w[1]..w[20] pesos o valores y hay que
  repartirlos en 3 partes que «pesen» lo mismo. Se puede
  hacer shuffle e ir probando. Ya digo, está arriba.


