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:
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)