#!/usr/bin/perl

use Net::SMTP;
use Mail::Address;

$file = 'mboard';

open(BOARD, "<$file");

%long = ('Bk' => 'Black',
         'Bu' => 'Blue',
         'Br' => 'Brown',
         'Gd' => 'Gold',
         'Gr' => 'Green',
         'Rd' => 'Red');
foreach $short (keys %long) {
  $short{$long{$short}} = $short;
}

%lter = ('B' => 'Brush',
         'D' => 'Desert',
	 'H' => 'Hills',
	 'J' => 'Jungle',
	 'M' => 'Marsh',
	 'm' => 'Mountains',
	 'P' => 'Plains',
	 'S' => 'Swamp',
         'T' => 'Tower',
	 't' => 'Tundra',
	 'W' => 'Woods');
foreach $ster (keys %lter) {
  $ster{$lter{$ster}} = $ster;
}

%ttype = ('1' => 'P',
          '2' => 'W',
          '3' => 'B',
          '4' => 'H',
          '5' => 'J',
          '6' => 'P',
          '7' => 'D',
          '8' => 'M',
          '9' => 'H',
          '10' => 'B',
          '11' => 'W',
          '12' => 'J',
          '13' => 'M',
          '14' => 'S',
          '15' => 'P',
          '16' => 'W',
          '17' => 'B',
          '18' => 'H',
          '19' => 'J',
          '20' => 'P',
          '21' => 'D',
          '22' => 'M',
          '23' => 'H',
          '24' => 'B',
          '25' => 'W',
          '26' => 'J',
          '27' => 'M',
          '28' => 'S',
          '29' => 'P',
          '30' => 'W',
          '31' => 'B',
          '32' => 'H',
          '33' => 'J',
          '34' => 'P',
          '35' => 'D',
          '36' => 'M',
          '37' => 'H',
          '38' => 'B',
          '39' => 'W',
          '40' => 'J',
          '41' => 'M',
          '42' => 'S',
          '101' => 'P',
          '102' => 'B',
          '103' => 'M',
          '104' => 'J',
          '105' => 'P',
          '106' => 'B',
          '107' => 'D',
          '108' => 'M',
          '109' => 'B',
          '110' => 'P',
          '111' => 'S',
          '112' => 'M',
          '113' => 'B',
          '114' => 'J',
          '115' => 'P',
          '116' => 'B',
          '117' => 'M',
          '118' => 'D',
          '119' => 'P',
          '120' => 'B',
          '121' => 'S',
          '122' => 'M',
          '123' => 'B',
          '124' => 'P',
          '125' => 'J',
          '126' => 'M',
          '127' => 'B',
          '128' => 'D',
          '129' => 'P',
          '130' => 'B',
          '131' => 'M',
          '132' => 'S',
          '133' => 'P',
          '134' => 'B',
          '135' => 'J',
          '136' => 'M',
          '137' => 'B',
          '138' => 'P',
          '139' => 'D',
          '140' => 'M',
          '141' => 'B',
          '142' => 'S',
	  '100' => 'T',
	  '200' => 'T',
	  '300' => 'T',
	  '400' => 'T',
	  '500' => 'T',
	  '600' => 'T',
	  '1000' => 'm',
	  '2000' => 't',
	  '3000' => 'm',
	  '4000' => 't',
	  '5000' => 'm',
	  '6000' => 't');

