Created
September 25, 2011 17:52
-
-
Save mberends/1240895 to your computer and use it in GitHub Desktop.
GUI solution for masak's matchboxes puzzle on Niecza Perl 6
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# gtk-matchboxes.pl - GUI solution for http://irclog.perlgeek.de/perl6/2011-09-23#i_4469618 | |
constant $GTK = "gtk-sharp,Version=2.12.0.0,Culture=neutral,PublicKeyToken=35e10195dab3c99f"; | |
constant $GDK = "gdk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f"; | |
constant $GLIB = "glib-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f"; | |
# use 'gacutil -l' to look up similar module details | |
constant Application = CLR::("Gtk.Application,$GTK"); | |
constant GdkCairoHelper = CLR::("Gdk.CairoHelper,$GDK"); | |
constant GLibTimeout = CLR::("GLib.Timeout,$GLIB"); | |
constant GtkDrawingArea = CLR::("Gtk.DrawingArea,$GTK"); | |
constant Window = CLR::("Gtk.Window,$GTK"); | |
Application.Init; | |
my $window = Window.new("matchboxes"); | |
my $running = True; | |
my $gameCount = 0; | |
constant InitialMatches = 40; | |
my @matchesA = 0 xx (InitialMatches+1); | |
my @matchesB = 0 xx (InitialMatches+1); | |
my $windowSizeX = 600; my $windowSizeY = 500; | |
$window.Resize($windowSizeX, $windowSizeY); | |
my $drawingarea = GtkDrawingArea.new; | |
$drawingarea.add_ExposeEvent(&ExposeEvent); | |
GLibTimeout.Add( 1000, &TimeoutEvent); | |
$window.add_DeleteEvent(&DeleteEvent); | |
$window.Add($drawingarea); | |
$window.ShowAll; | |
while $running { # event loop with custom body | |
Application.RunIteration(False); # handle all Gtk events | |
my ($box, $count) = MatchBoxGame(InitialMatches); | |
if $box eq 'A' { ++@matchesA[$count] } else { ++@matchesB[$count] } | |
++$gameCount; | |
} | |
# Randomly remove matches from box A or B until one of them is empty. | |
# Return the number of matches in the other box | |
sub MatchBoxGame($initialMatches) | |
{ | |
my $matchesA = my $matchesB = $initialMatches; | |
while $matchesA > 0 && $matchesB > 0 { | |
if rand < 0.5 { --$matchesA; } | |
else { --$matchesB; } | |
} | |
return ($matchesA > 0) ?? ('A', $matchesA) !! ('B', $matchesB); | |
} | |
sub ExposeEvent($obj, $args) { | |
$args; # suppress 'declared but not used' warnings | |
my $cc = GdkCairoHelper.Create($obj.GdkWindow); # Cairo Context | |
# TODO: the following two lines pass parameters by value, need to pass by references to integers | |
# my $windowX; my $windowY; my $windowWidth; my $windowHeight; my $windowDepth; | |
# $obj.GdkWindow.GetGeometry($windowX, $windowY, $windowWidth, $windowHeight, $windowDepth); | |
# Tracked as https://github.com/sorear/niecza/issues/57 | |
# TODO: remove the following one line cheat that works around the above problem | |
my $windowWidth = $windowSizeX; my $windowHeight = $windowSizeY; | |
$cc.SetSourceRGB(1, 1, 0.8); $cc.Paint(); # pale yellow background | |
DrawGraphs($cc, $windowWidth, $windowHeight); | |
$cc.Target.Dispose; | |
$cc.dispose-hack; | |
} | |
sub DrawGraphs($cc, $windowWidth, $windowHeight) | |
{ | |
# Calculate dimensions relative to window size | |
my $lineWidth = (($windowWidth min $windowHeight) * 0.005).Int max 1; | |
my $axisTop = $windowHeight * 0.1; | |
my $axisBottom = $windowHeight * 0.9; | |
my $axisALeft = $windowWidth * 0.1; | |
my $axisARight = $windowWidth * 0.45; | |
my $axisBLeft = $windowWidth * 0.55; | |
my $axisBRight = $windowWidth * 0.9; | |
# Draw the histograms | |
# NYI [max] @matchesA, @matchesB; | |
my $maxMatches = 0; | |
for @matchesA -> $m { if $m > $maxMatches { $maxMatches = $m; } } | |
for @matchesB -> $m { if $m > $maxMatches { $maxMatches = $m; } } | |
my $scaleX = ($axisARight - $axisALeft) / InitialMatches; | |
my $scaleY = ($axisBottom - $axisTop) / $maxMatches; | |
$cc.SetSourceRGB(1, 0, 0); # red for box A | |
my $i; loop ($i = 1; $i <= InitialMatches; ++$i) { | |
my $height = @matchesA[$i] * $scaleY; | |
my $x0 = ($axisALeft + $i * $scaleX).Int; | |
my $top = $axisBottom - $height; | |
$cc.Rectangle($x0,$top,$scaleX-1,$height-1); | |
$cc.Fill; | |
} | |
$cc.SetSourceRGB(0, 1, 0); # green for box B | |
loop ($i = 1; $i <= InitialMatches; ++$i) { | |
my $height = @matchesB[$i] * $scaleY; | |
my $x0 = ($axisBLeft + $i * $scaleX).Int; | |
my $top = $axisBottom - $height; | |
$cc.Rectangle($x0,$top,$scaleX-1,$height-1); | |
$cc.Fill; | |
} | |
$cc.Stroke; | |
# Draw the horizontal and vertical axes | |
$cc.LineWidth = $lineWidth; | |
$cc.SetSourceRGB(0, 0, 0); # Black | |
$cc.MoveTo($axisALeft, $axisTop); | |
$cc.LineTo($axisALeft, $axisBottom); | |
$cc.LineTo($axisARight, $axisBottom); | |
$cc.MoveTo($axisBLeft, $axisTop); | |
$cc.LineTo($axisBLeft, $axisBottom); | |
$cc.LineTo($axisBRight, $axisBottom); | |
$cc.Stroke; | |
# Label the graphs | |
$cc.SetSourceRGB(0, 0, 0); # Black | |
$cc.SetFontSize($windowWidth * 0.1); | |
my $textWidth = $cc.TextExtents('A').Width; | |
my $textHeight = $cc.TextExtents('A').Height; | |
$cc.MoveTo($axisALeft + $textWidth*3, $axisTop+$textHeight); $cc.ShowText('A'); | |
$cc.MoveTo($axisBLeft + $textWidth*3, $axisTop+$textHeight); $cc.ShowText('B'); | |
$cc.SetFontSize($windowWidth * 0.05); | |
$textWidth = $cc.TextExtents('0').Width; | |
$textHeight = $cc.TextExtents('0').Height; | |
$cc.MoveTo($axisALeft - $textWidth*0.5, $axisBottom+$textHeight*1.5); $cc.ShowText('0'); | |
$cc.MoveTo($axisARight - $textWidth, $axisBottom+$textHeight*1.5); $cc.ShowText('40'); | |
$cc.MoveTo($axisBLeft - $textWidth*0.5, $axisBottom+$textHeight*1.5); $cc.ShowText('0'); | |
$cc.MoveTo($axisBRight - $textWidth, $axisBottom+$textHeight*1.5); $cc.ShowText('40'); | |
# Label the Y axis maximum | |
$cc.SetFontSize($windowWidth * 0.03); | |
$textWidth = $cc.TextExtents(~ $maxMatches).Width; | |
$textHeight = $cc.TextExtents(~ $maxMatches).Height; | |
$cc.MoveTo($axisALeft - $textWidth * 1.1, $axisTop+$textHeight*0.5); | |
$cc.ShowText(~ $maxMatches); | |
$cc.SetFontSize($windowWidth * 0.04); | |
# Put a heading above the graphs | |
my $heading = "$gameCount Matchbox games"; | |
$textWidth = $cc.TextExtents($heading).Width; | |
$textHeight = $cc.TextExtents($heading).Height; | |
$cc.MoveTo($axisBLeft - $textWidth * 0.5, $axisTop - $textHeight * 0.5); | |
$cc.ShowText($heading); | |
$cc.Stroke; | |
} | |
sub TimeoutEvent # called once per second | |
{ | |
$drawingarea.QueueDrawArea(0,0,$windowSizeX,$windowSizeY); | |
return True; # meaning please continue calling this timeout handler | |
}; | |
sub DeleteEvent($obj, $args) { | |
$obj; $args; # suppress "declared but not used" Potential difficulties | |
$running = False; | |
Application.Quit; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment