#!/usr/bin/perl -w

use strict;

my $amount = 100 * 1000;

#######################################################

my %realms =
  (
   "Fire"      => 1,
   "Cold"      => 1,
   "Lightning" => 1,
   "Poison"    => 2,
   "Acid"      => 3,
   "Air"       => 5,
   "Earth"     => 5,
   "Mind"      => 7,
   "Shield"    => 7,
   "Chaos"     => 7,
   "Magic"     => 10,
   "Antimagic" => 10
  );


my %powers =
  (
   "Fire"      => {
                   "Add to Light" => 1,
                   "Slay Undead Brand" => 1,
                   "Fire Brand" => 1,
                   "Resist Fire" => 1,
                   "Fire Aura" => 1
                  },
   "Cold"      => {
                   "Cold Brand" => 1,
                   "Slay Dragon Brand" => 1,
                   "Slay Demon Brand" => 1,
                   "Resist Cold" => 1,
                   "Invisibility" => 1,
                   "Slow Digestion" => 1

                  },
   "Lightning" => {
                   "Electricity Brand" => 1,
                   "Slay Evil Brand" => 1,
                   "Resist Electricity" => 1,
                   "Electric Aura" => 1,
                   "Random Teleportation" => 1

                  },
   "Poison"    => {
                   "Add to Charisma" => 1,
                   "Sustain Charisma" => 1,
                   "Poison Brand" => 1,
                   "Vampiric Brand" => 1,
                   "Slay Animal Brand" => 1,
                   "Resist Poison" => 1,
                   "Drain Experience" => 1,
                   "Sense Trolls" => 1,
                   "Sense Giants" => 1
                  },
   "Acid"      => {
                   "Add to Tunnelling" => 1,
                   "Acid Brand" => 1,
                   "Slay Animal Brand" => 1,
                   "Earthquake Brand" => 1,
                   "Resist Acid" => 1

                  },
   "Air"       => {
                   "Add to Wisdom" => 1,
                   "Add to Stealth" => 1,
                   "Add to Infravision" => 1,
                   "Add to Speed" => 1,
                   "Sustain Wisdom" => 1,
                   "Resist Light" => 1,
                   "Resist Dark" => 1,
                   "Resist Blindness" => 1,
                   "Levitation" => 1,
                   "See Invisible" => 1,
                   "Blessed" => 1,
                   "Sense Good" => 1
                  },
   "Earth"     => {
                   "Add to Strength" => 1,
                   "Add to Constitution" => 1,
                   "Add to Tunnelling" => 1,
                   "Add to Blows" => 1,
                   "Sustain Strength" => 1,
                   "Sustain Constitution" => 1,
                   "Slay Troll Brand" => 1,
                   "Slay Giant Brand" => 1,
                   "Earthquake Brand" => 1,
                   "Resist Fear" => 1,
                   "Resist Shards" => 1,
                   "Free Action" => 1,
                   "Regeneration" => 1,
                   "Sense Trolls" => 1,
                   "Sense Giants" => 1
                  },
   "Mind"      => {
                   "Add to Intelligence" => 1,
                   "Add to Searching" => 1,
                   "Sustain Intelligence" => 1,
                   "Resist Confusion" => 1,
                   "Resist Fear" => 1,
                   "Sense Orcs" => 1,
                   "Sense Trolls" => 1,
                   "Sense Giants" => 1,
                   "Sense Animals" => 1,
                   "Sense Uniques" => 1,
                   "Sense Spiders" => 1,
                   "Sense Demons" => 1
                  },
   "Shield"    => {
                   "Add to Dexterity" => 1,
                   "Sustain Dexterity" => 1,
                   "Resist Sound" => 1,
                   "Resist Nexus" => 1,
                   "Invisibility" => 1,
                   "Reflection" => 1,
                   "Hold Life" => 1,
                   "Regeneration" => 1

                  },
   "Chaos"     => {
                   "Chaos Brand" => 1,
                   "Earthquake Brand" => 1,
                   "Resist Chaos" => 1,
                   "Resist Disenchantment" => 1,
                   "Regeneration" => 1,
                   "Telepathy" => 1
                  },
   "Magic"     => {
                   "Add to Mana" => 1,
                   "Add to Spellpower" => 1,
                   "Cloning Brand" => 1,
                   "Resist Chaos" => 1,
                   "Resist Disenchantment" => 1,
                   "Wraithform" => 1,
                   "Precognition" => 1,
                   "Flight" => 1

                  },
   "Antimagic" => {

                   "Add to Blows" => 1,
                   "Add to Speed" => 1,
                   "Add to Life" => 1,
                   "Vampiric Brand" => 1,
                   "Chaos Brand" => 1,
                   "Reflection" => 1,
                   "Free Action" => 1,
                   "Hold Life" => 1,
                   "No Teleportation" => 1,
                   "See Invisible" => 1,
                   "Anti-magic shell" => 1,
                   "Antimagic field 1" => 1,
                   "Antimagic field 2" => 1
                  }
  );