%trow = ('1' => '6',
         '2' => '6',
         '3' => '7',
         '4' => '7',
         '5' => '7',
         '6' => '6',
         '7' => '6',
         '8' => '5',
         '9' => '5',
         '10' => '5',
         '11' => '5',
         '12' => '4',
         '13' => '4',
         '14' => '4',
         '15' => '4',
         '16' => '3',
         '17' => '3',
         '18' => '2',
         '19' => '2',
         '20' => '2',
         '21' => '3',
         '22' => '3',
         '23' => '3',
         '24' => '2',
         '25' => '2',
         '26' => '2',
         '27' => '3',
         '28' => '3',
         '29' => '4',
         '30' => '4',
         '31' => '4',
         '32' => '4',
         '33' => '5',
         '34' => '5',
         '35' => '5',
         '36' => '5',
         '37' => '6',
         '38' => '6',
         '39' => '7',
         '40' => '7',
         '41' => '7',
         '42' => '6',
         '101' => '8',
         '102' => '8',
         '103' => '8',
         '104' => '8',
         '105' => '8',
         '106' => '7',
         '107' => '7',
         '108' => '6',
         '109' => '6',
         '110' => '5',
         '111' => '5',
         '112' => '4',
         '113' => '4',
         '114' => '3',
         '115' => '3',
         '116' => '2',
         '117' => '2',
         '118' => '1',
         '119' => '1',
         '120' => '1',
         '121' => '1',
         '122' => '1',
         '123' => '1',
         '124' => '1',
         '125' => '1',
         '126' => '1',
         '127' => '2',
         '128' => '2',
         '129' => '3',
         '130' => '3',
         '131' => '4',
         '132' => '4',
         '133' => '5',
         '134' => '5',
         '135' => '6',
         '136' => '6',
         '137' => '7',
         '138' => '7',
         '139' => '8',
         '140' => '8',
         '141' => '8',
         '142' => '8',
	 '100' => '7',
	 '200' => '6',
	 '300' => '3',
	 '400' => '2',
	 '500' => '3',
	 '600' => '6',
	 '1000' => '5',
	 '2000' => '5',
	 '3000' => '4',
	 '4000' => '4',
	 '5000' => '4',
	 '6000' => '5');

%tcol = ('1' => '8',
         '2' => '9',
         '3' => '9',
         '4' => '10',
         '5' => '11',
         '6' => '11',
         '7' => '10',
         '8' => '10',
         '9' => '11',
         '10' => '12',
         '11' => '13',
         '12' => '13',
         '13' => '12',
         '14' => '11',
         '15' => '10',
         '16' => '10',
         '17' => '11',
         '18' => '11',
         '19' => '10',
         '20' => '9',
         '21' => '9',
         '22' => '8',
         '23' => '7',
         '24' => '7',
         '25' => '6',
         '26' => '5',
         '27' => '5',
         '28' => '6',
         '29' => '6',
         '30' => '5',
         '31' => '4',
         '32' => '3',
         '33' => '3',
         '34' => '4',
         '35' => '5',
         '36' => '6',
         '37' => '6',
         '38' => '5',
         '39' => '5',
         '40' => '6',
         '41' => '7',
         '42' => '7',
         '101' => '8',
         '102' => '9',
         '103' => '10',
         '104' => '11',
         '105' => '12',
         '106' => '12',
         '107' => '13',
         '108' => '13',
         '109' => '14',
         '110' => '14',
         '111' => '15',
         '112' => '15',
         '113' => '14',
         '114' => '14',
         '115' => '13',
         '116' => '13',
         '117' => '12',
         '118' => '12',
         '119' => '11',
         '120' => '10',
         '121' => '9',
         '122' => '8',
         '123' => '7',
         '124' => '6',
         '125' => '5',
         '126' => '4',
         '127' => '4',
         '128' => '3',
         '129' => '3',
         '130' => '2',
         '131' => '2',
         '132' => '1',
         '133' => '1',
         '134' => '2',
         '135' => '2',
         '136' => '3',
         '137' => '3',
         '138' => '4',
         '139' => '4',
         '140' => '5',
         '141' => '6',
         '142' => '7',
	 '100' => '8',
	 '200' => '12',
	 '300' => '12',
	 '400' => '8',
	 '500' => '4',
	 '600' => '4',
	 '1000' => '8',
	 '2000' => '9',
	 '3000' => '9',
	 '4000' => '8',
	 '5000' => '7',
	 '6000' => '7');

