[SPOILER] Perl Quiz of the Week #24 (Turing Machine simulation)

Abhinav Modi <[email protected]>
Newsgroups gmane.comp.lang.perl.qotw.discuss
Message-ID <[email protected]>
On Fri, 17 Sep 2004 03:43:05 +0700, Bill Tucker <[email protected]> wrote:
> I was a little surprised at how easy this was. I'd studied Turing
> machines in school, but had never actually implemented one.
> 

Same here !! :)

This is my first QOTW attempt, and Im happy that I could do it
"relatively" easily. (Apart from getting the Hash to work ;)

Here's my entry, and suggestions on the approach/ critiques welcome ..

Thanks
Abhinav
--------------------------------------------------------------------------------

#!/local/perl5.8/bin/perl
use strict;
use warnings;
#use Data::Dumper;

die "No File as input!" if (!$ARGV[0] or !-f $ARGV[0]);
die "Incorrect input string" if ($ARGV[1] and $ARGV[1] !~ /^\s*\w+\s*$/ );

my %table;
my %states;
my $sr;     # The State Register
my $tape="_________";   # The Tape
my $head;   # The Head;
my $curVal;
my $newVal;
my $dir;

$tape = $ARGV[1] if ($ARGV[1]);

initTable();
$tape = '_'. $tape;
$head=1;

while(1)
{
 $curVal=substr($tape,$head,1);
 #print $curVal . "\n";

 (
 $sr = $table{$sr}{$curVal}[0] and
 $newVal = $table{$sr}{csurVal}[1] and
 $dir = $table{$sr}{$curVal}[3]
 )||
 ( $tape =~ s/^_*(.*)$/$1/ and $tape =~ s/^(\w*?)_*$/$1/ and print
$tape."\n" and exit);
 substr($tape,$head,1,$newVal);
 $head += 1 if ($dir eq 'R');
 appendRight() if (! substr($tape,$head,1));
 $head -= 1 if ($dir eq 'L');
 appendLeft() if ($head <= 0);
}

sub initTable
{

 open(FH, "<$ARGV[0]") or die "Could not open tm file $ARGV[0] : $!";
 my @lines = <FH>;
 close (FH) or die "Could not close tm file $ARGV[0] : $!";
 my $stateCnt = 1;

 for (@lines)
 {
   chomp $_;
   (print "skipped $_ \n" && next) if (/^\s*$/ || /^\s*#.*/ );
   die "Incorrect file format: line $_"
         if (! /^\s*(\w+)\s+(\w)\s+(\w+)\s+(\w)\s+([LR])\s*.*$/i);
   $states{$1} = $stateCnt++ if (!$states{$1});
   $sr=$states{$1}  unless($sr);
   $states{$3} = $stateCnt++ if (!$states{$3});
   $table{$states{$1}}{$2} = [$states{$3},$4,uc($5)] if (!
$table{$states{$1}}{$2}) or
           die "More than 1 rule for same state/input" ;
 }
 #print Dumper(\%table);
}

sub appendLeft
{
$tape="_" x 10 . $tape;
$head += 10;
}

sub appendRight
{
$tape .= "_" x 10;
}

-----------------------------------------------------------------------------
> I catch one thing I think is an input error that didn't (unless I
> missed it) get mentioned in the problem statement - more than one
> line in the program for a given state/tape symbol.
> 
> Thanks, that was fun.
> 
> Bill
> 
> ---------------------------------------------------------------
> 
> #!/usr/bin/perl
> 
> use strict;
> 
> my (@tape, $tapePos, $state, %transitions, $filename, $new, $out, $move);
> 
> @tape = ();
> $tapePos = 0;
> %transitions = ();
> 
> sub parse_pgm
>      {
>      my $filename = shift;
>      my ($fh);
> 
>      open ($fh,"<$filename") or die "Couldn't open $filename";
> 
>      while (<$fh>)
>          {
>          /^\s*(#.*)?$/ and next; # Skip blank and comment lines
>          /^\s*(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+([LR])\s*(#.*)?$/i or
> die "Illegal line at line number $.: $_";
>          (defined($state)) or $state = $1;  # This inits the state to
> the first one in the pgm
>          (defined($transitions{$1}{$2})) and die "Stop confusing me!
> There are two program lines for state $1, tape value $2";
>          $transitions{$1}{$2} = { 'STATE'=>$3, 'VALUE'=>$4, 'MOVE'=>$5 };
>          }
>      close ($fh);
>      }
> 
> sub move
>      {
>      my $direction = shift;
> 
>      if (uc($direction) eq "L")
>          {
>          ($tapePos == 0) ? (unshift (@tape, '_')) : ($tapePos--);
>          }
>      else    # We made sure the direction was "L" or "R" when we parsed the pgm
>          {
>          (defined($tape[++$tapePos]))  or push (@tape, '_');
>          }
>      }
> 
> # Start of main
> 
> ($filename = shift) or die "You didn't give me a program file!";
> (@ARGV) ? (@tape = split('',shift)) : ($tape[$tapePos] = '_');
> 
> &parse_pgm($filename);
> 
> while (defined($transitions{$state}{$tape[$tapePos]}))
>      {
>      $new = $transitions{$state}{$tape[$tapePos]};
>      $state          = $new->{STATE};
>      $tape[$tapePos] = $new->{VALUE};
>      &move($new->{MOVE});
>      }
> 
> $out = join('',@tape);
> $out =~ s/^\_*(.*?)\_*$/$1/;
> print $out."\n";
> exit;
> 
> 



-- 
-------------
http://www.abhinavmodi.tk
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.