my @realm_order =
  (
   "Fire",
   "Cold",
   "Lightning",
   "Poison",
   "Acid",
   "Air",
   "Earth",
   "Mind",
   "Shield",
   "Chaos",
   "Magic",
   "Antimagic"
  );


sub one_weapon {
    my $i;

    my $weap = {realms => [], points => 0, total_points => 0,
                pval => 0, to_h => 0, to_d => 0, powers => [],
                powers_avail => {}, failed_power_gains => 0};
    my $chance;

    for ($i = 1; $i < 50; $i++) {
        $chance = int(rand(100));

        if ($chance < 33) {
            if (rand(100) < 50) {
                $weap->{to_h}++;
            }
            else {
                $weap->{to_h} += 2;
            }
            $weap->{to_d}++
        }
        elsif ($chance < 66) {
            $weap->{points}++;
            $weap->{total_points}++;
            $weap->{to_h}++;

            $chance = int(rand(100));

            if ($chance < 40) {
                gain_realm($weap);
            } # gain realm
        } # gain point
        else {
            if (@{$weap->{realms}} == 0) {
                gain_realm($weap);
            }

            gain_power($weap);

            if ($weap->{pval} < 5) {
                if ($weap->{pval} == 0) {
                    $weap->{pval} = 1;
                } # if ($weap->{pval} == 0)
                else {
                     while (rand(100) < (20 - ($weap->{pval} * 2))) {
                        $weap->{pval}++;
                    }

                    if ($weap->{pval} >= 5) {
                        $weap->{pval} = 5;
                        $weap->{pval_maxed} = $i + 1;
                    }
                } # $weap->{pval} > 0
            } # if ($weap->{pval} < 5)
        }
    } # gain levels

    return $weap;
} # one_weapon()

sub gain_realm {
    my($weap) = @_;

    my %available = %realms;
    my($i, $realm);

    for ($i = 0; $i < @{$weap->{realms}}; $i++) {
        $realm = $weap->{realms}->[$i];

        # Already have that realm?
        delete($available{$realm});
    }

    # Get rid of too-expensive realms
    foreach $realm (keys %available) {
        if ($available{$realm} > $weap->{points}) {
            delete($available{$realm});
        }
    }

    return if keys(%available) == 0;

    my @avail_arr = keys(%available);

    $realm = $avail_arr[int(rand(@avail_arr))];

    push(@{$weap->{realms}}, $realm);

    $weap->{points} -= $realms{$realm};

    # Add to list of available powers
    my %new_powers = %{$powers{$realm}};
    my $power;

    foreach $power (keys(%new_powers)) {
        $weap->{avail_powers}->{$power} = 1;
    }

    # But don't re-add to the available list powers we already have
    foreach $power (@{$weap->{powers}}) {
        delete($weap->{avail_powers}->{$power});
    }
} # gain_realm()

sub gain_power {
    my($weap) = @_;

    my @avail = keys(%{$weap->{avail_powers}});

    if (@avail == 0) {
        $weap->{failed_power_gains}++;
        return;
    }

    my $power = $avail[int(rand(@avail))];

    push(@{$weap->{powers}}, $power);

    delete($weap->{avail_powers}->{$power});
} # gain_realm()

#############################################

sub print_amount {
    my $weapons = shift(@_);
    my $func    = shift(@_);

    my($i, @levels, $num);
    my $total = 0;

    for ($i = 0; $i < $amount; $i++) {
        $num = &$func($weapons->[$i], @_);

        $total += $num;

        $levels[$num]++;
    }

    print "Average value is ", $total / $amount, "\n\n";

    for ($i = 0; $i < scalar(@levels); $i++) {
        my $val = $levels[$i];

        next if (!$val || $val == 0);

        printf("%4i: %3i.%03i%%\n", $i, $val * 100 / $amount,
               ($val * 100 * 1000 / $amount) % 1000);
    }
    print "\n------------------------------------\n";
}

sub print_pct {
    my $weapons = shift(@_);
    my $func    = shift(@_);

    my($i, $num);

    $num = 0;
    for ($i = 0; $i < $amount; $i++) {
        $num++ if &$func($weapons->[$i], @_);
    }

    printf("%3i.%03i%%", $num * 100 / $amount,
           ($num * 100 * 1000 / $amount) % 1000);
}

#####################################
#####################################
#####################################

# Main

my $i;
my @weapons;

for ($i = 0; $i < $amount; $i++) {
    push(@weapons, one_weapon());
    my $weap = $weapons[$i];
}


print "Simulated $amount sentient weapons.\n\n";

print "Percent of weapons which gained each realm: \n";

my %realms_gained;
my $realm;