%tcrn = ('1' => 'c',
         '2' => 'c',
         '3' => 'c',
         '4' => 'c',
         '5' => 'l',
         '6' => 'r',
         '7' => 'l',
         '8' => 'r',
         '9' => 'l',
         '10' => 'r',
         '11' => 'l',
         '12' => 'l',
         '13' => 'r',
         '14' => 'l',
         '15' => 'r',
         '16' => 'l',
         '17' => 'r',
         '18' => 'l',
         '19' => 'c',
         '20' => 'c',
         '21' => 'c',
         '22' => 'c',
         '23' => 'c',
         '24' => 'c',
         '25' => 'c',
         '26' => 'r',
         '27' => 'l',
         '28' => 'r',
         '29' => 'l',
         '30' => 'r',
         '31' => 'l',
         '32' => 'r',
         '33' => 'r',
         '34' => 'l',
         '35' => 'r',
         '36' => 'l',
         '37' => 'r',
         '38' => 'l',
         '39' => 'r',
         '40' => 'c',
         '41' => 'c',
         '42' => 'c',
         '101' => 'c',
         '102' => 'c',
         '103' => 'c',
         '104' => 'c',
         '105' => 'l',
         '106' => 'r',
         '107' => 'l',
         '108' => 'r',
         '109' => 'l',
         '110' => 'r',
         '111' => 'l',
         '112' => 'l',
         '113' => 'r',
         '114' => 'l',
         '115' => 'r',
         '116' => 'l',
         '117' => 'r',
         '118' => 'l',
         '119' => 'c',
         '120' => 'c',
         '121' => 'c',
         '122' => 'c',
         '123' => 'c',
         '124' => 'c',
         '125' => 'c',
         '126' => 'r',
         '127' => 'l',
         '128' => 'r',
         '129' => 'l',
         '130' => 'r',
         '131' => 'l',
         '132' => 'r',
         '133' => 'r',
         '134' => 'l',
         '135' => 'r',
         '136' => 'l',
         '137' => 'r',
         '138' => 'l',
         '139' => 'r',
         '140' => 'c',
         '141' => 'c',
         '142' => 'c',
	 '100' => 'c',
	 '200' => 'l',
	 '300' => 'l',
	 '400' => 'c',
	 '500' => 'r',
	 '600' => 'r',
	 '1000' => 'c',
	 '2000' => 'l',
	 '3000' => 'l',
	 '4000' => 'c',
	 '5000' => 'r',
	 '6000' => 'r');

@map = (
'                     ______    ______    ______    ______',
'                  __/      \__/      \__/      \__/      \__',
'                 /  \      / P\      / M\      / B\      /  \\',
'                /    \ 125/ 124\ 123/ 122\ 121/ 120\ 119/    \\',
'               /   126\_J/      \_B/      \_S/      \_P/118   \\',
'               \_____M/  \______/  \______/  \______/  \D_____/',
'             __/B     \__/      \__/      \__/      \__/     M\__',
'            /  \127   /  \      / B\      / P\      /  \   117/  \\',
'           /    \    /    \  25/  24\ 400/  20\  19/    \    /    \\',
'          /   128\__/    26\_W/      \_T/      \_J/18    \__/116   \\',
'          \_____D/  \_____J/  \______/  \______/  \H_____/  \B_____/',
'        __/P     \__/M     \__/      \__/      \__/     B\__/     P\__',
'       /  \129   /  \27    /  \      / M\      /  \    17/  \   115/  \\',
'      /    \    /    \    /    \  23/  22\  21/    \    /    \    /    \\',
'     /   130\__/   500\__/    28\_H/      \_D/16    \__/300   \__/114   \\',
'     \_____B/  \_____T/  \_____S/  \______/  \W_____/  \T_____/  \J_____/',
'   __/M     \__/B     \__/P     \__/      \__/     P\__/     M\__/     B\__',
'  /  \131   /  \31    /  \29    /  \      /  \    15/  \    13/  \   113/  \\',
' /    \    /    \    /    \    /    \4000/    \    /    \    /    \    /    \\',
'/   132\__/    32\__/    30\__/  5000\_t/3000  \__/14    \__/12    \__/112   \\',
'\_____S/  \_____H/  \_____W/  \_____m/  \m_____/  \S_____/  \J_____/  \M_____/',
'/     P\__/     J\__/     D\__/     t\__/t     \__/H     \__/W     \__/S     \\',
'\   133/  \    33/  \    35/  \  6000/ m\2000  /  \9     /  \11    /  \111   /',
' \    /    \    /    \    /    \    /1000\    /    \    /    \    /    \    /',
'  \__/134   \__/34    \__/36    \__/      \__/     8\__/    10\__/   110\__/',
'     \B_____/  \P_____/  \M_____/  \______/  \_____M/  \_____B/  \_____P/',
'     /     J\__/     T\__/     H\__/      \__/D     \__/T     \__/B     \\',
'     \   135/  \   600/  \    37/ S\      / W\7     /  \200   /  \109   /',
'      \    /    \    /    \    /  42\   1/   2\    /    \    /    \    /',
'       \__/136   \__/38    \__/      \_P/      \__/     6\__/   108\__/',
'B Brush   \M_____/  \B_____/  \______/  \______/  \_____P/  \_____M/',
'D Desert  /     B\__/     W\__/      \__/      \__/J     \__/D     \\',
'H Hills   \   137/  \    39/ J\      / T\      / H\5     /  \107   /',
'J Jungle   \    /    \    /  40\  41/ 100\   3/   4\    /    \    /',
'M Marsh     \__/138   \__/      \_M/      \_B/      \__/   106\__/',
'm Mountains    \P_____/  \______/  \______/  \______/  \_____B/',
'P Plains       /     D\__/      \__/      \__/      \__/P     \\',
'S Swamp        \   139/ M\      / S\      / B\      / J\105   /',
'T Tower         \    / 140\ 141/ 142\ 101/ 102\ 103/ 104\    /',
't Tundra         \__/      \_B/      \_P/      \_M/      \__/',
'W Woods             \______/  \______/  \______/  \______/');

