Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Memory Game 1

Status
Not open for further replies.

AMiSM

Technical User
Jan 26, 2006
128
US
Hi, all!
For your review, I have posted a game I wrote to improve visual memory. ( It seems that visual memory is at the root of all learning, together with emotion. ) Blue is correct placement, red is incorrect placement, and white is non-placement. As one gets better, the array should be increased ( with the individual boxes reduced ) in size.

It works, but the code is hideous, I'm sure, particularly how the array of buttons is put together. I'm interested in what can be learned through this. If you know how it can be optimized without obfuscation, please post!

Code:
use Tk;

my $mw = MainWindow->new;
$mw->title('Recreate the Pattern of X\'s');

$f = $mw->fontCreate( -family => "Verdana", -size => 50);
$h = 1;
$w = 2;
$n = 35;

$enter = $mw->Button(-height=>$h/2)->grid(-row=>0,-column=>0,-columnspan=>7,-sticky=>"nsew");

push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>1,-column=>1));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>1,-column=>2));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>1,-column=>3));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>1,-column=>4));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>1,-column=>5));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>1,-column=>6));

push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>2,-column=>1));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>2,-column=>2));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>2,-column=>3));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>2,-column=>4));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>2,-column=>5));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>2,-column=>6));

push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>3,-column=>1));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>3,-column=>2));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>3,-column=>3));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>3,-column=>4));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>3,-column=>5));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>3,-column=>6));

push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>4,-column=>1));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>4,-column=>2));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>4,-column=>3));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>4,-column=>4));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>4,-column=>5));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>4,-column=>6));

push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>5,-column=>1));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>5,-column=>2));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>5,-column=>3));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>5,-column=>4));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>5,-column=>5));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>5,-column=>6));

push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>6,-column=>1));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>6,-column=>2));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>6,-column=>3));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>6,-column=>4));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>6,-column=>5));
push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>6,-column=>6));

$enter -> configure ( -text => "New Pattern", -command => \&new_pattern );
foreach ( @button ) { $_ -> configure ( -text => "", -font=> $f ); }
foreach ( 0..$n ) { $random[$_] = 0 }
foreach ( 0..$n ) { $entry[$_] = 0 }

MainLoop;

sub new_pattern {
	$enter -> configure ( -text => "Start", -command => \&start );
	foreach ( 0..$n ) { $random[$_] = 0 }
	foreach ( 0..$n ) { $entry[$_] = 0 }
	for ( 1..10 ) { $random[rand($n)]=1 }
	foreach ( 0..$n ) {
		$button[$_] -> configure ( -text => "", -foreground => "black", -command => \&park );
		if ( $random[$_]==1 ){
			$button[$_] -> configure ( -text => "X", -foreground => "black" );
			}
		}
}

sub start {
	$enter -> configure ( -text => "Check Answer", -command => \&check_answer );
	foreach ( 0..$n ) { $button[$_] -> configure ( -text => "", -command => [\&choose, $_] ); }
}

sub choose {
	$i=$_[0];
	if ( $entry[$i]==0 ) {
		$entry[$i]=1;
		$button[$i] -> configure ( -text => "X" );
	} else {
		$entry[$i]=0;
		$button[$i] -> configure ( -text => "" );
	}
}

sub check_answer {
	$enter -> configure ( -text => "New Pattern", -command => \&new_pattern );
	foreach ( 0..$n ) {
		$button[$_] -> configure ( -text => "", -foreground => "black", -command => \&park );
		if ( $random[$_]==1 && $entry[$_]==1){
			$button[$_] -> configure ( -text => "X", -foreground => "blue" );
		}elsif ( $random[$_]==1 && $entry[$_]==0){
			$button[$_] -> configure ( -text => "X", -foreground => "white" );
		}elsif ( $random[$_]==0 && $entry[$_]==1){
			$button[$_] -> configure ( -text => "X", -foreground => "red" );
		}else{}
	}
}

sub park {}
 
As far as your buttons go, consider nested loops.

Code:
my ($x,$y) = (0,0);
while (1) {
   $x++;
   for ($y = 1; $i <= 6; $y++) {
      push (@buttons,$mw->Button (-height => $h,
         -width => $w)->grid (-row => $x, -column => $y));
   }
   last if $x == 6;
}

