#!/usr/bin/perl

@weights = @ARGV;

$let = 'a';
@allet = ();
%lowercode = ();
foreach (@weights) {
  $lowercode{$let} = $_;
  push @allet, $let;
  $let++;
}

sub randint {
  return int(rand($_[0]));
}

sub sum {
  my $ans = 0;
  foreach (@_) { $ans += $lowercode{$_}; }
  return $ans;
}

sub randperm {
  return @_ if ($#_ <= 0);
  my $t = pop @_;
  my @answer = randperm(@_);
  splice @answer, randint(scalar(@answer)), 0, $t;
  return @answer;
}

$range = 10;
@fodder = ();
for (-$range..$range) {
  next if ($_ == 0);
  push @fodder, $_;
}

sub balance2 {
  my @left = split " ", $_[0];
  my @right = split " ", $_[1];
  my $ls = sum(@left);
  my $rs = sum(@right);
  my $gcd = gcd2($ls, $rs);
  $ls /= $gcd;
  $rs /= $gcd;
  return if ($rs * $rs > $range * $range);
  return if ($ls * $ls > $range * $range);
  my @answer = ($rs."x", $_[0], (-$ls)."x", $_[1]);
  return join " ", @answer;
}

sub balance3 {
  my @one = split " ", $_[0];
  my @two = split " ", $_[1];
  my @three = split " ", $_[2];
  my $s1 = sum(@one);
  my $s2 = sum(@two);
  my $s3 = sum(@three);
  my @c1 = randperm(@fodder);
  my @c2 = randperm(@fodder);
  my @c3 = randperm(@fodder);
  for $a1 (@c1) {
    for $a2 (@c2) {
      next if ($a2 == $a1);
      for $a3 (@c3) {
        next if ($a3 == $a1);
        next if ($a3 == $a2);
        if ($a1 * $s1 + $a2 * $s2 + $a3 * $s3 == 0) {
          my @answer = ($a1."x", $_[0], $a2."x", $_[1], $a3."x", $_[2]);
          return join " ", @answer;
        }
      }
    }
  }
  return;
}

sub try2 {
    my @left = ();
    my @right = ();
    my $form = "";
    my $attempts = 0;
    my @leftans = ();
    my @rightans = ();
    while (!$form) {
      @left = ();
      @right = ();
      my @tweights = randperm(@_);
      push @left, pop @tweights;
      push @right, pop @tweights;
      while ($#tweights >= 0) {
        if (randint(2) == 0 or $#right == $#left) {
          push @left, pop @tweights;
        } else {
          push @right, pop @tweights;
        }
      }
      $attempts++;
#print "attempt split @left / @right\n";
      $form = balance2(join(" ", @left), join(" ", @right));
      @leftans = recurse(@left); if (@leftans == () and scalar(@left) >= 2) { $form = ""; next; }
      @rightans = recurse(@right); if (@rightans == () and scalar(@right) >= 2) { $form = ""; next; }
      last if ($attempts > 10);
    }
    return () if ($attempts > 10);
    return (@leftans, @rightans, $form);
}

sub try3 {
    my @one = ();
    my @two = ();
    my @three = ();
    my $form = "";
    my $attempts = 0;
    my @oneans = ();
    my @twoans = ();
    my @threeans = ();
    while (!$form) {
      @one = ();
      @two = ();
      @three = ();
      my @tweights = randperm(@_);
      push @one, pop @tweights;
      push @two, pop @tweights;
      push @three, pop @tweights;
      while ($#tweights >= 0) {
        if ($#one == $#two and $#two == $#three) {
          push @one, pop @tweights;
        } elsif ($#one == $#two and randint(2) == 0) {
          push @one, pop @tweights;
        } elsif (randint(3) == 0) {
          push @one, pop @tweights;
        } elsif (randint(2) == 0 or ($#two == $#three)) {
          push @two, pop @tweights;
        } else {
          push @three, pop @tweights;
        }
      }
#print "attempt split @one / @two / @three\n";
      $form = balance3(join(" ", @one), join(" ", @two), join(" ", @three));
      $attempts++;
      @oneans = recurse(@one); if (@oneans == () and scalar(@one) >= 2) { $form = ""; next; }
      @twoans = recurse(@two); if (@twoans == () and scalar(@two) >= 2) { $form = ""; next; }
      @threeans = recurse(@three); if (@threeans == () and scalar(@three) >= 2) { $form = ""; next; }
      last if ($attempts > 10);
    }
    return () if ($attempts > 10);
#print "returning @oneans / @twoans / @threeans / $form\n";
    return (@oneans, @twoans, @threeans, $form);
}

$level = 0;

sub recurse {
#print "recurse @_\n";
  my @weights = @_;
  if ($#weights == 0) {
    return ();
  } elsif ($#weights == 1) {
    my @result = balance2(@weights);
#print "recurse2 @_ result is @result\n";
    return @result;
  } else {
    my @result = ();
    while (@result == ()) {
      if (randint(4) < 1) {
        @result = try2(@weights);
      } else {
        @result = try3(@weights);
      }
    }
#print "recurse3 @_ result is @result\n";
    return @result;
  }
}

sub gcd2 {
  return gcd2($_[1], -$_[0]) if ($_[0] < 0);
  return $_[0] if ($_[1] == 0);
  return $_[1] if ($_[0] % $_[1] == 0);
  return gcd2($_[1], $_[0]) if ($_[0] < $_[1]);
  return gcd2($_[1], ($_[0] % $_[1]));
}

sub gcd {
print join " ", @_, "\n";
  return $_[0] if ($#_ == 0);
  return gcd2(@_) if ($#_ == 1);
  return gcd2(gcd(@_[0..int($#_/2)]), gcd(@_[(int($#_/2)+1)..$#_]));
}

# srand($ARGV[0]);

%code = ();
$start = "A";

@answer = recurse(@allet);
foreach (@answer) {
  @stuff = split " ", $_;
  foreach (@stuff) {
    if ($_ !~ /x/) {
      if (!exists $code{$_}) {
        $code{$_} = $start;
        $code{$_} = chr($lowercode{$_} + ord('A') - 1);
        $start++;
      }
      $_ = $code{$_};
    }
  }
  print join " ", @stuff;
  print "\n";
}
print "Sol: ";
@stuff = ();
foreach (keys %code) {
  push @stuff, "$code{$_} = $lowercode{$_}";
}
print join "; ", sort @stuff;
print "\n";