@board = ();
while (<BOARD>) {
  chop $_;
  push @board, $_;
  if (/^UNITS \*/) {
    die "Duplicate UNITS section.\n" if defined($units);
    $units = $#board;
    die "UNITS section out of order\n" if $units <= 0;
  }
  elsif (/^ALL LEGIONS \*/) {
    die "Duplicate ALL section.\n" if defined($all);
    $all = $#board;
    die "ALL section out of order\n" if $all <= $units;
  }
  elsif (/^YOUR LEGIONS \*/) {
    die "Duplicate YOUR section.\n" if defined($your);
    $your = $#board;
    die "YOUR section out of order\n" if $your <= $all;
  }
  elsif (/^MAP \*/) {
    die "Duplicate MAP section.\n" if defined($map);
    $map = $#board;
    die "MAP section out of order\n" if $map <= $your;
  }
  elsif (/^PLAYERS \*/) {
    die "Duplicate PLAYERS section.\n" if defined($players);
    $players = $#board;
    die "PLAYERS section out of order\n" if $players <= $map;
  }
  elsif (/^GMS \*/) {
    die "Duplicate GMS section.\n" if defined($gms);
    $gms = $#board;
    die "GMS section out of order\n" if $gms <= $players;
  }
  elsif (/^OBSERVERS \*/) {
    die "Duplicate OBSERVERS section.\n" if defined($obs);
    $obs = $#board;
    die "OBSERVERS section out of order\n" if $obs <= $gms;
  }
  elsif (/^END \*/) {
    die "Duplicate END section.\n" if defined($end);
    $end = $#board;
    die "END section out of order\n" if $end <= $obs;
  }
}
close(BOARD);
die "UNITS section missing.\n" unless defined($units);
die "ALL section missing.\n" unless defined($all);
die "YOUR section missing.\n" unless defined($your);
die "MAP section missing.\n" unless defined($map);
die "PLAYERS section missing.\n" unless defined($players);
die "GMS section missing.\n" unless defined($gms);
die "OBSERVERS section missing.\n" unless defined($obs);
die "END section missing.\n" unless defined($end);

