« October 2006 | Main | December 2006 »

November 26, 2006

Zangband Tip: Digging Traps

In rougelike games such as Zangband, large numbers of monsters may easily overwhelm an exposed character. Properly dug traps expose your character to at most one monster, and prevent other monsters from using ranged attacks against you. Use wands of Stone to Mud or equivalent ability: switching to and using a shovel takes time, and may drop required benefits offered by your primary weapon.

Zangband! A winter sport for on-call and sick sysadmin!

  • Three square trap: only one adjacent square for a monster.

    ####### PPP ###P### ##P#### ###@### #######

  • Two square cut on a dead-end: one adjacent monster, additional square open to radius attacks against adjacent squares.

    ####### ##PPPP ##P#### ###@### #######

  • Doubling back: cutting back towards the monsters may cause them to wait in the corridor instead of attacking. Moving out of the trap may be required to lure in new monsters. The luring may limit attacks to small groups of monsters, allowing recovery, or expose character to damaging ranged attacks, depending on the situation.

    ##### # ### # # ## ## # ###@# # #####P# #####P# # PPP

Telepathy and other detection abilities allow a character to build traps in advance, before breaking into a room. Telepathy, in particular, allows observation of monster behaviour, so is highly recommended.

November 24, 2006

Unix Epoch Calculations

Coding bugs in Unix epoch time calculations may be avoided using the graphing method outlined here. Reasoning, however logical and detailed, does not work for me: I need to reference the visual diagram before trusting the resulting code. But first, a diversion down memory lane.

HISTORY
  A time() function appeared in Version 2 AT&T UNIX 
  and used to return time in sixtieths of a second in
  32 bits, which was to guarantee a crisis every 2.26
  years. Since the Version 6 AT&T UNIX time() scale
  was changed to seconds extending the pre-crisis
  stagnation period up to a total of 68 years.

Source: OpenBSD time(3) Documentation.

Technorati Tags:

  1. Graph Unix epoch time, and pick an arbitrary point to represent the current time when the date code encountered. Unix epoch time increases over time (discounting leap seconds and integer overflow problems), so use a linear 0 to ∞ line.

    Epoch-Graph-Base-1
  2. Divide the timeline into regions as appropriate for the coding problem. For example, data that expires—X.509 certificates or license codes—should be warned about if the expiration takes place soon, or critical warnings issued if already expired. This results in three regions:

    Epoch-Graph-Expiration-1
  3. In the code, create a variable for each time point, in this case expiration time and warn time. The Perl $EXPIRE_WARN_SECONDS variable (defined elsewhere) is added to the current time, as it lies to the right of the current time.

    my $current_time = time; my $time_expire = $current_time; my $time_warn = $current_time + $EXPIRE_WARN_SECONDS;

  4. Next, label an arbitrary time point in each region created by the previous step. In the case of X.509 certificate expiration monitoring, these would represent an expired certificate, a certificate in warning state, and a certificate requires no attention.

    Epoch-Graph-Labeled-2
  5. Finally, implement code to check the time derived from the X.509 certificate or license data. Reference the graph with each labeled point to determine the order of checks: expiration before warning, as an expired file is also less than the warn time. Match the > and < operators to the graph; larger numbers lie to the right. Use >= or <= if the time must coincide with the check, though for X.509 certificate expiration times, a second one way or the other should not matter, assuming the warning time allows for multiple checks before a certificate expires.

    # WRONG! Expired certificates are those # less than the expired time warn "expired" if $expire_date > $time_expire;

    # Accept epoch date of data to expire, return # whether expired, about to expire, or okay. sub expiration_check { my $expire_date = shift; my $current_time = time; my $time_expire = $current_time; my $time_warn = $current_time + $EXPIRE_WARN_SECONDS; if ( $expire_date <= $time_expire ) { return -1, 'error'; } elsif ( $expire_date <= $time_warn ) { return -1, 'warning'; } else { return 1, 'good'; } }

A tweak to make the above code more testable might be to pass in the current time, rather than generating it with each expiration_check call. Monitoring for certificate expiration with check-expire allows expiration monitoring, with configurable warning levels, and more.

November 20, 2006

The Cook’s Thesaurus