for ($i = 0; $i < $amount; $i++) {
    my $weap = $weapons[$i];

    my $realm;

    foreach $realm (@{$weap->{realms}}) {
        $realms_gained{$realm}++;
    }
}

foreach $realm (@realm_order) {
    my $gained = $realms_gained{$realm} || 0;
    printf("%-10s: %3i.%03i%%\n", $realm, $gained * 100 / $amount,
          ($gained * 100 * 1000 / $amount) % 1000);
}

print "\n------------------------------------\n";

#########

sub num_realms {
    my($weap) = @_;

    return scalar(@{$weap->{realms}});
}

print "\n       Number of realms gained\n\n";

print_amount(\@weapons, \&num_realms);

#########

sub final_pval {
    my($weap) = @_;

    return $weap->{pval};
}

print "\n       Final pval\n\n";

print_amount(\@weapons, \&final_pval);

#########

sub to_h_gained {
    my($weap) = @_;

    return $weap->{to_h};
}

print "\n       to_h gained \n\n";

print_amount(\@weapons, \&to_h_gained);

#########

sub to_d_gained {
    my($weap) = @_;

    return $weap->{to_d};
}

print "\n       to_d gained \n\n";

print_amount(\@weapons, \&to_d_gained);


#########

sub num_total_points {
    my($weap) = @_;

    return scalar($weap->{total_points});
}

print "\n       Number of points acquired over 49 level gains\n\n";

print_amount(\@weapons, \&num_total_points);

#########

sub num_points_left {
    my($weap) = @_;

    return scalar($weap->{points});
}

print "\n       Total number of points left unspent\n\n";

print_amount(\@weapons, \&num_points_left);

#########

print "\n";

sub realm_combos {
    my($weap, $realms, $amnt) = @_;

    my %realm_hash;
    my $realm;
    my $num = 0;

    foreach $realm (@{$realms}) {
        $realm_hash{$realm} = 1;
    }

    foreach $realm (@{$weap->{realms}}) {
        $num++ if ($realm_hash{$realm});
    }

    return ($num == $amnt);
}

print "Weapons with only one of Fire, Cold or Lightning: ";
print_pct(\@weapons, \&realm_combos, ["Fire", "Cold", "Lightning"], 1);
print "\n";

print "Weapons with two of Fire, Cold or Lightning: ";
print_pct(\@weapons, \&realm_combos, ["Fire", "Cold", "Lightning"], 2);
print "\n";

print "Weapons with all of Fire, Cold and Lightning: ";
print_pct(\@weapons, \&realm_combos, ["Fire", "Cold", "Lightning"], 3);
print "\n";

print "Weapons with only one of Air or Earth: ";
print_pct(\@weapons, \&realm_combos, ["Air", "Earth"], 1);
print "\n";

print "Weapons with both Air and Earth: ";
print_pct(\@weapons, \&realm_combos, ["Air", "Earth"], 2);
print "\n";

print "Weapons with only one of Mind, Shield or Chaos: ";
print_pct(\@weapons, \&realm_combos, ["Mind", "Shield", "Chaos"], 1);
print "\n";

print "Weapons with two of Mind, Shield or Chaos: ";
print_pct(\@weapons, \&realm_combos, ["Mind", "Shield", "Chaos"], 2);
print "\n";

print "Weapons with all of Mind, Shield and Chaos: ";
print_pct(\@weapons, \&realm_combos, ["Mind", "Shield", "Chaos"], 3);
print "\n";

print "Weapons with only one of Magic or Antimagic: ";
print_pct(\@weapons, \&realm_combos, ["Magic", "Antimagic"], 1);
print "\n";

print "Weapons with both Magic and Antimagic: ";
print_pct(\@weapons, \&realm_combos, ["Magic", "Antimagic"], 2);
print "\n";

##########################################################################
##########################################################################

# Now do powers

print "\n##########################################\n";

sub num_powers {
    my($weap) = @_;

    return scalar(@{$weap->{powers}});
}

print "\n       Number of powers acquired\n\n";

print_amount(\@weapons, \&num_powers);

###

sub failed_power_gains {
    my($weap) = @_;

    return $weap->{failed_power_gains};
}

print "\n       Number of power gain attempts which failed \n\n";

print_amount(\@weapons, \&failed_power_gains);

###

my %power_count = ();
my $power;

for ($i = 0; $i < $amount; $i++) {
    my $weap = $weapons[$i];

    foreach $power (@{$weap->{powers}}) {
        $power_count{$power}++;
    }
}

print "Powers gained: \n\n";

foreach $power (sort(keys(%power_count))) {
    my $val = $power_count{$power};
    printf("%-22s: %3i.%03i%%\n", $power, $val * 100 / $amount,
               ($val * 100 * 1000 / $amount) % 1000);
}

Spoilers/Sentient Weapons/Statistics/stats.pl (last edited 2006-03-10 19:48:36 by KhymChanur)