for ($pos = $players + 1; $pos < $gms; $pos++) {
  $line = $board[$pos];
  next if $line =~ /^\s*$/;
  die "Bad player line: $line\n" unless $line =~ /^\s*(\d)00\s+([A-Za-z]+)\s*(.*)$/;
  $color = ucfirst(lc($2));
  die "Bad player color: $2\n" unless defined($short{$color});
  die "Bad tower number: ${1}00\n" unless $1 >= 1 && $1 <= 6;
  die "Duplicate tower number: ${1}00\n" if defined($color[$1]);
  $color[$1] = $color;
  $color{$color} = $1;
  $email{$color} = $3;
  $email{$color} =~ s/\s+/ /g;
}

@gms = ();
for ($pos = $gms + 1; $pos < $obs; $pos++) {
  $line = $board[$pos];
  next if $line =~ /^\s*$/;
  $line =~ s/^\s*//;
  $line =~ s/\s*$//;
  $line =~ s/\s+/ /g;
  push @gms, $line;
}
die "There must be at least one GM.\n" unless scalar(@gms) > 0;

@obs = ();
for ($pos = $obs + 1; $pos < $end; $pos++) {
  $line = $board[$pos];
  next if $line =~ /^\s*$/;
  $line =~ s/^\s*//;
  $line =~ s/\s*$//;
  $line =~ s/\s+/ /g;
  push @obs, $line;
}

$types = $board[$units+1];
@types = $types =~ /[a-zA-Z][a-zA-Z][a-zA-Z]/g;
for ($pos = $units + 2; $pos < $map; $pos++) {
  last if $board[$pos] =~ /^Killed\s/i;
}
$killed = $board[$pos];
die "Bad Killed line\n" unless $killed =~ /^Killed\s/i;
@killed = $killed =~ /-|[0-9]+/g;
die "Killed line incorrect\n" if $#killed != $#types;
$avail = $board[$pos+1];
die "Bad Avail line\n" unless $avail =~ /^Avail\s/i;
@avail = $avail =~ /-|[0-9]+/g;
die "Avail line incorrect\n" if $#avail != $#types;
$total = $board[$pos+2];
die "Bad Total line\n" unless $total =~ /^Total\s/i;
@total = $total =~ /-|[0-9]+/g;
die "Total line incorrect\n" if $#total != $#types;
for ($char = 0; $char <= $#types; $char++) {
  $types[$char] = ucfirst(lc($types[$char]));
  $killed{$types[$char]} = $killed[$char];
  $avail{$types[$char]} = $avail[$char];
  $total{$types[$char]} = $total[$char];
}
$total{'Ttn'} = 6;

@active = ();
$old = '';
$last = 0;
$color{$old} = 7;
for ($pos = $your + 1; $pos < $players; $pos++) {
  $line = $board[$pos];
  next unless $line =~ /^([A-Za-z][A-Za-z])(\d\d)\s+([A-Za-z])(\d+)\s+/;
  $color = $long{ucfirst(lc($1))};
  die "Bad color code $1 used for a legion name.\n" unless defined $color;
  die "No player is using color: $color\n" unless defined $color{$color};
  die "Legion $1$2 not in color order.\n" if $color{$old} < $color{$color};
  die "Terrain is wrong for location for legion $1$2.\n"
    unless $ttype{$4} eq $3;
  if ($color ne $old) {
    $old = $color;
    $last = 0;
    push @active, $color;
    $count{$color} = {};
    $legion{$color} = [];
    $size{$color} = [];
    $loc{$color} = [];
  }
  die "Legion $1$2 out of order\n" if $last >= $2;
  $legion = $2;
  $loc = $4;
  push @{$loc{$color}}, $loc;
  @char = $' =~ /\S+/g;
  push @{$legion{$color}}, $legion;
  push @{$size{$color}}, scalar(@char);
  die "Empty legion $short{$color}$legion.\n" unless scalar(@char) > 0;
  foreach $char (@char) {
    $char = ucfirst(lc($char));
    die "Bad character $char in legion $short{$color}$legion.\n"
      unless defined $total{$char};
    ${$count{$color}}{$char}++;
  }
  $locn{$loc} = [] unless defined $locn{$loc};
  $locs{$loc} = [] unless defined $locs{$loc};
  push @{$locn{$loc}}, "$short{$color}$legion";
  push @{$locs{$loc}}, scalar(@char);
}

