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:
- Modern python doesn't use getters/setters except under the hood with property()
- It really should throw exceptions rather than returning -1 ... I'd probably use "assert self.peg == 'white'"
- For that matter, I'd use a flag for obj.has_peg instead of setting colours - it would clean up the code =)
- camelCase should be snake_case ;-)
- Comments should be docstrings
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)