(note: not tested. may have to adjust the <= and == things with $x/$y)

The rest of your code looks pretty efficient though. :)

-------------
Cuvou.com | My personal homepage
Project Fearless | My web blog
 
Oops, typo:

Code:
   for ($y = 1; [COLOR=red]$i[/color] <= 6; $y++) {
   for ($y = 1; [COLOR=blue]$y[/color] <= 6; $y++) {

You could actually also replace the outer while loop with a similar for loop with $x, but imho its sometimes easier to debug when you use a while loop, cuz then it can only make too many buttons rather than not make enough and then you're wondering where it went wrong.

-------------
Cuvou.com | My personal homepage
Project Fearless | My web blog
 

I think I tried the nested loops before, but they didn't work right. Worked ok this time.

Code:
for ( $x=1; $x<=$g; $x++ ) {
	for ( $y=1; $y<=$g; $y++ ) {
		push(@button,$mw->Button(-height=>$h,-width=>$w)->grid(-row=>$x,-column=>$y));
	}
}

I figure since the for loops describe two different directions, it wouldn't be so bad debugging.
 
BTW, is ther an advantage to declaring variables, "my" or otherwise before "for" loops? I would think that they would be destroyed after the end of the for loop.
 
That is the whole point AMiSM (do you have a name?). Global variables are bad, they should be used as little as possible. Lexical variables are good. Nearly all your perl programs should begin with strict and warnings turned on:

use strict;
use warnings;

then you should declare your variables as needed in the script.

------------------------------------------
- Kevin, perl coder unexceptional! [wiggle]
 
Note, I've never done any Tk programming before, but here is how I would suggest you initially clean up your code:

Code:
[url=http://perldoc.perl.org/functions/use.html][black][b]use[/b][/black][/url] [green]Tk[/green][red];[/red]

[black][b]use[/b][/black] [green]strict[/green][red];[/red]

[gray][i]# Constants:[/i][/gray]
[url=http://perldoc.perl.org/functions/my.html][black][b]my[/b][/black][/url] [blue]$height[/blue] = [fuchsia]1[/fuchsia][red];[/red]
[black][b]my[/b][/black] [blue]$width[/blue] = [fuchsia]2[/fuchsia][red];[/red]
[black][b]my[/b][/black] [blue]$rows[/blue] = [fuchsia]6[/fuchsia][red];[/red]
[black][b]my[/b][/black] [blue]$cols[/blue] = [fuchsia]6[/fuchsia][red];[/red]

[black][b]my[/b][/black] [blue]$mw[/blue] = MainWindow->[maroon]new[/maroon][red];[/red]
[blue]$mw[/blue]->[maroon]title[/maroon][red]([/red][red]'[/red][purple]Recreate the Pattern of X[purple][b]\'[/b][/purple]s[/purple][red]'[/red][red])[/red][red];[/red]

[black][b]my[/b][/black] [blue]$font[/blue] = [blue]$mw[/blue]->[maroon]fontCreate[/maroon][red]([/red]
	-[purple]family[/purple]  => [red]"[/red][purple]Verdana[/purple][red]"[/red],
	-[purple]size[/purple]    => [fuchsia]25[/fuchsia],
[red])[/red][red];[/red]

[black][b]my[/b][/black] [blue]$enter[/blue] = [blue]$mw[/blue]->[maroon]Button[/maroon][red]([/red]
	-[purple]height[/purple]     => [blue]$height[/blue]/[fuchsia]2[/fuchsia],
[red])[/red]->[maroon]grid[/maroon][red]([/red]
	-[purple]row[/purple]        => [fuchsia]0[/fuchsia],
	-[purple]column[/purple]     => [fuchsia]0[/fuchsia],
	-[purple]columnspan[/purple] => [fuchsia]7[/fuchsia],
	-[purple]sticky[/purple]     => [red]"[/red][purple]nsew[/purple][red]"[/red],
[red])[/red][red];[/red]
[blue]$enter[/blue]->[maroon]configure[/maroon][red]([/red]
	-[purple]text[/purple]       => [red]"[/red][purple]New Pattern[/purple][red]"[/red],
	-[purple]command[/purple]    => \[maroon]&new_pattern[/maroon],
[red])[/red][red];[/red]

[black][b]my[/b][/black] [blue]@button[/blue][red];[/red]
[black][b]my[/b][/black] [blue]@random[/blue][red];[/red]
[black][b]my[/b][/black] [blue]@entry[/blue][red];[/red]
[olive][b]for[/b][/olive] [black][b]my[/b][/black] [blue]$row[/blue] [red]([/red][fuchsia]1..[/fuchsia][blue]$rows[/blue][red])[/red] [red]{[/red]
	[olive][b]for[/b][/olive] [black][b]my[/b][/black] [blue]$col[/blue] [red]([/red][fuchsia]1..[/fuchsia][blue]$cols[/blue][red])[/red] [red]{[/red]
		[black][b]my[/b][/black] [blue]$button[/blue] = [blue]$mw[/blue]->[maroon]Button[/maroon][red]([/red]
			-[purple]height[/purple] => [blue]$height[/blue],
			-[purple]width[/purple]  => [blue]$width[/blue],
		[red])[/red]->[maroon]grid[/maroon][red]([/red]
			-[purple]row[/purple]    => [blue]$row[/blue],
			-[purple]column[/purple] => [blue]$col[/blue],
		[red])[/red][red];[/red]
		[blue]$button[/blue]->[maroon]configure[/maroon][red]([/red]
			-[purple]text[/purple]   => [red]"[/red][purple][/purple][red]"[/red],
			-[purple]font[/purple]   => [blue]$font[/blue],
		[red])[/red][red];[/red]
		[url=http://perldoc.perl.org/functions/push.html][black][b]push[/b][/black][/url] [blue]@button[/blue], [blue]$button[/blue]
	[red]}[/red]
[red]}[/red]

MainLoop[red];[/red]

[url=http://perldoc.perl.org/functions/sub.html][black][b]sub[/b][/black][/url] [maroon]new_pattern[/maroon] [red]{[/red]
	[blue]$enter[/blue]->[maroon]configure[/maroon][red]([/red]
		-[purple]text[/purple]     => [red]"[/red][purple]Start[/purple][red]"[/red],
		-[purple]command[/purple]  => \[maroon]&start[/maroon],
	[red])[/red][red];[/red]
	
	[blue]@random[/blue] = [blue]@entry[/blue] = [red]([/red][fuchsia]0[/fuchsia][red])[/red] x [blue]@button[/blue][red];[/red]
	[blue]$random[/blue][red][[/red][url=http://perldoc.perl.org/functions/int.html][black][b]int[/b][/black][/url] [url=http://perldoc.perl.org/functions/rand.html][black][b]rand[/b][/black][/url][red]([/red][blue]@random[/blue][red])[/red][red]][/red] = [fuchsia]1[/fuchsia] [olive][b]for[/b][/olive] [red]([/red][fuchsia]1..10[/fuchsia][red])[/red][red];[/red]
	
	[olive][b]foreach[/b][/olive] [black][b]my[/b][/black] [blue]$i[/blue] [red]([/red][fuchsia]0..[/fuchsia][blue]$#button[/blue][red])[/red] [red]{[/red]
		[blue]$button[/blue][red][[/red][blue]$i[/blue][red]][/red]->[maroon]configure[/maroon][red]([/red]
			-[purple]text[/purple]        => [red]"[/red][purple][/purple][red]"[/red],
			-[purple]foreground[/purple]  => [red]"[/red][purple]black[/purple][red]"[/red],
			-[purple]command[/purple]     => \[maroon]&park[/maroon],
		[red])[/red][red];[/red]
		
		[olive][b]if[/b][/olive] [red]([/red][blue]$random[/blue][red][[/red][blue]$i[/blue][red]][/red] == [fuchsia]1[/fuchsia][red])[/red] [red]{[/red]
			[blue]$button[/blue][red][[/red][blue]$i[/blue][red]][/red]->[maroon]configure[/maroon][red]([/red]
				-[purple]text[/purple]       => [red]"[/red][purple]X[/purple][red]"[/red],
				-[purple]foreground[/purple] => [red]"[/red][purple]black[/purple][red]"[/red],
			[red])[/red][red];[/red]
		[red]}[/red]
	[red]}[/red]
[red]}[/red]

[black][b]sub[/b][/black] [maroon]start[/maroon] [red]{[/red]
	[blue]$enter[/blue]->[maroon]configure[/maroon][red]([/red]
		-[purple]text[/purple]     => [red]"[/red][purple]Check Answer[/purple][red]"[/red],
		-[purple]command[/purple]  => \[maroon]&check_answer[/maroon],
	[red])[/red][red];[/red]
	
	[olive][b]for[/b][/olive] [black][b]my[/b][/black] [blue]$i[/blue] [red]([/red][fuchsia]0..[/fuchsia][blue]$#button[/blue][red])[/red] [red]{[/red]
		[blue]$button[/blue][red][[/red][blue]$i[/blue][red]][/red]->[maroon]configure[/maroon][red]([/red]
			-[purple]text[/purple]     => [red]"[/red][purple][/purple][red]"[/red],
			-[purple]command[/purple]  => [red][[/red]\[maroon]&choose[/maroon], [blue]$i[/blue][red]][/red],
		[red])[/red][red];[/red]
	[red]}[/red]
[red]}[/red]

[black][b]sub[/b][/black] [maroon]choose[/maroon] [red]{[/red]
	[black][b]my[/b][/black] [blue]$i[/blue] = [url=http://perldoc.perl.org/functions/shift.html][black][b]shift[/b][/black][/url][red];[/red]
	
	[olive][b]if[/b][/olive] [red]([/red][blue]$entry[/blue][red][[/red][blue]$i[/blue][red]][/red] == [fuchsia]0[/fuchsia][red])[/red] [red]{[/red]
		[blue]$entry[/blue][red][[/red][blue]$i[/blue][red]][/red] = [fuchsia]1[/fuchsia][red];[/red]
		[blue]$button[/blue][red][[/red][blue]$i[/blue][red]][/red]->[maroon]configure[/maroon][red]([/red]-[purple]text[/purple] => [red]"[/red][purple]X[/purple][red]"[/red][red])[/red][red];[/red]
		
	[red]}[/red] [olive][b]else[/b][/olive] [red]{[/red]
		[blue]$entry[/blue][red][[/red][blue]$i[/blue][red]][/red] = [fuchsia]0[/fuchsia][red];[/red]
		[blue]$button[/blue][red][[/red][blue]$i[/blue][red]][/red]->[maroon]configure[/maroon][red]([/red]-[purple]text[/purple] => [red]"[/red][purple][/purple][red]"[/red][red])[/red][red];[/red]
	[red]}[/red]
[red]}[/red]

[black][b]sub[/b][/black] [maroon]check_answer[/maroon] [red]{[/red]
	[blue]$enter[/blue]->[maroon]configure[/maroon][red]([/red]
		-[purple]text[/purple]    => [red]"[/red][purple]New Pattern[/purple][red]"[/red],
		-[purple]command[/purple] => \[maroon]&new_pattern[/maroon],
	[red])[/red][red];[/red]
	
	[olive][b]foreach[/b][/olive] [black][b]my[/b][/black] [blue]$i[/blue] [red]([/red][fuchsia]0..[/fuchsia][blue]$#button[/blue][red])[/red] [red]{[/red]
		[blue]$button[/blue][red][[/red][blue]$i[/blue][red]][/red]->[maroon]configure[/maroon][red]([/red]
			-[purple]text[/purple]       => [red]"[/red][purple][/purple][red]"[/red],
			-[purple]foreground[/purple] => [red]"[/red][purple]black[/purple][red]"[/red],
			-[purple]command[/purple]    => \[maroon]&park[/maroon],
		[red])[/red][red];[/red]
		
		[black][b]my[/b][/black] [blue]$foreground[/blue] = [blue]$random[/blue][red][[/red][blue]$i[/blue][red]][/red] == [fuchsia]1[/fuchsia] && [blue]$entry[/blue][red][[/red][blue]$i[/blue][red]][/red] == [fuchsia]1[/fuchsia] ? [red]'[/red][purple]blue[/purple][red]'[/red]
			: [blue]$random[/blue][red][[/red][blue]$i[/blue][red]][/red] == [fuchsia]1[/fuchsia] && [blue]$entry[/blue][red][[/red][blue]$i[/blue][red]][/red] == [fuchsia]0[/fuchsia] ? [red]'[/red][purple]white[/purple][red]'[/red]
			: [blue]$random[/blue][red][[/red][blue]$i[/blue][red]][/red] == [fuchsia]0[/fuchsia] && [blue]$entry[/blue][red][[/red][blue]$i[/blue][red]][/red] == [fuchsia]1[/fuchsia] ? [red]'[/red][purple]red[/purple][red]'[/red]
			: [olive][b]next[/b][/olive][red];[/red]
			
		[blue]$button[/blue][red][[/red][blue]$i[/blue][red]][/red]->[maroon]configure[/maroon][red]([/red]
			-[purple]text[/purple]       => [red]"[/red][purple]X[/purple][red]"[/red],
			-[purple]foreground[/purple] => [blue]$foreground[/blue],
		[red])[/red][red];[/red]
	[red]}[/red]
[red]}[/red]

[black][b]sub[/b][/black] [maroon]park[/maroon] [red]{[/red][red]}[/red]
[tt]------------------------------------------------------------
Pragmas (perl 5.8.8) used :
[ul]
[li]strict - Perl pragma to restrict unsafe constructs[/li]
[/ul]
Other Modules used :
[ul]
[li]Tk[/li]
[/ul]
[/tt]

Otherwise, neat test. This reminds me of a recent slashdot article about monkeys scoring better than college students at memory:

Chimps Outscore College Students on Memory Test

- Miller
 
That looks pretty sharp, Miller! Can you explain this bit, please:

@random = @entry = (0) x @button;
$random[int rand(@random)] = 1 for (1..10);

The first line seems to be just zero being the result of using a non-number in a numeric statement, right? The second line, however, kinda throws me. What is this usage of "for"? I just want to make sure I understand what I think I'm seeing.
 
The first line uses the Repitition operator to create an array of 0's the size of the @button array.

The second line is just using an alternative syntax for 'for', to initialize 10 random entires to 1 (with possibly repitition). I should note that your previous code had a bug where the last button would never be given an X. That is because rand does not include the last number as a possible output. So to get an integer from 0 to 35, one must take the rand of 36.

Also, my coffee has finally hit, so I've noticed that your choose sub could be condensed a little bit:

Code:
[url=http://perldoc.perl.org/functions/sub.html][black][b]sub[/b][/black][/url] [maroon]choose[/maroon] [red]{[/red]
	[url=http://perldoc.perl.org/functions/my.html][black][b]my[/b][/black][/url] [blue]$i[/blue] = [url=http://perldoc.perl.org/functions/shift.html][black][b]shift[/b][/black][/url][red];[/red]

	[blue]$entry[/blue][red][[/red][blue]$i[/blue][red]][/red] ^= [fuchsia]1[/fuchsia][red];[/red]
	
	[blue]$button[/blue][red][[/red][blue]$i[/blue][red]][/red]->[maroon]configure[/maroon][red]([/red]
		-[purple]text[/purple] => [red]([/red][blue]$entry[/blue][red][[/red][blue]$i[/blue][red]][/red] ? [red]'[/red][purple]X[/purple][red]'[/red] : [red]'[/red][purple][/purple][red]'[/red][red])[/red],
	[red])[/red]
[red]}[/red]

The above could actually be condensed into a single statement, but that would be messy.

- Miller
 
Sweet!

BTW, how do you get your code to be syntax-colored?
 
The domain where that link resides appears to be down right now. The subroutine rewrite is pretty clever, but it doesn't seem as readable. Is there a performance advantage?

Now that I've got some nuts and bolts of Perl down, I've been trying to work out my styling. Is it as simple as making a new line with indent wherever there's a paren or brace?

What about you, Kirsle, what are your style guides?
 
To determine good style guidelines, I suggest that you pick up Conway's book "Perl Best Practices". True, you could dream up your own. But you'd be better off picking up those styles used by the majority of perl programmers.

- Miller
 
Sorry, guys, I was busy over the holidays.
Didn't mean to be rude a few exchanges up, Kevin: I'm Sean. Thanks for the link. It all seems easy enough to remember.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top