foreach $color (@active) {
  die "$color does not have exactly one Ttn.\n"
    unless ${$count{$color}}{'Ttn'} == 1;
}

foreach $char (@types) {
  $count = $killed{$char} + $avail{$char};
  foreach $color (@active) {
    $count += ${$count{$color}}{$char};
  }
  die "Incorrect count of ${char}'s.\n" unless $count == $total{$char};
}

foreach $loc (keys %locn) {
  $x = 5 * $tcol{$loc} - 3;
  $y = 5 * $trow{$loc} - 2;
  $z = ($tcol{$loc} + $trow{$loc}) % 2;
  if (scalar(@{$locn{$loc}}) == 1) {
    $y1 = $y;
    $y1 += $z * 2 - 1 if $tcrn{$loc} eq 'c';
    substr($map[$y1], $x, 4) = ${$locn{$loc}}[0];
    $y2 = $y + 4 * $z - 2;
    $x2 = $x + ($tcrn{$loc} eq 'l');
    substr($map[$y2], $x2, 3) = "(${$locs{$loc}}[0])";
  }
  elsif (scalar(@{$locn{$loc}}) == 2) {
    $y -= 2 - 2 * $z;
    substr($map[$y], $x, 4) = ${$locn{$loc}}[0];
    substr($map[$y + 1], $x - 1, 6) = " ${$locs{$loc}}[0]/${$locs{$loc}}[1]  ";
    substr($map[$y + 2], $x, 4) = ${$locn{$loc}}[1];
  }
  elsif (scalar(@{$locn{$loc}}) == 3) {
    $y -= 2 - 2 * $z;
    substr($map[$y], $x, 4) = ${$locn{$loc}}[0];
    substr($map[$y + 1], $x - 1, 6) = " ${$locn{$loc}}[1] ";
    substr($map[$y + 2], $x, 4) = ${$locn{$loc}}[2];
  }
  else {
    $x = scalar(@{$locn{$loc}});
    die "$x stacks at $loc.\n";
  }
}

$gmt = gmtime;
@gmt = split(/ +/,$gmt);
$date = "Date: $gmt[0], $gmt[2] $gmt[1] $gmt[4] $gmt[3] -0000 (GMT)\n";

