[SPOILER] Perl Quiz of the Week #24 (Turing Machine simulation)
Jimmy Selgen Nielsen <jse-0I578M6uKxnkQYj/[email protected]>
| Newsgroups | gmane.comp.lang.perl.qotw.discuss |
|---|---|
| Message-ID | <7858C99FF2E1C24BA3311BE8BEBE6A8E01D3A04F@limail.lint.lyngso-industri.dk> |
Wow .. Easier than I first thought :)
Here's my first QOTW post and try.
Decided to use a hash for the tape contents since it greatly simplifies the
"infinite tape" problem :)
Also not the shortest entry, but I gains on readability (or so I like to
think).
Credits : the by_number sort was stolen from "learning perl"
/Jimmy
-------------------------------------------------------------------------
#!/usr/bin/perl -w
use strict;
our(@ARGV);
my $tape_pos = 0;
my $state = undef;
my %state_trans;
my %tape_contents;
sub read_state_file{
my $fname = shift;
open(FILE,"<$fname") or die "Unable to open $fname";
while(<FILE>){
if(/^\s*(\S+)\s+(\w+)\s+(\S+)\s+(\w+)\s+([r|l|R|L])\s*(\#.*)?$/){
if(defined $state_trans{$1}{$2}){
#already defined state/value
die "state $1 value $2 already defined\n";
}else{
$state = $1 if(!defined $state);
$state_trans{$1}{$2} = [$3,$4,$5];
}
}elsif(/^$/){
#blank line, ignore
}else{
print STDERR "Illigal instruction : $_\n";
}
}
close(FILE);
}
sub parse{
my $n_tape_pos = 0;
my $n_state = undef;
STEP:for(;;){
$tape_contents{$tape_pos} = '_' if !defined
$tape_contents{$tape_pos};
last STEP if (!exists
$state_trans{$state}{$tape_contents{$tape_pos}});
#save new tape_pos and state for after we modify tape_contents
$n_tape_pos = $state_trans{$state}{$tape_contents{$tape_pos}}[2] eq
'L' ? -1 : 1;
$n_state = $state_trans{$state}{$tape_contents{$tape_pos}}[0];
#modify tape contents
$tape_contents{$tape_pos}=
$state_trans{$state}{$tape_contents{$tape_pos}}[1];
#set new state and tape position
$state = $n_state;
$tape_pos += $n_tape_pos;
}
}
sub by_number {
# a sort subroutine, expect $a and $b
if ($a < $b) { -1 } elsif ($a > $b) { 1 } else { 0 }
}
sub main{
die "nope .. not a file" if (!defined $ARGV[0]) or (! -f $ARGV[0]);
read_state_file($ARGV[0]);
$tape_contents{$tape_pos} = '_'; #initialize tape
if(defined ($ARGV[1])){
my $ctr = 0;
foreach my $c (split('',$ARGV[1])){
$tape_contents{$ctr++} = $c;
}
}
parse();
foreach my $c (sort by_number keys(%tape_contents)){
print "$tape_contents{$c}";
}
print "\n";
}
main()