http://qs321.pair.com?node_id=876618

I'm having to buy a car, and didn't know how to compare them, so I whipped up a little thing this morning to compare cars. It could use a bit more (estimated repairs/month, etc), but it does what I want.

Warning: Long, hence the readmore tags, though I can't recall if readmore tags actually do any good on a "top level" node.

#!/usr/bin/perl # # How much does it cost to drive a car? # use strict; use warnings; use Data::Dumper; use Getopt::Long; my $fuel_gal = "2.80"; my $weekly_miles=300; my $rpt_weekly=0; my $rpt_fuel =0; my $result = GetOptions( "miles=i" => \$weekly_miles, "weekly" => \$rpt_weekly, "fuel" => \$rpt_fuel, "gas=s" => \$fuel_gal, ); ##### # STEP 1: Fill out the distances between the locations you typically # drive between. We'll build our routes from them. Only one # one direction is required, unless you want asymmetric routes. ##### my %Distances = ( Home => { Work => 18.1, Son=>12.4, School=>12.4, Grandma=>25.3 }, Work => { Son => 11.3, School => 12.8 }, ); fixup_Distances(); # Fill out the missing table entries ##### # STEP 2: Define your common routes ##### my %Routes = map { my ($name, @locations) = @$_; $name => { Route => \@locations } } ( # Route_Name List of locations [ qw( Morning Home Work ) ], [ qw( Morning_w_Son Home School Work ) ], [ qw( Evening Work Home ) ], [ qw( Evening_w_Son Work Son Home ) ], [ qw( Get_Son Home Son Home ) ], [ qw( Visit_Grandma Home Grandma Home ) ], ); ##### # STEP 3: Build your daily itinerary ##### my @Itinerary = ( # DAY => qw( LIST OF ROUTES YOU TAKE THAT DAY ) [ SUN => qw( Visit_Grandma ) ], [ MON => qw( Morning_w_Son Evening ) ], [ TUE => qw( Morning Evening_w_Son ) ], [ WED => qw( Morning_w_Son Evening ) ], [ THU => qw( Morning Evening ) ], [ FRI => qw( Morning Evening ) ], [ SAT => qw( Get_Son ) ], ); ##### # STEP 4: Compute your weekly minimum mileage ##### if ($rpt_weekly) { print "\nWEEKLY MILEAGE\n\n"; my $weekly_ttl=0; for (@Itinerary) { my ($day, @routes) = (@$_); my @res; my $ttl=0; for (@routes) { my $d = route_length($_); $ttl += $d; push @res, $_, $d; } printf "%s %6.2f mi (", $day, $ttl; $weekly_ttl += $ttl; while (@res) { my $name=shift @res; my $dist=shift @res; print "$name=$dist "; } print ")\n"; } printf "\nTTL %6.2f mi MINIMUM (misc trips)\n", $weekly_ttl; } ##### # STEP 5: Set your weekly mileage to something more reasonable # (account for grocery shopping, visiting friends, etc. ##### printf "\nComputing remainder of report using $weekly_miles mi/wk\n"; if ($rpt_fuel) { my @Gas_Prices = ( 2.50, 2.75, 2.80, 2.90, 3.00, 3.10, 3.25 ); my @MPGs = ( 20, 25, 28, 30, 33, 35, 40 ); print "Fuel costs (MPG / GalPrice)\n\n"; print "MPG "; printf "%6.2f ", $_ for @Gas_Prices; print "\n"; for my $mpg (@MPGs) { printf "% 3u: ", $mpg; for my $GP (@Gas_Prices) { printf "%6.2f ", $GP*$weekly_miles / $mpg; } print "\n"; } print "\n\n"; } ##### # STEP 6: Plug in the cars you want to compare ##### my %Cars = ( "Optima EX" => { Mileage => [ 26, 35 ], Insurance => 448.70, Price => 13998.0, }, "PT Cruiser" => { Mileage => [ 20, 28 ], Insurance => 368.14, Price => 10998.0, }, "Solstice 2006" => { Mileage => [ 23.1, 30.2 ], Insurance => 230.89, Price => 14888, }, "Solstice 2006b" => { Mileage => [ 23.1, 30.2 ], Insurance => 230.89, Price => 10995, }, "Crossfire 2005" => { Mileage => [ 22.9, 27.3 ], Insurance => 230.89, Price => 12870, }, "Corolla 2010" => { Mileage => [ 26, 34 ], Insurance => 420.52, Price => 13599, }, "Elantra 2010" => { Mileage => [26, 34 ], Insurance => 403.74, Price => 14998, }, "Fusion 2008" => { Mileage => [ 20, 28 ], Insurance => 390.62, Price => 15998, }, ); print <<EOHDR; Monthly cost of ownership (weekly mi=$weekly_miles, fuel=\$$fuel_gal/g +al) Car Price /mo Ins Fuel -------------------- ------ ------ ------ -------/------- EOHDR for my $car (sort keys %Cars) { my ($miMax, $miMin) = map { 4 * $fuel_gal * $weekly_miles / $_ } @{$Cars{$car}{Mileage}}[0,1]; my $cost = $Cars{$car}{Price}; my $cost_mo = $cost/(5*12); my $ins_mo = $Cars{$car}{Insurance}/6; my $min = $ins_mo+$cost_mo+$miMin; my $max = $ins_mo+$cost_mo+$miMax; printf "%-20.20s %6u% 7.2f % 6.2f % 7.2f/%7.2f: (%6.2f / %6.2f)\n +", $car, $cost, $cost_mo, $ins_mo, $miMin, $miMax, $min, $max; } #--------------------------------------------------------------------- +------- # Miscellaneous subroutines #--------------------------------------------------------------------- +------- sub fixup_Distances { # Fill in the missing %Distances entries by reversing $from # and $to in the table. for my $from (keys %Distances) { for my $to (keys %{$Distances{$from}}) { # Don't mirror leg if it's already declared # (allows for asymmetric routes) next if exists($Distances{$to}) and exists($Distances{$to}{$from}); $Distances{$to}{$from} = $Distances{$from}{$to}; } } } sub route_length { my $route = shift; die "Route '$route' not defined!\n" if ! exists $Routes{$route}; if (! exists $Routes{$route}{LEN}) { my $ar = $Routes{$route}{Route}; my $cur = shift @$ar; my $ttl = 0; while (my $next = shift @$ar) { $ttl += leg_distance($cur, $next); $cur = $next; } $Routes{$route}{LEN} = $ttl; } return $Routes{$route}{LEN}; } sub leg_distance { # Distance between any two locations my ($from, $to) = (@_); die "Unknown location '$from'!\n" unless exists $Distances{$from}; die "Unknown location '$to'!\n" unless exists $Distances{$from}{$t +o}; return $Distances{$from}{$to}; }