$mail = Net::SMTP->new;
die "Unable to connect to SMTP server\n" unless $mail;
die "Unable to open new file ${file}.new.\n" unless open(BOARD,">${file}.new");
$mail->mail((Mail::Address->parse($gms[0]))[0]->address);
foreach $m (@gms) {
  foreach $addr (Mail::Address->parse($m)) {
    $mail->to($addr->address);
  }
}
$mail->data;
$mail->datasend("From: $gms[0]\n");
$mail->datasend("To: ", join(",\n ", @gms), "\n");
$mail->datasend($date);
$mail->datasend("Subject: $board[0]\n");
print BOARD "$board[0]\n";
$mail->datasend("\n");
foreach $line (@board[1..$units+1]) {
  $mail->datasend("$line\n");
  print BOARD "$line\n";
}
foreach $color (@active) {
  $mail->datasend(sprintf('%-7s', $color));
  printf BOARD '%-7s', $color;
  foreach $char (@types) {
    if (${$count{$color}}{$char} != 0) {
      $mail->datasend(sprintf('%3d', ${$count{$color}}{$char}));
      printf BOARD '%3d', ${$count{$color}}{$char};
    }
    else {
      $mail->datasend('  -');
      print BOARD '  -';
    }
  }
  $mail->datasend("\n");
  print BOARD "\n";
}
$mail->datasend('Killed ');
print BOARD 'Killed ';
foreach $char (@types) {
  if ($killed{$char} != 0) {
    $mail->datasend(sprintf('%3d', $killed{$char}));
    printf BOARD '%3d', $killed{$char};
  }
  else {
    $mail->datasend('  -');
    print BOARD '  -';
  }
}
$mail->datasend("\n");
print BOARD "\n";
$mail->datasend('Avail  ');
print BOARD 'Avail  ';
foreach $char (@types) {
  if ($avail{$char} != 0) {
    $mail->datasend(sprintf('%3d', $avail{$char}));
    printf BOARD '%3d', $avail{$char};
  }
  else {
    $mail->datasend('  -');
    print BOARD '  -';
  }
}
$mail->datasend("\n");
print BOARD "\n";
$mail->datasend('Total  ');
print BOARD 'Total  ';
foreach $char (@types) {
  if ($total{$char} != 0) {
    $mail->datasend(sprintf('%3d', $total{$char}));
    printf BOARD '%3d', $total{$char};
  }
  else {
    $mail->datasend('  -');
    print BOARD '  -';
  }
}
$mail->datasend("\n\n$board[$all]\n");
print BOARD "\n\n$board[$all]\n";
$most = 0;
@line = ();
foreach $color (@active) {
  $most = scalar(@{$legion{$color}}) if $most < scalar(@{$legion{$color}});
  push @line, "#$short{$color} Sz  Loc";
}
$mail->datasend(join(' |', @line), "\n");
print BOARD join(' |', @line), "\n";
for ($legion = 0; $legion < $most; $legion++) {
  @line = ();
  foreach $color (@active) {
    if (defined(${$legion{$color}}[$legion])) {
      push @line, sprintf(' %2d %2d %4d', ${$legion{$color}}[$legion],
	${$size{$color}}[$legion], ${$loc{$color}}[$legion]);
    }
    else {
      push @line, '           ';
    }
  }
  $mail->datasend(join(' |', @line), "\n");
  print BOARD join(' |', @line), "\n";
}
$mail->datasend("\n");
print BOARD "\n";
foreach $line (@board[$your..$map]) {
  $mail->datasend("$line\n");
  print BOARD "$line\n";
}
foreach $line (@map) {
  $mail->datasend("$line\n");
  print BOARD "$line\n";
}
$mail->datasend("$line\n");
print BOARD "$line\n";
foreach $line (@board[$players..$end]) {
  $mail->datasend("$line\n");
  print BOARD "$line\n";
}
$mail->dataend;
close(BOARD);
die "Unable to rename old file to ${file}.old\n"
  unless rename $file, "${file}.old";
die "Unable to rename new file to ${file}\n"
  unless rename "${file}.new", $file;

if (scalar(@obs) > 0) {
  $mail->mail((Mail::Address->parse($gms[0]))[0]->address);
  foreach $m (@obs) {
    foreach $addr (Mail::Address->parse($m)) {
      $mail->to($addr->address);
    }
  }
  $mail->data;
  $mail->datasend("From: $gms[0]\n");
  $mail->datasend("To: ", join(",\n ", @obs), "\n");
  $mail->datasend($date);
  $mail->datasend("Subject: $board[0]\n");
  $mail->datasend("\n");
  foreach $line (@board[1..$units+1]) {
    $mail->datasend("$line\n");
  }
  foreach $color (@active) {
    $mail->datasend(sprintf('%-7s', $color));
    foreach $char (@types) {
      if (${$count{$color}}{$char} != 0) {
        $mail->datasend(sprintf('%3d', ${$count{$color}}{$char}));
      }
      else {
        $mail->datasend('  -');
      }
    }
    $mail->datasend("\n");
  }
  $mail->datasend('Killed ');
  foreach $char (@types) {
    if ($killed{$char} != 0) {
      $mail->datasend(sprintf('%3d', $killed{$char}));
    }
    else {
      $mail->datasend('  -');
    }
  }
  $mail->datasend("\n");
  $mail->datasend('Avail  ');
  foreach $char (@types) {
    if ($avail{$char} != 0) {
      $mail->datasend(sprintf('%3d', $avail{$char}));
    }
    else {
      $mail->datasend('  -');
    }
  }
  $mail->datasend("\n");
  $mail->datasend('total  ');
  foreach $char (@types) {
    if ($total{$char} != 0) {
      $mail->datasend(sprintf('%3d', $total{$char}));
    }
    else {
      $mail->datasend('  -');
    }
  }
  $mail->datasend("\n\n$board[$all]\n");
  $most = 0;
  @line = ();
  foreach $color (@active) {
    $most = scalar(@{$legion{$color}}) if $most < scalar(@{$legion{$color}});
    push @line, "#$short{$color} Sz  Loc";
  }
  $mail->datasend(join(' |', @line), "\n");
  for ($legion = 0; $legion < $most; $legion++) {
    @line = ();
    foreach $color (@active) {
      if (defined(${$legion{$color}}[$legion])) {
        push @line, sprintf(' %2d %2d %4d', ${$legion{$color}}[$legion],
  	${$size{$color}}[$legion], ${$loc{$color}}[$legion]);
      }
      else {
        push @line, '           ';
      }
    }
    $mail->datasend(join(' |', @line), "\n");
  }
  $mail->datasend("\n$board[$map]\n");
  foreach $line (@map) {
    $mail->datasend("$line\n");
  }
  $mail->datasend("\n");
  foreach $line (@board[$players..$end]) {
    $mail->datasend("$line\n");
  }
  $mail->dataend;
}