Try the Cook’s Thesaurus for a handy reference of ingredients and kitchen tools.

Technorati Tags: ,

November 19, 2006

Perl Dæmons

Wrote Running Perl Daemon Processes since perl daemon searches all somehow miss the perlipc documentation. If writing a service for Unix, ensure it runs properly in the background. Notably, many Java programs fail to daemonize, perhaps due to the platform specific nature of daemonization. Other random links:

Technorati Tags: ,

November 18, 2006

Programming Recommended Reading

Great programming Recommended Reading links put together by Limbic~Region.

Technorati Tags:

The Thinker’s Thesaurus

Speaking of execrable, The Thinker's Thesaurus offers excellent word choices (when you can find a match) along with great example uses of the word. Otherwise, nowhere near the depth of Roget’s Thesaurus.

November 16, 2006

Loop without Loop

Today’s installment of execrable Perl inspired by inexperienced coders asking koan-esque questions “how do I loop over something, but without looping over it?” Actual user question in this case turned out to be $ref->foo->foo->… iteration, which would require a slightly different recursive call. But this let me fiddle with &… prototypes to good effect.

#!/usr/bin/perl -w # Abuse recursion and so forth to # "loop without looping". use strict; # So don't need () and can specify # a sub-less sub. sub loop (&$;$); my @list = qw(a b c d); # No way known to specify @list, then # use reference in subsequent calls loop { print } \@list; sub loop (&$;$) { # Use @_ directly instead of named # variables as prototype disallows # repassing code ref (insists # on a block...) local $_ = $_[1]->[ $_[2]++ ]; eval { &{ $_[0] } }; if ($@) { # ed(1) style error messages :) die "!\n"; } $_[2] > $#{ $_[1] } || &loop; }

November 12, 2006

Pan Fried Gnocchi

Finally got around to making pan fried gnocchi as reported earlier. Used imported gnocchi, cranberry beans from the University Farmer’s Market, chanterelle mushrooms, shallot, grape seed oil, roma tomato, thyme, fresh ground white and black pepper, salt.

Tomato did not mix well flavor-wise (too high and sharp), so added some Zinfandel vinegar and cooked bit longer. Hard to taste mushrooms over the beans (cooked mushrooms too long?), gnocchi really picked up on the grape seed oil flavor. Need to try with olive oil instead, perhaps boil gnocchi briefly before frying. Also should try adding fresh ground pepper to oil while frying gnocchi, to let them absorb the spices better.

Not sure where to find fresh gnocchi in Seattle, or how much they would improve the dish. All in all, an excellent dish…

Technorati Tags:

November 09, 2006

Chess960 position generator

Wrote chess960open to generate Chess960 opening positions for White. Here’s one possibility:

Bishop Rook King Rook Knight Queen Knight Bishop

Technorati Tags:

November 06, 2006

Sending E-mail with Perl

Since so many coders invoke sendmail directly, never the wiser: sending e-mail with Perl.

Technorati Tags:

November 03, 2006

Sphere III

The previous two live elsewhere.

November 01, 2006

convert-date - match dates and perform TZ conversions

Quick Perl script to match dates in input data by regex, and convert between the specified time zones.

#!/usr/bin/perl -w # # Usage: convert-date < input > output use strict; use Date::Manip qw(UnixDate ParseDate Date_ConvTZ); # should be arguments my $from_tz = 'UTC'; my $to_tz = 'PDT'; my $output_format = '%Y-%m-%d %H:%M:%S'; while (<>) { # How to match the date in the input data. May # need to munge to something Date::Manip can # grok, or add HH:MM:SS, depending. s/ (\d{4}-\d\d-\d\d [T\s] \d\d:\d\d:\d\d) /fix_date($1)/ex; print; } sub fix_date { my $input = shift; my $date_in = ParseDate($input); warn "$0: error: could not parse: date=$input\n" if length $date_in < 1; my $date_out = Date_ConvTZ( $date_in, $from_tz, $to_tz ); warn "$0: error: could not convert: " . "date=$input, from=$from_tz, to=$to_tz\n" if length $date_out < 1; my $output = UnixDate( $date_out, $output_format ); return $output; }

Technorati Tags: ,