#!/usr/bin/perl -w
#
# 070502 liverpole -- Demonstrates a weirdness which I don't understand
#
# Strict
use strict;
use warnings;
# Libraries
use Tk;
##################
## Main program ##
##################
# Construct the GUI
my $mw = new MainWindow();
my $f1 = $mw->Frame()->pack;
my $chosen = "";
my $fr1 = $f1->Frame()->pack(-side => 'left');
my $fr2 = $f1->Frame()->pack(-side => 'left');
button($fr1, 'green', ' Exit GUI ', sub { $mw->destroy() });
button($fr1, 'green', ' Start test ', sub { start_test($fr2) });
$fr1->Label(-width => 16, -textvar => \$chosen, -bg => 'white')->pack;
MainLoop();
#################
## Subroutines ##
#################
sub button {
my ($w, $bg, $text, $pcmd) = @_;
my $b = $w->Button(-bg => $bg, -text => $text);
$b->configure(-width => 16, -command => $pcmd);
$b->pack;
return $b;
}
sub randomize_list {
my $plist = shift;
my $prandom = [ ];
while (@$plist) {
push @$prandom, splice(@$plist, int(rand(@$plist)), 1);
}
return $prandom;
}
sub start_test {
my ($frame) = @_;
# Create a random list of 9 items { 1 ... 9 }
my @values = qw( 1 2 3 4 5 6 7 8 9 );
my $pvalues = randomize_list([ @values ]);
my $chosen_idx = -1;
foreach my $num (@$pvalues) {
$chosen = $num;
# Create a duplicate list (not including the chosen number)
my @dups = grep { $_ ne $num } @values;
my $pdups = randomize_list([ @dups ]);;
# Insert chosen number at a random place { 0 ... 3 } in the list
my $correct_idx = int(rand(4));
$pdups->[$correct_idx] = $num;
my $pbuttons = [ ];
for (my $i = 0; $i < 4; $i++) {
my $dup = $pdups->[$i];
my $icopy = $i;
# The closure where I'm expecting $chosen_idx to get
# assigned to $i = {0,1,2,3}, but it seems to always
# get assigned to 4! (or whatever the final value of
# $i is.) However, if I set $chosen_idx to $icopy:
#
# my $psub = sub { $chosen_idx = $icopy };
#
# then everything works ... ???
#
my $psub = sub { $chosen_idx = $i };
push @$pbuttons, button($frame, 'skyblue', $dup, $psub);
}
$chosen_idx = -1;
while ($chosen_idx < 0) {
$mw->update();
}
# Delete the buttons
map { $_->destroy() } @$pbuttons;
# Why on EARTH is this showing $chosen_idx as 4 every time?!
print "correct idx[$correct_idx] ... chosen_idx[$chosen_idx]\n";
}
}
####
sub button {
my ($w, $bg, $text, $pcmd, $ival) = @_;
(defined $ival) and print "Value of \$i is $ival\n";
my $b = $w->Button(-bg => $bg, -text => $text);
$b->configure(-width => 16, -command => $pcmd);
$b->pack;
return $b;
}
# ... and later, when calling button() ...
push @$pbuttons, button($frame, 'skyblue', $dup, $psub, $i);
# The above correctly displays each value of $i
####
my $icopy = $i;
# ...
my $psub = sub { $chosen_idx = $icopy };