foreach $active (@active) {
  $mail->mail((Mail::Address->parse($gms[0]))[0]->address);
  foreach $addr (Mail::Address->parse($email{$active})) {
    $mail->to($addr->address);
  }
  $mail->data;
  $mail->datasend("From: $gms[0]\n");
  $mail->datasend("To: $email{$active}\n");
  $mail->datasend($date);
  $mail->datasend("Subject: $board[0]\n");
  $mail->datasend("\n");
  foreach $line (@board[1..$units+1]) {
    $mail->datasend("$line\n");
  }
  foreach $color (@active) {
    $mail->datasend(sprintf('%-7s', $color));
    foreach $char (@types) {
      if (${$count{$color}}{$char} != 0) {
        $mail->datasend(sprintf('%3d', ${$count{$color}}{$char}));
      }
      else {
        $mail->datasend('  -');
      }
    }
    $mail->datasend("\n");
  }
  $mail->datasend('Killed ');
  foreach $char (@types) {
    if ($killed{$char} != 0) {
      $mail->datasend(sprintf('%3d', $killed{$char}));
    }
    else {
      $mail->datasend('  -');
    }
  }
  $mail->datasend("\n");
  $mail->datasend('Avail  ');
  foreach $char (@types) {
    if ($avail{$char} != 0) {
      $mail->datasend(sprintf('%3d', $avail{$char}));
    }
    else {
      $mail->datasend('  -');
    }
  }
  $mail->datasend("\n");
  $mail->datasend('total  ');
  foreach $char (@types) {
    if ($total{$char} != 0) {
      $mail->datasend(sprintf('%3d', $total{$char}));
    }
    else {
      $mail->datasend('  -');
    }
  }
  $mail->datasend("\n\n$board[$all]\n");
  $most = 0;
  @line = ();
  foreach $color (@active) {
    $most = scalar(@{$legion{$color}}) if $most < scalar(@{$legion{$color}});
    push @line, "#$short{$color} Sz  Loc";
  }
  $mail->datasend(join(' |', @line), "\n");
  for ($legion = 0; $legion < $most; $legion++) {
    @line = ();
    foreach $color (@active) {
      if (defined(${$legion{$color}}[$legion])) {
        push @line, sprintf(' %2d %2d %4d', ${$legion{$color}}[$legion],
	${$size{$color}}[$legion], ${$loc{$color}}[$legion]);
      }
      else {
        push @line, '           ';
      }
    }
    $mail->datasend(join(' |', @line), "\n");
  }
  $mail->datasend("\n$board[$your]\n");
  $mail->datasend("\n");
  foreach $line (@board[$your+1..$map-1]) {
    $mail->datasend("$line\n") if $line =~ /^$short{$active}/i;
  }
  $mail->datasend("\n$board[$map]\n");
  foreach $line (@map) {
    $mail->datasend("$line\n");
  }
  $mail->datasend("\n");
  foreach $line (@board[$players..$end]) {
    $mail->datasend("$line\n");
  }
  $mail->dataend;
}
$mail->quit;