...roboticus

Replies are listed 'Best First'.
Re: Auto cost per month
by ww (Archbishop) on Dec 11, 2010 at 20:58 UTC
    Neat. Very neat!

    I do agree, it can benefit from at least a couple more cost items. You've already mentioned one; repair/maintenance costs. Another that should perhaps play into your equation: "Opportunity cost," -- the cost of having your money tied up in an (object) rather than in an investment.

    Given your initial state -- "having to buy a car" -- the minimum cost of any (acceptable) vehicle isn't the issue here... but the cost differential between the lowest priced possibility and the others might offset some other factor(s) -- differential milage, repairs or insurance, just for example.

      :-)   But, before you get too rational about this, remember what a wise economist once told me: "Rational considerations aren't the whole issue, when buying a car."

      ww:

      Very true. I just get overwhelmed when I have a dozen printouts and such, and just needed a way to organize the info. After a few organization passes, it kinda grew, and helped me decide which printouts to pitch, and which cars to look for deals on.

      (I've been driving a '98 Saturn SL1 for 11 years, and it's been getting a very consistent 33mpg. So I put in the fuel calculations to see what would happen to my fuel bill when I change cars. Then, I added a "baseline" (repairing my Saturn) and added a column showing how much more each car would be than just repairing it. The engine blew, and the shop wants more than it's worth to drop in a rebuilt engine.)

      Update: (20140811) I forgot to update this with the actual car I got. I selected the PT Cruiser for some of its truck-like qualities. Unfortunately, gasoline went up immediately after I bought it, so in the end, I should've gotten a car with better mpg. I like the cruiser though, it's treated me well these past few years.

      ...roboticus

      When your only tool is a hammer, all problems look like your thumb.

      regarding your smiley-sentence: I can support it with a quote from the movie King Ralph:

      Gas mileage is fine, but keep in mind - the first question every car buyer asks themselves is 'Will this car get me laid?'

      All the best, Rata (really liking the idea and code of this thread, despite that quote ;-)