Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hello.

I have a task to model a gaming board of squares similar to an uncoloured chess board, only some squares can have walls at the border to their respective four neighbours. (There's also a complete wall along the physical border of the board surrounding the board.)

My current approach is to have each square be an object with the properties x, y, has_east_wall, has_west_wall, has_south_wall, has_north_wall.

I'm not happy with the design because I should not have to repeat that the north wall of a square exists and its northern neighbour's south wall, too. I am afraid to model wall changing without wrapping it into transactions so I do not have inconsistent data, but I feel it makes it all much too complicated. There must be something simpler, but I cannot think of anything.

PS: This is a homework question, so it's all right if you just give hints instead of full code.

Replies are listed 'Best First'.
Re: gaming board design
by moritz (Cardinal) on Oct 22, 2008 at 12:47 UTC
    Instead of attaching walls as properties to the squares, you can make them squares on their own. So
    |_|_|

    Would translate to

    # # # #####

    With 0-index arrays, all squares with even indexes are walls, and if you have players, they can only move in steps which are multiples of two.

Re: gaming board design
by dHarry (Abbot) on Oct 22, 2008 at 12:47 UTC

    In the past I modeled this like a graph, i.e. for each node define which other nodes can be accessed. A matrix of nodes is then your board. If you can’t access one node from the other there is a wall between them. I used it for simulating walking through a labyrinth.

    board 0 1 2 3 4 5 6 7 8 0 -> 3 1 -> 4 2 -> 5 3 -> 0 3 -> 4 3 -> 6 etc.

    In my experience the implementation of the board is influenced by what you want to do with it, i.e. the complexity of the game. Often you want some efficient internal representation. The presentation would be another layer.

    HTH

Re: gaming board design
by JavaFan (Canon) on Oct 22, 2008 at 13:30 UTC
    Easy. Just store for each square whether it has a south wall and wether it has a east wall. If you want to know whether a square has a north wall, just test to see it its north neighbour has a south wall (just be sure it has a neighbour to its north, otherwise it's on the border - of course, to make programming easier (at least, in some aspects) you could make an extra row of cells on the north and west sides). Similar for a west wall: just ask your neighbour on the west if it has an east wall.
Re: gaming board design
by zentara (Cardinal) on Oct 22, 2008 at 13:40 UTC
    Here is a Tk script that may help you. You can play with the rectangle edges by adjusting the outline color, and possibly using premade square images . I won't help you anymore, since it's homework. :-) Read perldoc Tk::Canvas and google for "perl tk chessboard"
    #!/usr/bin/perl -w use strict; use Tk; # by Jack D. improving on some code of mine my ($x, $y); my $iconSize = 20; my ($width, $height) = (10, 10); my ($canvasWidth, $canvasHeight) = ($iconSize+$width*$iconSize, $iconSize+$height*$iconSize); my $w = $canvasWidth+$iconSize; my $h = $canvasHeight+$iconSize; my $MW = MainWindow->new; $MW->geometry($w.'x'.$h); my $MF = $MW->Frame->pack; my $c = $MF->Canvas( -width => $canvasWidth, -height => $canvasHeight )->pack; for ($y = $iconSize; $y < $canvasHeight; $y+=$iconSize) { for ($x = $iconSize; $x < $canvasWidth; $x+=$iconSize) { $c->createRectangle ($x, $y, $x+$iconSize, $y+$iconSize, -fill => '#AFAFAF', -activefill => '#CFCFCF', -tags=>['rect',"row.$y", "col.$x"] ); } } $c->bind('rect', '<Enter>', \&enter ); $c->bind("rect", "<Leave>", \&leave ); MainLoop; sub findtag { my ($canv) = @_; my $id = $canv->find('withtag', 'current'); my @tags = $canv->gettags($id); my ($row) = ( grep /^row\d*/, @tags ); my ($col) = ( grep /^col\d*/, @tags ); return ($row,$col); } sub enter { my ($canv) = @_; my ($r,$c) = findtag($canv); $canv->itemconfigure($r, -fill=>$canv->itemcget($r,-activefill)); $canv->itemconfigure($c, -fill=>$canv->itemcget($c,-activefill)); } sub leave{ my ($canv) = @_; $canv->itemconfigure('rect', -fill=>'#AFAFAF'); # note replaced 'all' with 'rect' above - just in case there are oth +er canvas items :-) } __END__

    I'm not really a human, but I play one on earth Remember How Lucky You Are
Re: gaming board design
by zentara (Cardinal) on Oct 22, 2008 at 16:19 UTC
    Just for fun, here is an actual board with nice images. Left and right mouse clicks, will select/deselect a square. Sometimes a little demo can spur your imagination.
    #!/usr/bin/perl use warnings; use strict; use Tk; use Tk::JPEG; my @oddrow = qw(d l d l d l d l); my @evenrow = qw(l d l d l d l d); #inline base64_encoded images are 70 x 70 my ($cWidth, $cHeight) = (8 * 70, 8*70); my $w = $cWidth + 70; my $h = $cHeight + 70; my $mw = MainWindow->new; $mw->geometry($w.'x'.$h); my $c = $mw->Canvas( -bg => 'lightsteelblue', -width => $cWidth + 140, -height => $cHeight + 140)->pack; my $dimage = $mw->Photo(-data => get_dark() ); my $limage = $mw->Photo(-data => get_light() ); my %marker; my %square; foreach my $row(1..8){ my @template; if($row % 2){ @template = @oddrow }else{ @template = @evenrow }; foreach my $col (1..8) { my $image; my $colortag = shift @template; if ($colortag eq 'd'){$image = $dimage}else{$image = $limage} $square{$row}{$col} = $c->createImage ($row * 70 , $col *70, -image => $image, -tags=>['square', $colortag ,"row.$col", "col.$row"] ); # row col hack to make everything "normal" :-) $marker{$row}{$col} = $c->createRectangle( $row * 70 - 9, $col *70 -9 , $row * 70 + 9, $col *70 + 9, -fill=>'lightyellow', -tags => ['rect', $colortag ,"row.$col", "col +.$row"], ); } } $c->lower('rect','square'); #hide the rects under the squares $c->bind('square', '<Button-1>', \&click ); $c->bind('square', '<Button-3>', \&clickout ); $c->bind('rect', '<Button-3>', \&clickout ); MainLoop; sub findtag { my ($canv) = @_; my $id = $canv->find('withtag', 'current'); my @tags = $canv->gettags($id); print "@tags\n"; my ($r) = ( grep /^row\d*/, @tags ); my ($c) = ( grep /^col\d*/, @tags ); my($row)= $r =~ /(\d+)/; my($col)= $c =~ /(\d+)/; print "$row $col\n"; return ($id,$row,$col); } sub click{ my ($canv) = @_; my ($id,$row,$col) = findtag($canv); print "$row $col clicked\n"; $canv->raise($marker{$col}{$row},$square{$col}{$row}); } sub clickout{ my ($canv) = @_; my ($id,$row,$col) = findtag($canv); print "$row $col clickedout\n"; $canv->raise($square{$col}{$row}); } sub get_dark{ return '/9j/4AAQSkZJRgABAQEASABIAAD//gAXQ3JlYXRlZCB3aXRoIFRoZSBHSU1Q/+EAFkV4a +WYAAE1N ACoAAAAIAAAAAAAA/9sAQwAFAwQEBAMFBAQEBQUFBgcMCAcHBwcPCwsJDBEPEhIRDxEREx +YcFxMU GhURERghGBodHR8fHxMXIiQiHiQcHh8e/9sAQwEFBQUHBgcOCAgOHhQRFB4eHh4eHh4eHh +4eHh4e Hh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4e/8AAEQgARgBGAwEiAAIRAQ +MRAf/E ABoAAAMBAQEBAAAAAAAAAAAAAAADBAIBBQj/xAAsEAACAgEEAQIFBAMBAAAAAAABAgMRAA +QSITFB UWEFEyJxkSMygbFCocFS/8QAGwEAAgMAAwAAAAAAAAAAAAAAAgMAAQQFBgf/xAAdEQACAw +EBAAMA AAAAAAAAAAAAAQIRITESA0JR/9oADAMBAAIRAxEAPwD55B3Exn0B4yvUIEhRX6H1d+uZEL +DUMoAL dE3lk0KyRhS1MFvj28Z1Zy1UejMim2HTxkbrUsDZyF5doZVJ+2NllEmilVQPoYGx75PGtA +EnkgfU Tj4Rrov0NcfM0kw6oqSAfaskCqpUqb9eMuQ/pzgUSYzdfcZApcUSvqKOMWgNlOuffINnCu +ASfXEx Mx007KLA28nrvNbTLsWgdhI548XiUcrFIrHtTS4aiLcjSuzi/wCsM5CzeRQrisMqij3J2A ++JOeeD Yxe8pqlJfgmvznC9ymSibW7/AIyaeT9aJlWlFH+cyxWmmTJ42KRzRGzXf5zDghI+RtINHx +jJQV1c oLdsbv3zsyLSxV+w9V4zTaFoNE6oJPq7jPJ6JxKEzEItCs3o0LTpuWkDAf8AMxuA1Xy416 +bbfnvL orjEPKYpfoNm7zmo2xTHnsX/AB3mJo3SVgP8Tz+cPi7A6ukr9qix9sdFCXg2Fz8sbaA98M +XptwTb tPHrhgtCrPZgJQspPis3KVGnDVyrePtmQL1JX/yCW++a1Vto3ANbdpNf7zElpyMqFTANMW +LVvUf1 nZ3X5qkA0yjrFFS0QIIPAq8dAEMahqsxlb9DhpgURlnGoKx2PrBH5xblo9Y/RKtZOZ+YTJ +YHJOMn iK6tixXwSAeDjk6FyZJr5HOqddtCyePfCSGTfGzglqAb/mW6mNX+KVGqlmI765zMyyhEmM +lOpA2e Mb6XBXm3pNIkt8sp9h4wz1VgVE3bRIzHn2wxT+YLwjehBfUSDfyyE2MEG+R4yKXaaOGicR +uZGBKA 0cxLKIZnCgWOqzPtmli/mAbVr1sZzTNv10UQs3x+cbJscRSkMe7v1GS6eQHXq/IG7v05xk +UiVgg2 HKgXXf5xohkklUsSNx9c46AaiUruI3kC8oikqUbjwR3hyf4D0zK0cOtXddihx5IyKR2Mrq +R+1/P3 yj4kd2pLhSACDfti50Vp3ok7yeffDjXm2JeSpFWllV0IkYCj64YnRxJEpOwsT3eGKajYWl +jtt0xP g81i/iSkagEULjVuPthhgwGrowgPoIQLFE5Pp1UqGN4YZIkfB84VZHVbpzZvErEBJ2eMMM +sFHTGJ HKknmM/6xWlhDo/NbaYf1hhjFwD7HpCJABx2LwwwzI2NP//Z'; } sub get_light{ return '/9j/4AAQSkZJRgABAQEAlgCWAAD/4QAWRXhpZgAATU0AKgAAAAgAAAAAAAD/2wBDAAUDB +AQEAwUE BAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJB +weHx7/ 2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh +4eHh4e Hh4eHh4eHh4eHh7/wAARCABGAEYDASIAAhEBAxEB/8QAGgAAAwEBAQEAAAAAAAAAAAAAAA +IDBAEF B//EADIQAAIBAwMCAwUIAwEAAAAAAAECEQADIQQSMUFRBRMiFDJhccEkQoGRobHR8DRSc+ +H/xAAa AQEBAQEBAQEAAAAAAAAAAAADAgEABAYH/8QAJBEAAgICAQMEAwAAAAAAAAAAAAECEQMhEh +MxUQQU QVIyQpH/2gAMAwEAAhEDEQA/APtFo3LtpG9r1RzGL7/zXblq9tJGp1YH/dx9a0aayotLjo +Ovb9a0 MPSQOGM84r8zeSb3yZ9PJxUuxg9m1JQMus1ZA6jUP+0/tXW02rBC+16xt2QRqX/mt9tdpE +Lg8DtT 3DHvCCeBzH8Vrnkr8mTzV6R5Vy1qbXqGq1qmADOpeCZ+eK41vUDZ9r1ixg/aHwfzrfq2Bt +ghpIWY BrJqLjG0pKY3CQKnq5F+zEik12Bg5bcNTqSVOANQ+f1qNtntt/lazg86hyQJ+dUeGaSu05 +xH1pD/ ALKWx8aN+oyfZiLHHwAJuXGS5rNWAMhjfuAH5eoUUAgMxYJBPac0VXucn2f9N6UfBfS+Yb +aknG0c fvV2LhhJiRB+hqViGFoghfTEHmr3VhQ04BwYma6gpNNjIXImQAYMdzS30dlJBIWOvNIhLC +FPGIPM 1a4dm0K8mR1xNUtoNqnoy6q2zIoZfUB0rPuDW9o97mJyela7z2wRIPaOlQICj19JBxP9+d +HKx4uk ADbpPGSZEVNY8wgHIP3frVWbfDTkYxwalcZdwECWEY7ij4/JUWyJJLnacfrRVSqKN7APOM +xNFcoi Wh9LcZ7VkkhhtBjqMVuUgp70QPdrJ4ZbD+G6ZpJ9AkEZ4rfbFlh6/lkV6Iq+55MjVkiGck +A4nPQ5 qvloEBOIPPemW2IkCDkTM9asuxbcAA7es1SQM5mV7W9htIO0yD0rhshQThYB/CrWwA7FZB +PEVBgo ukMxkAzFc1ouLZn2rBLYBM/jS30QsWXkHOKtJltsQekc1K6LhAPIEzRVoaL2TDEHIUmB73 +NFduKS BAkHMgTRUl6H8Jtk+HWTBnaDBPIq9pPSm5iY5isPgGqa74Za2wYXIIrfaYBp7n8qddrCyX +yZVVKh WlgPnigMJ2loJOfhXHcQQSAvU9RQqhnKyNvQd65BJKthY2s7KWmBGeD8aXVIm5WbBBgR0q +toDeYY Hv3FJq9hKhSCZkGOta2qOTfISAHTzDDR37UmpI2gjBUEkgcgUXYJQk+ocfCo37jG1IM7Zg +x/YqPg VJtir5ySQGAMEADvRSXXeRLlcDAOKKnQtM83w7Wey6VLIthmT7081p9tYF32e6cweaKKZR +Rs3tlB rUch/LYSdpzmg+IlbxRkJAmCDniaKKrig2OviADqDazPINLe8QDMFNv3TzOeaKK1xRJK74 +gRcQFJ hoGelP7Sz2SPLGCQPV/5RRWvHHwWjK3iBVRtUzAmT8KKKKzpx8FWf//Z'; } __END__

    I'm not really a human, but I play one on earth Remember How Lucky You Are
Re: gaming board design
by dragonchild (Archbishop) on Oct 22, 2008 at 14:58 UTC
    You really want to use a graph here. Graphs also provide some other benefits, such as being able to ask "Where can a knight go?" and have it be pretty simple to implement.

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?