# Hacked together by Simon Green (@lumbarius) to decode the Webstock Game 2011 (@webstockgame).
use strict;
use Memoize;
memoize( 'Run', 'MotivationModifier', 'Time', 'Duration' );
my ($motivations_ref, $motivationCombos_ref, $units_ref, $foods_ref, $foodBoost_ref, $foodCombos_ref, $speakers_ref, $results_ref);
my $best_ref = [0, undef, undef];
Main();
sub Main
{
Initialise();
BruteForce();
foreach my $time ( sort { $b <=> $a }
keys %{$results_ref} )
{
print "$results_ref->{$time}\n";
}
return;
}
sub Initialise
{
# http://twitter.com/webstockgame/status/37978363020713984 "LOLCats: + 2.2 km/h. It's either laughter or fear that gives your feet wings."
# http://twitter.com/webstockgame/status/37982147289550848 "TSA: +2.2 km/h. Get enough millimetre waves through your body and it'll turn into kilometres."
# http://twitter.com/webstockgame/status/38021097811087360 "Amanda Palmer album: +2.7 km/h. Because everyone likes Tasmania."
# http://twitter.com/webstockgame/status/38033677829013504 "API: +1.9 km/h. Because APIs help you come up to speed and click RUN."
# http://twitter.com/webstockgame/status/38324338209857536 "Accessibility: +3.1 km/h. Unfortunately not everyone cares about accessibility :-("
# http://twitter.com/webstockgame/status/38344478796419072 "Running tips: +1.4 mph. Unfortunately, spending 16 hours a day googling does not make an athlete."
# http://twitter.com/webstockgame/status/38397856910032896 "The ONYAs boost you 2.9 km/h. #scheduledtweetfail #webstock"
$motivations_ref = {
'LOLCats' => 2.2,
'TSA' => 2.2,
'Amanda Palmer Album' => 2.7,
'API' => 1.9,
'Accessibility' => 3.1,
'Running tips' => 1.4 * 1.61,
'Onyas Ticket' => 2.9,
};
# http://twitter.com/webstockgame/status/38311297552617472 "You might have realised by now that food has different effects on each speaker. Might be anything between -30% to +30% on each 1000m sector."
$foodBoost_ref = {
'UMD' => 0.7,
'MD' => 0.8,
'SD' => 0.9,
'Y' => 1,
'SB' => 1.1,
'MB' => 1.2,
'UMB' => 1.3,
};
# http://twitter.com/webstockgame/status/38311410115153920 "And having too much food of one kind is even worse..."
$foods_ref = {
'Coffee' => 3,
'Fish' => 99,
'IceCream' => 3,
'L&P' => 3,
'Marmite' => 2,
'Pavlova' => 2,
'Wine' => 3,
};
# Josh Clark "A speaker's base speed is expressed in the common measurement units of their home country (according to Twitter)."
$units_ref = {
'kph' => 1,
'mph' => 1.61,
};
# http://webstockgame.org/
# http://webstockgame.org/speakers.xml
$speakers_ref = {
'Amanda Palmer' => { 'Initials' => 'AP', 'Profession' => [ 'Artist' ], 'BaseSpeed' => 10, 'Unit' => 'mph', 'Food' => { 'Coffee' => 'SD', 'Fish' => 'Y', 'Wine' => 'SB', 'Pavlova' => 'MB', 'L&P' => 'UMB', 'Marmite' => 'UMD', 'IceCream' => 'MD' }, 'Glasses' => 0, 'American' => 1 },
'Charlie Bird' => { 'Initials' => 'CB', 'Profession' => [ 'Organiser' ], 'BaseSpeed' => 13, 'Unit' => 'kph', 'Food' => { 'Coffee' => 'MD', 'Fish' => 'SD', 'Wine' => 'Y', 'Pavlova' => 'SB', 'L&P' => 'MB', 'Marmite' => 'UMB', 'IceCream' => 'UMD' }, 'Glasses' => 0, 'American' => 0 },
'Christine Perfetti' => { 'Initials' => 'CP', 'Profession' => [ 'Maven' ], 'BaseSpeed' => 15, 'Unit' => 'mph', 'Food' => { 'Coffee' => 'Y', 'Fish' => 'SB', 'Wine' => 'MB', 'Pavlova' => 'UMB', 'L&P' => 'UMD', 'Marmite' => 'MD', 'IceCream' => 'SD' }, 'Glasses' => 0, 'American' => 1 },
'David McCandless' => { 'Initials' => 'DMC', 'Profession' => [ 'Creative' ], 'BaseSpeed' => 13, 'Unit' => 'mph', 'Food' => { 'Coffee' => 'UMD', 'Fish' => 'MD', 'Wine' => 'SD', 'Pavlova' => 'Y', 'L&P' => 'SB', 'Marmite' => 'MB', 'IceCream' => 'UMB' }, 'Glasses' => 1, 'American' => 0 },
'David Recordon' => { 'Initials' => 'DR', 'Profession' => [ 'Maven' ], 'BaseSpeed' => 12, 'Unit' => 'mph', 'Food' => { 'Coffee' => 'MB', 'Fish' => 'UMB', 'Wine' => 'UMD', 'Pavlova' => 'MD', 'L&P' => 'SD', 'Marmite' => 'Y', 'IceCream' => 'SB' }, 'Glasses' => 0, 'American' => 1 },
'Doug Bowman' => { 'Initials' => 'DB', 'Profession' => [ 'Creative' ], 'BaseSpeed' => 11, 'Unit' => 'mph', 'Food' => { 'Coffee' => 'SD', 'Fish' => 'Y', 'Wine' => 'SB', 'Pavlova' => 'MB', 'L&P' => 'UMB', 'Marmite' => 'UMD', 'IceCream' => 'MD' }, 'Glasses' => 1, 'American' => 1 },
'Frank Chimero' => { 'Initials' => 'FC', 'Profession' => [ 'Creative' ], 'BaseSpeed' => 9, 'Unit' => 'mph', 'Food' => { 'Coffee' => 'SB', 'Fish' => 'MB', 'Wine' => 'UMB', 'Pavlova' => 'UMD', 'L&P' => 'MD', 'Marmite' => 'SD', 'IceCream' => 'Y' }, 'Glasses' => 1, 'American' => 1 },
'Glenda Sims' => { 'Initials' => 'GS', 'Profession' => [ 'Maven' ], 'BaseSpeed' => 11, 'Unit' => 'mph', 'Food' => { 'Coffee' => 'UMD', 'Fish' => 'MD', 'Wine' => 'SD', 'Pavlova' => 'Y', 'L&P' => 'SB', 'Marmite' => 'MB', 'IceCream' => 'UMB' }, 'Glasses' => 0, 'American' => 1 },
'Jason Cohen' => { 'Initials' => 'JCO', 'Profession' => [ 'Maven' ], 'BaseSpeed' => 8, 'Unit' => 'mph', 'Food' => { 'Coffee' => 'UMD', 'Fish' => 'MD', 'Wine' => 'SD', 'Pavlova' => 'Y', 'L&P' => 'SB', 'Marmite' => 'MB', 'IceCream' => 'UMB' }, 'Glasses' => 0, 'American' => 1 },
'Jason Santa Maria' => { 'Initials' => 'JSM', 'Profession' => [ 'Artist' ], 'BaseSpeed' => 10, 'Unit' => 'mph', 'Food' => { 'Coffee' => 'UMB', 'Fish' => 'UMD', 'Wine' => 'MD', 'Pavlova' => 'SD', 'L&P' => 'Y', 'Marmite' => 'SB', 'IceCream' => 'MB' }, 'Glasses' => 1, 'American' => 1 },
'Jason Webley' => { 'Initials' => 'JW', 'Profession' => [ 'Artist' ], 'BaseSpeed' => 10, 'Unit' => 'mph', 'Food' => { 'Coffee' => 'SB', 'Fish' => 'MB', 'Wine' => 'UMB', 'Pavlova' => 'UMD', 'L&P' => 'MD', 'Marmite' => 'SD', 'IceCream' => 'Y' }, 'Glasses' => 0, 'American' => 1 },
'John Gruber' => { 'Initials' => 'JG', 'Profession' => [ 'Coder' ], 'BaseSpeed' => 12, 'Unit' => 'mph', 'Food' => { 'Coffee' => 'MD', 'Fish' => 'SD', 'Wine' => 'Y', 'Pavlova' => 'SB', 'L&P' => 'MB', 'Marmite' => 'UMB', 'IceCream' => 'UMD' }, 'Glasses' => 0, 'American' => 1 },
'Josh Clark' => { 'Initials' => 'JC', 'Profession' => [ 'Maven' ], 'BaseSpeed' => 11, 'Unit' => 'mph', 'Food' => { 'Coffee' => 'MB', 'Fish' => 'UMB', 'Wine' => 'UMD', 'Pavlova' => 'MD', 'L&P' => 'SD', 'Marmite' => 'Y', 'IceCream' => 'SB' }, 'Glasses' => 0, 'American' => 1 },
'Kristina Halvorson' => { 'Initials' => 'KH', 'Profession' => [ 'Maven' ], 'BaseSpeed' => 7, 'Unit' => 'mph', 'Food' => { 'Coffee' => 'SD', 'Fish' => 'Y', 'Wine' => 'SB', 'Pavlova' => 'MB', 'L&P' => 'UMB', 'Marmite' => 'UMD', 'IceCream' => 'MD' }, 'Glasses' => 1, 'American' => 1 },
'Marco Arment' => { 'Initials' => 'MA', 'Profession' => [ 'Maven' ], 'BaseSpeed' => 10, 'Unit' => 'mph', 'Food' => { 'Coffee' => 'UMD', 'Fish' => 'MD', 'Wine' => 'SD', 'Pavlova' => 'Y', 'L&P' => 'SB', 'Marmite' => 'MB', 'IceCream' => 'UMB' }, 'Glasses' => 0, 'American' => 1 },
'Mark Pilgram' => { 'Initials' => 'MP', 'Profession' => [ 'Coder', 'Maven' ], 'BaseSpeed' => 13, 'Unit' => 'mph', 'Food' => { 'Coffee' => 'SB', 'Fish' => 'MB', 'Wine' => 'UMB', 'Pavlova' => 'UMD', 'L&P' => 'MD', 'Marmite' => 'SD', 'IceCream' => 'Y' }, 'Glasses' => 1, 'American' => 1 },
'Merlin Mann' => { 'Initials' => 'MM', 'Profession' => [ 'Maven' ], 'BaseSpeed' => 14, 'Unit' => 'mph', 'Food' => { 'Coffee' => 'UMB', 'Fish' => 'UMD', 'Wine' => 'MD', 'Pavlova' => 'SD', 'L&P' => 'Y', 'Marmite' => 'SB', 'IceCream' => 'MB' }, 'Glasses' => 1, 'American' => 1 },
'Michael Koziarski' => { 'Initials' => 'MK', 'Profession' => [ 'Coder' ], 'BaseSpeed' => 19, 'Unit' => 'kph', 'Food' => { 'Coffee' => 'Y', 'Fish' => 'SB', 'Wine' => 'MB', 'Pavlova' => 'UMB', 'L&P' => 'UMD', 'Marmite' => 'MD', 'IceCream' => 'SD' }, 'Glasses' => 0, 'American' => 0 },
'Michael Lopp' => { 'Initials' => 'ML', 'Profession' => [ 'Coder', 'Maven' ], 'BaseSpeed' => 11, 'Unit' => 'mph', 'Food' => { 'Coffee' => 'MB', 'Fish' => 'UMB', 'Wine' => 'UMD', 'Pavlova' => 'MD', 'L&P' => 'SD', 'Marmite' => 'Y', 'IceCream' => 'SB' }, 'Glasses' => 0, 'American' => 1 },
'Mike Brown' => { 'Initials' => 'MB', 'Profession' => [ 'Organiser' ], 'BaseSpeed' => 23, 'Unit' => 'kph', 'Food' => { 'Coffee' => 'Y', 'Fish' => 'SB', 'Wine' => 'MB', 'Pavlova' => 'UMB', 'L&P' => 'UMD', 'Marmite' => 'MD', 'IceCream' => 'SD' }, 'Glasses' => 0, 'American' => 0 },
'Nicole Sullivan' => { 'Initials' => 'NS', 'Profession' => [ 'Coder' ], 'BaseSpeed' => 12, 'Unit' => 'mph', 'Food' => { 'Coffee' => 'Y', 'Fish' => 'SB', 'Wine' => 'MB', 'Pavlova' => 'UMB', 'L&P' => 'UMD', 'Marmite' => 'MD', 'IceCream' => 'SD' }, 'Glasses' => 0, 'American' => 1 },
'Peter Sunde' => { 'Initials' => 'PS', 'Profession' => [ 'Coder' ], 'BaseSpeed' => 21, 'Unit' => 'kph', 'Food' => { 'Coffee' => 'SD', 'Fish' => 'Y', 'Wine' => 'SB', 'Pavlova' => 'MB', 'L&P' => 'UMB', 'Marmite' => 'UMD', 'IceCream' => 'MD' }, 'Glasses' => 0, 'American' => 0 },
'Scott McCloud' => { 'Initials' => 'SMC', 'Profession' => [ 'Artist' ], 'BaseSpeed' => 12, 'Unit' => 'mph', 'Food' => { 'Coffee' => 'MD', 'Fish' => 'SD', 'Wine' => 'Y', 'Pavlova' => 'SB', 'L&P' => 'MB', 'Marmite' => 'UMB', 'IceCream' => 'UMD' }, 'Glasses' => 1, 'American' => 1 },
'Steve Souders' => { 'Initials' => 'SS', 'Profession' => [ 'Maven' ], 'BaseSpeed' => 12, 'Unit' => 'mph', 'Food' => { 'Coffee' => 'MD', 'Fish' => 'SD', 'Wine' => 'Y', 'Pavlova' => 'SB', 'L&P' => 'MB', 'Marmite' => 'UMB', 'IceCream' => 'UMD' }, 'Glasses' => 0, 'American' => 1 },
'Tash Lampard' => { 'Initials' => 'TL', 'Profession' => [ 'Organiser' ], 'BaseSpeed' => 16, 'Unit' => 'kph', 'Food' => { 'Coffee' => 'SB', 'Fish' => 'MB', 'Wine' => 'UMB', 'Pavlova' => 'UMD', 'L&P' => 'MD', 'Marmite' => 'SD', 'IceCream' => 'Y' }, 'Glasses' => 0, 'American' => 0 },
'Tom Coates' => { 'Initials' => 'TC', 'Profession' => [ 'Maven' ], 'BaseSpeed' => 16, 'Unit' => 'mph', 'Food' => { 'Coffee' => 'UMB', 'Fish' => 'UMD', 'Wine' => 'MD', 'Pavlova' => 'SD', 'L&P' => 'Y', 'Marmite' => 'SB', 'IceCream' => 'MB' }, 'Glasses' => 0, 'American' => 1 },
};
foreach my $speaker ( keys %{$speakers_ref} )
{
$speakers_ref->{$speaker}->{'Name'} = $speaker;
# Convert boost names to values
foreach my $food ( keys %{$foods_ref} )
{
$speakers_ref->{$speaker}->{'Food'}->{$food} = $foodBoost_ref->{ $speakers_ref->{$speaker}->{'Food'}->{$food} };
}
}
FriendOrFoe();
# Combos originally built with the help of http://www.mathsisfun.com/combinatorics/combinations-permutations-calculator.html to save time and brain cycles
SafeFoodCombos();
MotivationCombos();
}
sub FriendOrFoe
{
foreach my $speaker1_ref ( values %{$speakers_ref} )
{
$speaker1_ref->{'Arch-Enemies'} = [];
$speaker1_ref->{'Buddies'} = [];
# Scott McCloud: "Your duo is a team, but there's 'me' in 'team', and that's why speakers with the same first name would rather nuke their iPads than run together."
$speaker1_ref->{'Name'} =~ /^([^ ]+) /;
my $firstName = $1;
foreach my $speaker2_ref ( grep { $speaker1_ref->{'Name'} != $_->{'Name'} &&
$_->{'Name'} =~ /^$firstName / &&
!$_->{'Arch-Enemies'} }
values %{$speakers_ref} )
{
push @{$speaker1_ref->{'Arch-Enemies'}}, $speaker2_ref->{'Name'};
push @{$speaker2_ref->{'Arch-Enemies'}}, $speaker1_ref->{'Name'};
}
# Amanda Palmer: "David Recordon's a big fan of the open seas. He'll friend anyone with a surname that begins with a 'C'!"
if ($speaker1_ref->{'Name'} == 'David Recordon')
{
foreach my $speaker2_ref ( grep { $_->{'Name'} != $speaker1_ref->{'Name'} &&
$_->{'Name'} =~ /^(?:[^ ]+) C/ }
values %{$speakers_ref} )
{
push @{$speaker1_ref->{'Buddies'}}, $speaker2_ref->{'Name'};
}
}
}
# Jason Cohen "Harry and Voldemort. Superman and Lex. Frank and Marco. Pilgrim and Perfetti. Clark and Coates. Palmer and Sims."
$speakers_ref->{'Frank Chimero'}->{'Arch-Enemies'} = [ 'Marco Arment' ];
$speakers_ref->{'Marco Arment'}->{'Arch-Enemies'} = [ 'Frank Chimero' ];
$speakers_ref->{'Mark Pilgram'}->{'Arch-Enemies'} = [ 'Christine Perfetti' ];
$speakers_ref->{'Christine Perfetti'}->{'Arch-Enemies'} = [ 'Mark Pilgram' ];
$speakers_ref->{'Josh Clark'}->{'Arch-Enemies'} = [ 'Tom Coates' ];
$speakers_ref->{'Tom Coates'}->{'Arch-Enemies'} = [ 'Josh Clark' ];
$speakers_ref->{'Amanda Palmer'}->{'Arch-Enemies'} = [ 'Glenda Sims' ];
$speakers_ref->{'Glenda Sims'}->{'Arch-Enemies'} = [ 'Amanda Palmer' ];
# Michael Koziarski "Souders & Sullivan once worked together optimising a site. The final files were a negative size, resulting in a black hole. They must never team up again."
$speakers_ref->{'Steve Souders'}->{'Arch-Enemies'} = [ 'Nicole Sullivan' ];
$speakers_ref->{'Nicole Sullivan'}->{'Arch-Enemies'} = [ 'Steve Souders' ];
# Kristina Halvorson "Abbott and Costello. Bret and Jemaine. Clark and McCandless. Palmer and Webley. Lopp and Gruber. Souders and Sunde."
$speakers_ref->{'Josh Clark'}->{'Buddies'} = [ 'David McCandless' ];
$speakers_ref->{'David McCandless'}->{'Buddies'} = [ 'Josh Clark' ];
$speakers_ref->{'Amanda Palmer'}->{'Buddies'} = [ 'Jason Webley' ];
$speakers_ref->{'Jason Webley'}->{'Buddies'} = [ 'Amanda Palmer' ];
$speakers_ref->{'Michael Lopp'}->{'Buddies'} = [ 'John Gruber' ];
$speakers_ref->{'John Gruber'}->{'Buddies'} = [ 'Michael Lopp' ];
$speakers_ref->{'Steve Souders'}->{'Buddies'} = [ 'Peter Sunde' ];
$speakers_ref->{'Peter Sunde'}->{'Buddies'} = [ 'Steve Souders' ];
# Tom Coates "Frodo & Sam. Batman & Robin. Merlin & Doug. Frank and Tom. Tash, Mike % Charlie. Mark & Glenda."
$speakers_ref->{'Merlin Mann'}->{'Buddies'} = [ 'Doug Bowman' ];
$speakers_ref->{'Doug Bowman'}->{'Buddies'} = [ 'Merlin Mann' ];
$speakers_ref->{'Frank Chimero'}->{'Buddies'} = [ 'Tom Coates' ];
$speakers_ref->{'Tom Coates'}->{'Buddies'} = [ 'Frank Chimero' ];
$speakers_ref->{'Tash Lampard'}->{'Buddies'} = [ 'Charlie Bird', 'Mike Brown' ];
$speakers_ref->{'Mike Brown'}->{'Buddies'} = [ 'Charlie Bird', 'Tash Lampard' ];
$speakers_ref->{'Charlie Bird'}->{'Buddies'} = [ 'Mike Brown', 'Tash Lampard' ];
$speakers_ref->{'Mark Pilgram'}->{'Buddies'} = [ 'Glenda Sims' ];
$speakers_ref->{'Glenda Sims'}->{'Buddies'} = [ 'Mark Pilgram' ];
# John Gruber: "Arment, Gilbert & Sullivan. Cohen & Koziarski. McCloud and Santa Maria Perfetti and Halvorson. Lemon and Paeroa."
$speakers_ref->{'Marco Arment'}->{'Buddies'} = [ 'Nicole Sullivan' ];
$speakers_ref->{'Nicole Sullivan'}->{'Buddies'} = [ 'Marco Arment' ];
$speakers_ref->{'Jason Cohen'}->{'Buddies'} = [ 'Michael Koziarski' ];
$speakers_ref->{'Michael Koziarski'}->{'Buddies'} = [ 'Jason Cohen' ];
$speakers_ref->{'Scott McCloud'}->{'Buddies'} = [ 'Jason Santa Maria' ];
$speakers_ref->{'Jason Santa Maria'}->{'Buddies'} = [ 'Scott McCloud' ];
$speakers_ref->{'Christine Perfetti'}->{'Buddies'} = [ 'Kristina Halvorson' ];
$speakers_ref->{'Kristina Halvorson'}->{'Buddies'} = [ 'Christine Perfetti' ];
return;
}
sub SafeFoodCombos
{
my ($food, $foodCombo_ref, $foodComboInfo_ref) = @_;
# Mike Brown "Your submission should include no more than 5 food cards"
if (!$food)
{
$foodCombos_ref = [];
foreach my $food2 ( keys %{$foods_ref} )
{
my @foodCombo = ();
my %foodComboInfo = ();
SafeFoodCombos($food2, \@foodCombo, \%foodComboInfo);
}
}
else
{
foreach my $food2 ( grep { ( $food le $_ ) &&
( $foodComboInfo_ref->{$_} + 1 < $foods_ref->{$_} ) }
keys %{$foods_ref} )
{
push @{$foodCombo_ref}, $food2;
$foodComboInfo_ref->{$food2}++;
if ($#{$foodCombo_ref} < 4)
{
SafeFoodCombos($food2, $foodCombo_ref, $foodComboInfo_ref);
}
else
{
push @{$foodCombos_ref}, [ @{$foodCombo_ref} ];
}
pop @{$foodCombo_ref};
$foodComboInfo_ref->{$food2}--;
}
}
return;
}
sub MotivationCombos
{
$motivationCombos_ref = [];
# Charlie Bird "This is a relay race - if you don't provide a team of exactly two speakers, there's no way you'll even participate."
# Doug Bowman "Each speaker should have one motivation card, but be careful - both racers will be affected by both motivations."
foreach my $motivation1 ( keys %{$motivations_ref} )
{
foreach my $motivation2 ( grep {$_ gt $motivation1}
keys %{$motivations_ref} )
{
push @{$motivationCombos_ref}, [$motivation1, $motivation2];
}
}
# http://twitter.com/kalena/status/38185965981929472 "@webstockgame Can you include duplicate motivation or food cards in your submission? Can't find the answer to this anywhere!"
# http://twitter.com/webstockgame/status/38305095099748352 "@kalena If there's no rule explicitly forbidding it, I think you could give it a try :)"
foreach my $motivation ( keys %{$motivations_ref} )
{
push @{$motivationCombos_ref}, [$motivation, $motivation];
}
}
sub BruteForce
{
foreach my $runner1_ref (
# sort {$a->{'Name'} cmp $b->{'Name'}}
values %{$speakers_ref} )
{
foreach my $runner2_ref (
# sort {$a->{'Name'} cmp $b->{'Name'}}
grep { $_->{'Name'} gt $runner1_ref->{'Name'} }
values %{$speakers_ref} )
{
Relay($runner1_ref, $runner2_ref);
}
}
}
sub Relay
{
my ($runner1_ref, $runner2_ref) = @_;
# Charlie Bird "This is a relay race - if you don't provide a team of exactly two speakers, there's no way you'll even participate."
foreach my $runner1Profession ( @{$runner1_ref->{'Profession'}} )
{
# Tash Lampard "Bennifer and Brangelina - ah, popular portmanteaus! Write oue for your running buddies and stick it in with your entry. It's funny enough they'll get a 5% base speed bonus!"
my $runner1Modifier = 1.05;
my $runner2Modifier = 1.05;
# David Recordon "Any American teamed up with a non-American gains a 10% base speed increase!"
$runner1Modifier *= ($runner1_ref->{'American'} && !$runner2_ref->{'American'}) ? 1.1 : 1;
$runner2Modifier *= ($runner2_ref->{'American'} && !$runner1_ref->{'American'}) ? 1.1 : 1;
# Michael Lopp "Glasses - they focus your eyes. Surprisingly, they also focus your race mentality. FOUR EYES SPEAKER POWERUP: 10% base speed increase!"
$runner1Modifier *= ($runner1_ref->{'Glasses'}) ? 1.1 : 1;
$runner2Modifier *= ($runner2_ref->{'Glasses'}) ? 1.1 : 1;
# http://twitter.com/webstockgame/status/38003315480469504 "Running with a racing buddy friend gives a speaker a 10% bonus on their base speed."
$runner1Modifier *= ("@{$runner1_ref->{'Buddies'}}" =~ /$runner2_ref->{'Name'}/) ? 1.1 : 1;
$runner2Modifier *= ("@{$runner2_ref->{'Buddies'}}" =~ /$runner1_ref->{'Name'}/) ? 1.1 : 1;
# http://twitter.com/webstockgame/status/38003446254665728 "Running with an arch-enemy makes reduces their base speed by about 25%"
$runner1Modifier /= ("@{$runner1_ref->{'Arch-Enemies'}}" =~ /$runner2_ref->{'Name'}/) ? 1.25 : 1;
$runner2Modifier /= ("@{$runner2_ref->{'Arch-Enemies'}}" =~ /$runner1_ref->{'Name'}/) ? 1.25 : 1;
# http://twitter.com/webstockgame/status/38044995223031808 "If a speaker has multiple archetypes, you a their coach can decide which one they're gonna be by circling it on the card."
foreach my $runner2Profession ( @{$runner2_ref->{'Profession'}} )
{
foreach my $motivationCombo_ref ( @{$motivationCombos_ref} )
{
foreach my $foodCombo_ref ( @{$foodCombos_ref} )
{
my $runner1speed_ref = Run($runner1_ref->{'Name'}, $runner1Modifier, $runner1Profession, $motivationCombo_ref, $foodCombo_ref);
my $runner2speed_ref = Run($runner2_ref->{'Name'}, $runner2Modifier, $runner2Profession, $motivationCombo_ref, $foodCombo_ref);
my $runner1Time = Time( @{$runner1speed_ref} );
my $runner2Time = Time( @{$runner2speed_ref} );
my $time = $runner1Time + $runner2Time;
if (!$best_ref->[0] || $time < $best_ref->[0])
{
$best_ref->[0] = $time if (!$best_ref->[0] || $time < $best_ref->[0]);
my %m = ();
foreach my $m ( @{$motivationCombo_ref} ) { $m{$m}++; }
my %f = ();
foreach my $f ( @{$foodCombo_ref} ) { $f{$f}++; }
my $fGroup = join ', ', map { "$_" . ( $f{$_} > 1 ? " x $f{$_}" : '' ) } keys %f;
my $mGroup = join ', ', map { "$_" . ( $m{$_} > 1 ? " x $m{$_}" : '' ) } keys %m;
$best_ref = [$runner1Time + $runner2Time, Duration($best_ref->[0]) . " $runner1_ref->{'Name'} ($runner1Profession) & $runner2_ref->{'Name'} ($runner2Profession); $mGroup; $fGroup", $runner1_ref, $runner2_ref];
$results_ref->{$time} = $best_ref->[1];
}
}
}
}
}
}
sub Run
{
my ($runnerName, $modifier, $profession, $motivationGroup_ref, $foodGroup_ref) = @_;
my $runner_ref = $speakers_ref->{$runnerName};
my $motivationSpeed = 0;
foreach my $motivation ( @{$motivationGroup_ref} )
{
$motivationSpeed += MotivationModifier($motivation, $profession);
}
my @speed = ();
# Merlin Mann "Each speaker runs 5000 metres. The five food cards affect how they run each 1000 metres of their race leg."
foreach my $food (@{$foodGroup_ref})
{
# Rules "When scoring we first calculate the speed of each of your speakers and apply any racing buddy modifications and other personal add-ons. Then we'll have a look at their motivation and finally we'll feed them, in that order. Got it?"
push @speed, ( $runner_ref->{'BaseSpeed'}
* $units_ref->{$runner_ref->{'Unit'}}
* $modifier
+ $motivationSpeed )
* $runner_ref->{'Food'}->{$food}
;
}
return \@speed;
}
sub MotivationModifier
{
my ($motivation, $profession) = @_;
# http://twitter.com/webstockgame/status/38003477846167553 "If you try to motivate speakers with something they hate, expect the benefit of the motivation card to be negated."
# http://twitter.com/webstockgame/status/37970752279941120 "Coders are intrinsically motivated to the highest level. Each motivation card has just 50% of the positive effect it'd have on other people."
my $coderModifier = ($profession =~ /^Coder$/) ? 0.5 : 1;
if ($motivation =~ /^Amanda Palmer Album$/)
{
# http://twitter.com/webstockgame/status/38349545591013376 "Music: often the lifeblood of creative people, and often another nascent trend to be harvested by Mavens."
if ($profession =~ /^(?:Creative|Maven)$/)
{
return $motivations_ref->{$motivation};
}
}
elsif ($motivation =~ /^LOLCats$/)
{
if ($profession =~ /^Artist$/)
{
# http://twitter.com/webstockgame/status/37987374608678912 "Every LOLcat picture is a work of art. It follows that every artist loves LOLcats, no?"
return $motivations_ref->{$motivation};
}
elsif ($profession =~ /^Organiser$/)
{
# Steve Souders: Organisers spend half their lives hearding kittens. Think it makes them happy?
return $motivations_ref->{$motivation} * -1;
}
}
elsif ($motivation =~ /^API$/)
{
# http://twitter.com/webstockgame/status/38055177172819968 "Mavens and APIs? Reeeallllly?"
if ($profession =~ /^Maven$/)
{
return $motivations_ref->{$motivation} * -1;
}
}
elsif ($motivation =~ /^TSA$/)
{
# http://twitter.com/webstockgame/status/38012371079266305 "Coders have strong opinions on everything, but being groped by underpaid security guards makes them worry about accessibility."
if ($profession =~ /^Coder$/)
{
return $motivations_ref->{$motivation} * -1 * $coderModifier;
}
}
elsif ($motivation =~ /^Accessibility$/)
{
# http://twitter.com/webstockgame/status/38068897210961920 "Organisers: they read a hell of a lot (when they're not alphabetising their book catalogue)!"
if ($profession =~ /^Organiser$/)
{
return $motivations_ref->{$motivation};
}
}
elsif ($motivation =~ /^Running tips$/)
{
# Glenda Sims: We know that artists and creatives are motivated by an eternay search for beauty and meaning. Surprisingly, so are coders.
if ($profession =~ /^(?:Artist|Coder|Creative)$/)
{
return $motivations_ref->{$motivation} * $coderModifier;
}
}
elsif ($motivation =~ /^Onyas Ticket$/)
{
# http://twitter.com/lumbarius/status/38367128251932672 "@webstockgame I haven't seen a rule for ONYAs... did I miss something?"
# http://twitter.com/webstockgame/status/38377248499314688 "@lumbarius doesn't everyone love the ONYAs ???? #Webstock"
return $motivations_ref->{$motivation} * $coderModifier;
}
return 0;
}
sub Time
{
my $sum = 0;
foreach my $val (@_)
{
$sum += 1 / $val * 3600;
}
return $sum;
}
sub Duration
{
my ($seconds) = @_;
my $decimal = (($2 + 0) * 10) + ($3 + 0) + (($4 + 0) >= 5 ? 1 : 0);
my $minutes = int($seconds / 60);
$seconds -= ($minutes * 60);
$seconds =~ s/^(\d+(?:.\d{0,2})?).*$/$1/;
return "$minutes:" . ($seconds < 10 ? '0' : '') . $seconds;
}