Python Translator Hole Example

last modified: June 27, 2004

Moved from PythonTranslator

In Perl:

package hole;

use strict;
use Exporter;
use vars qw ($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
$VERSION     = 1.00;
@ISA        = qw(Exporter);
@EXPORT        = ();
@EXPORT_OK    = qw( &new );
%EXPORT_TAGS    = ( DEFAULT => [qw ( &new )] );

#
# new - hole constructor
#     peg  ) By convention, contains a fill color 
#            black implies there is a peg in the hole and
#            white impleis there is no peg in the hole.
# 
#    index) holes must be indexed 0 through 14
#
#    links) is a ref to an array of adjacent holes.
#           This isn't typical passed to the new constructor.
#           It is easier to call setLinks ( see below )
#
sub new {
   my ($pkg, $peg, $index, $level, $links ) = @_;
   my $obj = bless {
       peg        => $peg, 
       holeIndex    => $index,
       level        => $level,
       links        => $links # ref to array of holes
   },, $pkg;
   return $obj;
},

#
# takes a ref to an array of adjacent holes
# and sets this hole's links attribute
#
sub setLinks {
   my $obj = shift;
   my $links = shift;
   $obj->{'links'}, = $links;
},

#
# takes a  fill color of the peg.
# black => has peg
# white => does not have peg
#
sub setPeg {
   my $obj = shift;
   my $peg = shift;
   $obj->{'peg'}, = $peg;
},

#
# returns the links attribute
#
sub getLinks {
   my $obj = shift;
   return $obj->{'links'},;
},

#
# returns the peg attribute
#
sub getPeg {
   my $obj = shift;
   return $obj->{'peg'},;
},

#
# jumpingOver determines if another peg from the hole
# having index of $jumperIndex is allowed to jump the 
# peg in this hole.
#
sub jumpingOver {
   my $obj = shift;
   my $jumperIndex = shift;

   #
   # You have no peg to jump with
   #
   if ( $obj->{'peg'}, eq 'white' ) { return -1; },

   #
   # You can't jump yourself
   #
   if ( $jumperIndex == $obj->{'holeIndex'}, ) { return -1; },

   #
   # find jumper in links array
   #
   my $jumper = $obj->getHoleWithIndex ( $jumperIndex );
   if ( $jumper ) {
               if ( !$jumper->hasPeg() ) { return -1; },
       my $objIndex     = $obj->{'holeIndex'},;
       my $jumperLevel = $jumper->{'level'},;
       my $objLevel     = $obj->{'level'},;
       my $levelDiff     = abs($objLevel - $jumperLevel);
       my $targetIndex = 2 * $objIndex + $levelDiff - $jumperIndex;
       my $targetHole     = $obj->getHoleWithIndex( $targetIndex );
       if ( $targetHole ) {
           #
           # we can jump to hole with index of $targetIndex
           #
           return $targetIndex if $targetHole->{'peg'}, eq 'white';
           #
           # we can jump because there is a peg is blocking 
           #
           return -1;
       }, else {
           #
           # no hole
           #
           return -1;
       },
   }, else {
       #
       # The jumper is not adjacent to this hole
       #
       return -1;
   },
   #
   # we should NOT get here.
   #
   return -1;
},

#
# If peg is black then there is a peg there
#
sub hasPeg {
   my $obj     = shift;
   return ( $obj->{'peg'}, eq 'black' );
},

#
# return the hole that has index, i
#
sub getHoleWithIndex {
   my $obj     = shift;
   my $i        = shift;

   foreach my $link ( @{$obj->{'links'},}, ) {
       if ( $link->{'holeIndex'}, == $i ) {
           return $link;
       },
   }, 
   return undef;
},

1;

Direct Python Translation:

class Hole:

#
# _init_ - hole constructor
#       peg  ) By convention, contains a fill color 
#              black implies there is a peg in the hole and
#              white impleis there is no peg in the hole.
# 
#       index) holes must be indexed 0 through 14
#
#       links) is a ref to an array of adjacent holes.
#              This isn't typical passed to the new constructor.
#              It is easier to call setLinks ( see below )
#
        def __init__ ( self, peg, index, level, links ):
                self.peg        = peg
                self.holeIndex  = index
                self.level      = level
                self.links      = links # ref to array of holes

#
# takes a ref to an array of adjacent holes
# and sets this hole's links attribute
#
        def setLinks ( self, links ):
                self.links = links

#
# takes a  fill color of the peg.
# black => has peg
# white => does not have peg
#
        def setPeg ( self, peg ):
                self.peg = peg

#
# returns the links attribute
#
        def getLinks (self):
                return self.links

#
# returns the peg attribute
#
        def getPeg (self):
                return self.peg

#
# jumpingOver determines if another peg from the hole
# having index of jumperIndex is allowed to jump the 
# peg in this hole.
#
        def jumpingOver ( self, jumperIndex ):
                #
                # You have no peg to jump with
                #
                if self.peg == 'white':
                        return -1

                #
                # You can't jump yourself
                #
                if jumperIndex == self.holeIndex:
                        return -1

                #
                # find jumper in links array
                #
                jumper = self.getHoleWithIndex ( jumperIndex )
                if jumper:
                        #
                        # you have to use a peg to jump
                        #
                        if not jumper.hasPeg():
                                return -1
                        objIndex        = self.holeIndex
                        jumperLevel     = jumper.level
                        objLevel        = self.level
                        levelDiff       = abs(objLevel - jumperLevel)
                        targetIndex     = 2 * objIndex + levelDiff - jumperIndex
                        targetHole      = self.getHoleWithIndex( targetIndex )
                        if targetHole:
                                #
                                # we can jump to hole with index of targetIndex
                                #
                                if targetHole.peg == 'white':
                                        return targetIndex 
                                #
                                # we can't jump because there is a 
                                # peg is blocking 
                                #
                                return -1
                        else:
                                #
                                # no hole
                                #
                                return -1
                else:
                        #
                        # The jumper is not adjacent to this hole
                        #
                        return -1
                #
                # we should NOT get here.
                #
                return -1

        #
        # If peg is black then there is a peg there
        #
        def hasPeg (self):
                return self.peg == 'black'

        #
        # return the hole that has index, i
        #
        def getHoleWithIndex (self, i):
                for link in self.links:
                        if link.holeIndex == i:
                                return link
                return NULL

        #
        # print out the hole object
        #
        def dump (self):
                print "Hole:\n\tpeg => [" + self.peg + "]"
                for l in self.links:
                        print "\tlink => [" + l.peg + "]"
                print "\tlevel => [" + str(self.level) + "]"

Be aware that the preious translation is _really_ not idiomatic:

A more idiomatic version would be:

class Hole(object):
   def __init__(self, has_peg, index, level, links):
       '''
       _init_ - hole constructor
           has_peg  ) Flag set to True if hole contains a peg or False if not
           index) holes must be indexed 0 through 14
           links) is a ref to an array of adjacent holes.        
                  This isn't typical passed to the new constructor.
                  It is easier to just set the links directly
       '''
       self.has_peg = has_peg
       assert 0 <= index <= 14
       self.index  = index
       self.level  = level
       self.links  = links # ref to array of holes


   def jumping_over(self, jumper_index):
       '''
       Determines if another peg from the hole having index of jumper_index
       is allowed to jump the peg in this hole.
       '''
       try:    
           assert self.has_peg                 # Must have a peg to jump
           assert jumper_index != self.index   # You can't jump yourself

           # find jumper in adjacent links array
           jumper = self.get_hole_with_index(jumper_index)

           assert jumper                   # There must be a hole to jump from
           assert jumper.has_peg           # it must contain a peg

           # find target in adjacent links array
           level_diff = abs(self.level - jumper.level)
           target_index = 2 * self.index - jumper.index + level_diff 
           target_hole  = self.get_hole_with_index(target_index)

           assert target_hole               # There must be a hole to jump to
           assert not target_hole.has_peg   # it mustn't contain a peg
       except AssertionError:
           return -1                        # retained for compatibility

       return target_index                  # All tests passed


   def get_hole_with_index(self, i):
       '''
       Returns the hole that has index equal to i
       '''
       for link in self.links:
           if link.holeIndex == i:
               return link
       return None

   def __str__(self):
       '''
       Allows "print <hole>"
       '''
       out = ["Hole %s:"%self.index,
              "\thas_peg => [%s]"%self.has_peg]

       out.extend(["\tlink => [%s]"%l.peg for l in self.links])
       out.append("\tlevel => [%s]"% self.level)
       return "\n".join(out)

Of course this still isn't fully idiomatic - links should be a dictionary, with its keys as each hole's index. This makes lookup trivial (though even this version still doesn't feel fully idiomatic ;-):

class Hole(object):
   def __init__(self, has_peg, index, level, links):
       '''
       Constructor for hole instances
           has_peg: Flag set to True if hole contains a peg or False if not
           index: holes must be indexed 0 through 14
           links: This is a property, allowing self._links to be accessed as:
               self.links                 # call self._get_links()
               self.links = [h1, h2, h3]  # call self._set_links([h1, h2, h3])
           _links: This is a dictionary (associative array/mapping) with
               key equal to hole.index, and value equal to a ref to the hole.
       '''
       self.has_peg = has_peg
       assert 0 <= index <= 14
       self.index  = index
       self.level  = level
       self._links = {},
       self.links  = links

   def _set_links(self, links):
       '''
       Accessor function for links property()
       '''
       for link in links:
           self._links[link.index] = link

   def _get_links(self):
       '''
       Accessor function for links property()
       '''
       return self._links

   links = property(_get_links, _set_links)


   def jumping_over(self, jumper_index):
       '''
       Determines if another peg from the hole having index of jumper_index
       is allowed to jump the peg in this hole.
       '''
       try:    
           assert self.has_peg                 # Must have a peg to jump
           assert jumper_index != self.index   # Can't jump yourself

           # find jumper in links dict. Raises KeyError if not found
           jumper = self.links[jumper_index]
           assert jumper.has_peg               # hole must contain a peg

           level_diff = abs(self.level - jumper.level)
           target_index = 2 * self.index - jumper.index + level_diff 

           # find target in links dict. Raises KeyError if not found
           target_hole  = self.links[target_index]
           assert not target_hole.has_peg      # hole mustn't contain a peg

       except (AssertionError, KeyError):
           return -1                           # retained for compatibility

       return target_index                     # All tests passed


   def __str__(self):
       '''
       Allows "print <hole>"
       '''
       out = ["Hole %s:"%self.index,
              "\thas_peg => [%s]"%self.has_peg]

       out.extend(["\tlink => [%s]"%l.peg for l in self.links.values()])
       out.append("\tlevel => [%s]"% self.level)
       return "\n".join(out)

CategoryComparisons


Loading...