[Rt-devel] RT DEVELOPER CHALLENGE: TOWER OF HANOI

Bron Gondwana brong at fastmail.fm
Mon Oct 25 21:47:24 EDT 2004


On Sat, 23 Oct 2004 03:33:20 -0400, "Jesse Vincent"
<jesse at bestpractical.com> said:
> Perhaps it's the fault of the delicious bottle of Port that a houseguest
> brought me, but I've got a challenge for the RT community. 
> 
> The first person to develop and document a solution to the famed Tower
> of Hanoi puzzle[1] using RT's Scrips system with queues modeling the
> rods, tickets modeling the disks and ticket relationships modeling the
> relative disk sizes will win a fabulous prize.[2]

I've made a couple of them, but they suck for various reasons. 
Basically
it's hard to make them sort correctly, because it takes forever if you
put
a 'sleep 1' in, but otherwise (at least with Mysql's dates) they don't
sort
properly.

Anyway, here's one that's pretty chatty, but gets the moves in the
correct
order txn-wise.

The Scrip:
===============================================================

Condition: On Comment

Action: User Defined

Prepration Code: (<< __EOF__)
my $comment = $self->TransactionObj->Content();

if ($comment =~ m/move to ([A-Za-z0-9_ ]+)/) {
  my $new_queue_match = lc($1);
  $new_queue_match =~ s/^\s+//;
  $new_queue_match =~ s/\s+$//;

  my $user = $self->TransactionObj->CurrentUser();
  my $old_queue_id = $self->TicketObj->Queue();

  # Find a third queue to use as temporary space for this move.
  my $queues = RT::Queues->new($user);
  $queues->UnLimit();
  my $queue_items = $queues->ItemsArrayRef;

  my %queue_names;
  my $temp_queue_id;
  my $new_queue_id;
  foreach my $item (@$queue_items) {
    my $id = $item->id;
    my $name = $item->Name;
    my $matchname = lc($name);
    $matchname =~ s/^\s+//;
    $matchname =~ s/\s+$//;
    $queue_names{$id} = $name;
    if ($id == $old_queue_id) {
      # nothing to do
    } elsif ($new_queue_match eq $matchname) {
      $new_queue_id = $id;
    } elsif (!$temp_queue_id) {
      $temp_queue_id = $id;
    }
  }

  # make sure a move is actually required (the case of trying to move to
  where
  # we already are will leave this blank as well)
  return 0 unless $new_queue_id;

  # the next smaller disk is our member.
  my $members = $self->TicketObj->Members->ItemsArrayRef;
  if (@$members) {
    # make sure there's spare space to move this thing!
    return 0 unless $temp_queue_id;
    my $child_obj = RT::Ticket->new($user);
    $child_obj->Load($members->[0]->LocalBase);
    if ($child_obj->Queue != $temp_queue_id) {
      $child_obj->Comment(Content => "move to
      $queue_names{$temp_queue_id}");
    }
    $self->TicketObj->SetQueue($new_queue_id);
    $child_obj->Comment(Content => "move to
    $queue_names{$new_queue_id}");
  } else {
    # no children, just move ourselves!
    $self->TicketObj->SetQueue($new_queue_id);
  }
  return 1;
}

return 0;
__EOF__

Cleanup Code: return 1;

Stage: TransactionCreate

===============================================================

How to use:

a) Have at least 3 queues available.
b) Create tickets with a Parent/Child relationship (Parent is the larger
disk)
c) Create a comment on the largest disk "move to <name of another
queue>".

All the other disks will be moved as appropriate.

NOTE: There is no concept of 'stacking' in RT queues, so the disks are
assumed to
be stacked correctly at the start since there's no way of detecting
otherwise.

The script won't move a disc until the immediately smaller disk is on
the a third
stack (not the source or destination of the first move) - and that
propagates up
to the top disk which has no children and hence can always move.

I still think this solution is rather ugly, but it works.

Bron.
-- 
  Bron Gondwana
  brong at fastmail.fm



More information about the Rt-devel mailing list