#!/usr/bin/perl use strict; use warnings; use Math::BigInt; use POSIX; use Tk; use Tk::Pane; ################################################################################ # SOME GLOBAL DECLARATION ################################################################################ my @tartaglia ; #AoA used as CACHE my @tkcache; #AoA used as CACHE for Tk buttons in the triangles my $tart_win; # triangle window my $ow; #output window my $out; #output var for out_win my $row_num = 15; #default row noumber for the triangle my $dot_after = 2; # default: instead of '24' it prints '..' my $debug = 0; # no debug infos in the output window my @posible_colors = qw(red royalblue orange green yellow violet blue pink purple ); my %next_col = (red=>'royalblue',royalblue=>'orange',orange=>'green',green=>'yellow',yellow=>'violet', violet=>'blue',blue=>'pink',pink=>'purple',purple=>'red'); my @colorized; # array of Tk button yet colorized my $size_tile = 8; # size and boldness of various fonts my $bold_tile = 0; my $size_help = 13; my $bold_help = 1; my $size_out = 13; my $bold_out = 1 ; use subs 'tar_print'; ################################################################################ # MAIN WINDOW CREATION ################################################################################ my $mw = MainWindow->new (); $mw->Icon(-image => $mw->Pixmap(-data => &tart_icon)); $mw->geometry("688x861+0+0"); #->geometry("300x450+0+0"); 320+0 $mw->title(" command "); #$mw->optionAdd('*font', 'Courier 10'); $mw->optionAdd('*Label.font', 'Courier 10'); $mw->optionAdd( '*Entry.background', 'lavender' ); $mw->optionAdd( '*Entry.font', 'Courier 12 bold' ); my $scrolled_top = $mw->Scrolled('Frame', -background=>'white', -scrollbars => 'osoe',)->pack(-expand => 1, -fill => 'both'); my $fr0 = $scrolled_top->Frame(-borderwidth => 2, -relief => 'groove')->pack(-side=>'top',-pady=>10); $fr0->Label(-text => "-Tartaglia's triangle properties-" )->pack(-pady=>10); my $fr1 = $scrolled_top->Frame(-borderwidth => 2, -relief => 'groove')->pack(-side=>'top',-anchor=>'w',-pady=>5); #,-fill=>'x' $fr1->Label(-text => "Rows in the triangle: from 0 to ")->pack(-side => 'left');#,-expand => 1, -fill=>'x' $fr1->Entry(-width => 3,-borderwidth => 4, -textvariable => \$row_num)->pack(-side => 'left', -expand => 1,-padx=>5); #-side => 'left', -expand => 1, -fill=>'x' $fr1->Label(-text => "Tiles font size")->pack(-side => 'left',-expand => 1); $fr1->Entry(-width => 3,-borderwidth => 4, -textvariable => \$size_tile)->pack(-side => 'left', -expand => 1,-padx=>5); $fr1->Label(-text => "bold")->pack(-side => 'left',-expand => 1); $fr1->Checkbutton( -variable =>\$bold_tile )->pack(-side => 'left', -expand => 1); $fr1->Button(-padx=> 5,-text => "introduction",-borderwidth => 4, -command => sub{&help(\&help_intro)})->pack(-side => 'right',-expand => 1,-padx=>5);#128 my $fr2 = $scrolled_top->Frame(-borderwidth => 2, -relief => 'groove')->pack(-side=>'top',-anchor=>'w',-pady=>5); $fr2->Label(-text => "Numbers as dot if ")->pack(-side => 'left',-expand => 1); $fr2->Radiobutton(-text => "1",-variable => \$dot_after, -value=>'1')->pack(-side => 'left',-expand => 1); $fr2->Radiobutton(-text => "2",-variable => \$dot_after, -value=>'2')->pack(-side => 'left',-expand => 1); $fr2->Radiobutton(-text => "3",-variable => \$dot_after, -value=>'3')->pack(-side => 'left',-expand => 1); $fr2->Radiobutton(-text => "4",-variable => \$dot_after, -value=>'4')->pack(-side => 'left',-expand => 1); $fr2->Radiobutton(-text => "never",-variable => \$dot_after, -value=>'9999')->pack(-side => 'left',-expand => 1); $fr2->Label(-text => " digits. Print debug information")->pack(-side => 'left',-expand => 1); $fr2->Checkbutton( -variable =>\$debug,-command => sub { tar_print "Debug info ".($debug ? 'enabled' : 'disabled')."\n" })->pack(); my $fr2a = $scrolled_top->Frame(-borderwidth => 2, -relief => 'groove')->pack(-side=>'top',-anchor=>'w',-pady=>5); $fr2a->Label(-text => "Size of help texts")->pack(-side => 'left',-expand => 1); $fr2a->Entry(-width => 3,-borderwidth => 4, -textvariable => \$size_help)->pack(-side => 'left', -expand => 1,-padx=>5); #-side => 'left', -expand => 1, -fill=>'x' $fr2a->Label(-text => "bold")->pack(-side => 'left',-expand => 1); $fr2a->Checkbutton( -variable =>\$bold_help )->pack(-side => 'left', -expand => 1); $fr2a->Label(-text => " Size of output ")->pack(-side => 'left',-expand => 1); $fr2a->Entry(-width => 3,-borderwidth => 4, -textvariable => \$size_out)->pack(-side => 'left', -expand => 1,-padx=>5); #-side => 'left', -expand => 1, -fill=>'x' $fr2a->Label(-text => "bold")->pack(-side => 'left',-expand => 1); $fr2a->Checkbutton( -variable =>\$bold_out )->pack(-side => 'left', -expand => 1); my $fr3 = $scrolled_top->Frame(-background => 'white')->pack(-side=>'top',-pady=>5); $fr3->Button(-padx=> 20,-text => "draw triangle",-borderwidth => 4, -command => \&draw_triangle)->pack(-side => 'left',-expand => 1,-padx=>5); $fr3->Button(-padx=> 20,-text => "delete triangle",-borderwidth => 4, -command => \&destroy_tri )->pack(-side => 'left',-expand => 1,-padx=>5); ################################################################################ # EXPERIMENTS CREATION FRAME ################################################################################ my $fr4 = $scrolled_top->Frame(-borderwidth => 2, -relief => 'groove')->pack(-side=>'top',-pady=>10); $fr4->Label(-text => "-Tartaglia's triangle experiments-" )->pack(-pady=>10); ##### BINOMIAL EXPANSION my $input_bin; my $color_bin = 'red'; my $title_bin = "Binomial Expansion (a+b)^"; create_experiment (\$input_bin, \$color_bin, $title_bin, \&help_bin, \sub { $input_bin=~s/\s+//g; &given_coord($color_bin,$input_bin." 0-$input_bin"); &bin_exp($input_bin)}); ##### POWERS OF TWO my $input_p2; my $color_p2 = 'red'; my $title_p2 = "Powers of 2 2^"; create_experiment (\$input_p2, \$color_p2, $title_p2, \&help_pow2, \sub {power_of_two($input_p2,$color_p2)} ); ##### POWERS OF ELEVEN my $input_p11; my $color_p11 = 'red'; my $title_p11 = "Powers of 11 11^"; create_experiment (\$input_p11, \$color_p11, $title_p11,\&help_pow11,\sub {power_of_eleven($input_p11,$color_p11)} ); ##### FIBONACCI my $input_fib; my $color_fib = 'red'; my $title_fib = "Fibonacci max row"; create_experiment (\$input_fib, \$color_fib, $title_fib,\&help_fib,\sub {fibonacci($input_fib,$color_fib)} ); ##### PRIME NUMBERS my $input_pri; my $color_pri = 'red'; my $title_pri = "Prime numbers max row"; create_experiment (\$input_pri, \$color_pri, $title_pri,\&help_pri,\sub {is_prime($input_pri,$color_pri)} ); ### POLYGONAL NUMBERS my $input_tri; my $color_tri = 'red'; my $title_tri = "Triangular numbers num"; create_experiment (\$input_tri, \$color_tri, $title_tri, \&help_tri, \sub {&triangulars($input_tri, $color_tri)}); #### COORDINATES my $input_coord; my $color_coord = 'red'; my $title_coord = "Colorize by coordinates"; create_experiment (\$input_coord, \$color_coord, $title_coord,\&help_bycoord, \sub {&given_coord($color_coord ,$input_coord)}); ### DAVID'S STAR my $input_star; my $color_star = 'red'; my $title_star = "David's star row col"; create_experiment (\$input_star, \$color_star, $title_star, \&help_david, \sub {&david_star($input_star, $color_star)}); ### CAPELAN my $input_cat; my $color_cat = 'red'; my $title_cat = "Catalan's numbers max row"; create_experiment (\$input_cat, \$color_cat, $title_cat, \&help_cat, \sub {&catalan($input_cat, $color_cat)}); ### MERSENNE AND M PRIMES my $input_mer; my $color_mer = 'red'; my $title_mer = "Mersenne numbers max row"; create_experiment (\$input_mer, \$color_mer, $title_mer, \&help_mer, \sub {&mersenne($input_mer, $color_mer)}); ### SIERPINSKI my $input_sie; my $color_sie = 'red'; my $title_sie = "Sierpinski fractals num"; create_experiment (\$input_sie, \$color_sie, $title_sie, \&help_sie, \sub {&sierpinski($input_sie, $color_sie)}); ### COMBINATIONS my $input_com; my $color_com = 'red'; my $title_com = "Combinations row col"; create_experiment (\$input_com, \$color_com, $title_com, \&help_com, \sub {&combination($input_com, $color_com)}); ### EVALUATION my $input_eval; my $color_eval = 'red'; my $title_eval = "Colorize by evaluation"; create_experiment (\$input_eval, \$color_eval, $title_eval, \&help_eval, \sub {&col_eval($color_eval ,$input_eval)}); ### HOCKEY STICK PATTERN my $input_hoc; my $color_hoc = 'red'; my $title_hoc = "Hockey stick row col"; create_experiment (\$input_hoc, \$color_hoc, $title_hoc, \&help_hockey, \sub {&hockeystick($input_hoc, $color_hoc)}); ### PARALLELOGRAM PATTERN my $input_par; my $color_par = 'red'; my $title_par = "Parallelogram row col"; create_experiment (\$input_par, \$color_par, $title_par, \&help_para, \sub {¶llelogram($input_par, $color_par)}); ### SUM OF SQUARES my $input_ssq; my $color_ssq = 'red'; my $title_ssq = "Sum of squares in the row"; create_experiment (\$input_ssq, \$color_ssq, $title_ssq, \&help_squa, \sub {&sum_squares($input_ssq, $color_ssq)}); tar_print "Welcome to Tartaglia's triangle fun offered by Discipulus as found at www.perlmonks.org"; &draw_triangle; #tar_print "MainWindow geometry: ",$mw->geometry(),"\n"; # tar_print "Triangle geometry: ",$tart_win->geometry(),"\n"; # tar_print "output geometry: ",$ow->geometry(),"\n"; MainLoop; ################################################################################ # EXPERIMENTS SUBROUTINES ################################################################################ sub sum_squares { my ($input,$color)=@_; if ($input =~ /\s?(\d+)\D/){$input = $1} my $col2 = $next_col{$color}; tar_print "\n\n*** Sum of sqares of rown $input\n\n"; my @row = tartaglia_row($input); my $calc = join ' ** 2 + ',@row; tar_print "The sumation of squares of $color tiles in ".$input."th row is:\n$calc = ",eval $calc,"\n"; given_coord($color, "$input 0-".($input + 1)); my @double = tartaglia_row($input * 2); my $central = $double[ (int $#double / 2 )]; given_coord($col2, ($input * 2)." ".((int $#double / 2 ))); tar_print "the central element of $input x 2 (".($input * 2).") row is $central\n\n"; } ################################################################################ sub parallelogram { my ($input,$color)=@_; my ($row,$col)= split ' ',$input; tar_print "\n\n*** Parallelogram pattern \n\n"; given_coord ($color, "$row $col"); my $wanted = ${[tartaglia_row($row)]}[$col]; my @parallelogram; my $col2 = $next_col{$color}; $col--; my $first = $col; my $last = $col; foreach my $prow (reverse 0..$row-2){ my @val = tartaglia_row($prow); $first = 0 if $first < 0; $last = $col if $last > $col; $last = $#val if $last > $#val; push @parallelogram, @val[$first .. $last]; given_coord ($col2, "$prow ".$first.'-'.$last); $first--; $last++; } my $sum = join ' + ', sort @parallelogram; my $res = eval $sum; tar_print "$wanted ($color tile) is equal to the sum of $col2 tiles + 1:\n"; tar_print "$sum = $res\n$res + 1 = ",$res + 1," = $wanted ($color tile)\n"; } ################################################################################ sub hockeystick { my ($input,$color)=@_; my ($row,$col)= split ' ',$input; tar_print "\n\n*** Hockey stick pattern \n\n"; my $col2 = $next_col{$color}; given_coord ($col2, "0-".($row-1)." ".($col-1) ); given_coord ($color, "$row $col"); my @hockey; foreach my $trow ( 0 .. $row-1) { my @val = tartaglia_row($trow); defined $val[$col-1] ? (push @hockey, $val[$col-1]) : next; } my $number = ${ [tartaglia_row($row)] }[$col]; my $sum = join ' + ',@hockey; tar_print "$number ($color tile) is equal to the sum of $col2 tiles:\n$sum = ".eval $sum."\n"; } ################################################################################ sub triangulars{ my ($input,$color)=@_; if ($input =~ /\s?(\d+)\D/){$input = $1} my $col2 = $next_col{$color}; tar_print "\n\n*** Triangular number $input\n\n"; given_coord ($col2, "0-$row_num 2"); given_coord ($color, ($input+2)." 2"); my @triangulars = map {my $n; my $x = $_; foreach my $i(0..$x) {$n+=$i};$n } 1..$input+1; tar_print "\nThe $input".'th '."triangular number is: $triangulars[-1] ($color tile)\n"; tar_print "First triangular numbers found ($col2 tiles):\n",(join ' ', @triangulars),"\n\n"; } ################################################################################ sub combination{ my ($input,$color)=@_; my ($row,$col)= split ' ',$input; if ($col > $row) {tar_print "Warning column must be lesser or equal to row\n"; return} tar_print "\n\n*** Combinations of $col items in a group of $row\n\n"; my $col2 = $next_col{$color}; my $col3 = $next_col{$col2}; my $col4 = $next_col{$col3}; given_coord ($col2, "$row 0-$row_num"); given_coord ($col3, "0-$row_num $col"); given_coord ($col4, ($row + $col - 1)." $col"); given_coord ($color, "$row $col"); tar_print "There are ",${[tartaglia_row($row)]}[$col]," ($color tile position $row - $col) different combinations (when the order does not matter) of $col items in group of $row.\n"; tar_print "There are ",${[tartaglia_row($row + $col - 1)]}[$col],( $col > 1 ? " ($col4 tile)" : '')." different combinations with repetitions of $col items in group of $row.\n\n"; } ################################################################################ sub sierpinski{ my ($input,$color)=@_; if ($input =~ /\s?(\d+)\D/){$input = $1} tar_print "\n\n*** Sierpinski fractal: show numbers divisible by $input\n\n"; col_eval ($color, '$_ % '.$input.' == 0'); } ################################################################################ sub mersenne{ my ($input,$color)=@_; my @mersenne; tar_print "\n\n*** Mersenne's numbers and Mersenne's primes (max row $input)\n\n"; foreach my $row (0..$input){ my $cur; map {$cur += $_ } tartaglia_row($row); push @mersenne, $cur-1; given_coord($color,"$row 0-".$row); $color = $next_col{$color}; } tar_print "\nMersenne's numbers found in first $input rows:\n"; foreach my $n (@mersenne){ tar_print "$n ",( check_prime($n) ? "Mersenne prime " : ''),"\n"; #check_prime($n) } tar_print "\n\n"; } ################################################################################ sub catalan{ my ($input,$color)=@_; my @catalan; my $natural = 1; tar_print "\n\n*** Catalan's numbers (max row $input)\n\nNote two methods to generate the serie: the first divide the central term of any odd row ($color tiles) by the correspondant counting number: this gives the right serie: 1 1 2 5 14..\n"; tar_print "The second method is the central term of any odd row minus the term two place left, if present ($next_col{$color} tiles). This gives the rigth serie but without the first '1'.\n\n"; given_coord($next_col{$next_col{$color}}, "0-".int($input / 2 + 1)." 1"); foreach my $rc (0..$input){ next if ($rc+1) % 2 == 0; my @row = tartaglia_row($rc); my $mid = (scalar @row / 2); my $two_left = ($mid - 2) >= 0 ? $row[$mid - 2] : 0 ; tar_print "$row[$mid] / $natural = ",$row[$mid] / $natural,"\t\t$row[$mid] - $two_left = ",$row[$mid] - $two_left,"\n"; push @catalan, ($row[$mid] / $natural); colorize($tkcache[$rc][$mid],$color); colorize($tkcache[$rc][$mid - 2],$next_col{$color}) if ($mid - 2) >= 0 and defined $tkcache[$rc][$mid - 2]; $natural++; } tar_print "\nCatalan's numbers found in first $input rows:\n",(join ' ', @catalan),"\n\n"; } ################################################################################ sub david_star { my ($input,$color)=@_; tar_print ("warning coordinated expected\n") unless $input =~ /\d+\s+\d/; my ($row, $col) = split /\s/,$input; if ($row < 2 or $col == $row or $col == 0){tar_print "warning coordinates must be not on the border\n";return} unless ($tkcache[$row][$col]){$debug ? tar_print "skipping $row - $col (outside the triangle)\n" :0;return; } my $next_col = $next_col{$color}; my $other_col = $next_col{$next_col}; map {&colorize ($_, $next_col)} $tkcache[$row-1][$col-1], $tkcache[$row][$col+1], $tkcache[$row+1][$col]; map {&colorize ($_, $other_col)} $tkcache[$row-1][$col], $tkcache[$row+1][$col+1], $tkcache[$row][$col-1]; &colorize ($tkcache[$row][$col], $color); my @above = tartaglia_row ($row-1); my @mid = tartaglia_row ($row); my @below = tartaglia_row ($row+1); tar_print "\n\n*** David's star for number $mid[$col] ( $row - $col, $color)\n\n"; tar_print "($next_col tiles)\ngreatest common divisor: GCD ($above[$col-1], $mid[$col+1], $below[$col]) = ",Math::BigInt::bgcd($above[$col-1], $mid[$col+1], $below[$col]),"\n"; tar_print "product $above[$col-1] x $mid[$col+1] x $below[$col] = ",$above[$col-1] * $mid[$col+1] * $below[$col],"\n"; tar_print "\n($other_col tiles)\ngreateast common divisor: GCD ($above[$col], $mid[$col-1],$below[$col+1]) = ",Math::BigInt::bgcd($above[$col], $mid[$col-1],$below[$col+1]),"\n"; tar_print "product $above[$col] x $mid[$col-1] x $below[$col+1] = ",$above[$col] * $mid[$col-1] * $below[$col+1],"\n"; tar_print "\nProduct of six terms is always an integer perfect square:\n"; tar_print "$above[$col-1] x $mid[$col+1] x $below[$col] x $above[$col] x $mid[$col-1] x $below[$col+1] = "; my $big_prod = $above[$col-1] * $mid[$col+1] * $below[$col] * $above[$col] * $mid[$col-1] * $below[$col+1]; tar_print $big_prod, "\nsquare root of $big_prod = ", sqrt $big_prod,"\n\n"; } ################################################################################ sub is_prime{ my ($input,$color)=@_; tar_print "\n\n*** Prime numbers (max row $input)\n\n"; foreach my $row (0..$input){ my @vals = tartaglia_row($row); foreach my $pos (0..$#vals){ next if $vals[$pos] == 1; if (check_prime($vals[$pos])) { tar_print "$vals[$pos] is prime\n"; colorize($tkcache[$row][$pos],$color ); } } } } ################################################################################ sub fibonacci{ my ($input,$color)=@_; if ($input > $row_num){$input=$row_num;tar_print "Warning: too many rows specified. Using $row_num\n" if $debug} tar_print "\n\n*** Fibonacci's numbers (max row $input)\n\n"; my @aoa_vals = map {[tartaglia_row($_)]} 0..$input; # why i build triangle by hockey stick pattern?!?!? argh my @fibonacci; my $fibonacci; my $col_i=0; foreach my $row (reverse 0..$input){ my $cur_pos = 0; my $cur_row = $row; while ($cur_row >= $cur_pos){ next unless $tkcache[$cur_row][$cur_pos]->isa('Tk::Button'); colorize($tkcache[$cur_row][$cur_pos], $posible_colors[$col_i]); push @{$fibonacci[$row]}, $aoa_vals[$cur_row][$cur_pos];# tar_print "push \$fibonacci[$row], $aoa_vals[$cur_row][$cur_pos];\n"; $cur_row--; $cur_pos++; } $col_i++; $col_i > $#posible_colors ? $col_i=0 : 0; } map { my $sum = join '+',@{$_};tar_print $sum,' = ', eval $sum,"\n";$fibonacci.=(eval $sum).' ';} @fibonacci; tar_print "\n\nFibonacci's numbers: $fibonacci\n\n"; } ################################################################################ sub power_of_eleven{ my ($input,$color)=@_; my $big_int = Math::BigInt->new( '11' ); tar_print "\n\n*** Power of 11:\t11^$input = ", $big_int->bpow($input),"\n\n"; &given_coord($color ,"$input 0-$input"); my @row =tartaglia_row($input); my $level = $input; my $cur_dec=0; my @final; tar_print "row $input: ",join ' ',@row,"\n\n"; foreach my $num ( reverse @row) { # reverse is not util but.. my ($dec,$unit,$partial_dec,$tmp); if ($num=~/(\d+)(\d)$/){$dec=$1;$unit=$2} else{$dec=0;$unit=$num} my $pad = ' '.(" " x $level--).' '; my $minus = (length ("$dec")+1); $pad =~ s/\s{$minus}//; tar_print $pad."$dec|$unit\n"; $num+=$cur_dec; if ($num=~/(\d+)(\d)$/){$cur_dec=$1;$num=$2} else{$cur_dec=0; } unshift @final,$num; } $cur_dec ? unshift @final, $cur_dec : 0; tar_print "\n ",(join ' ',@final),"\n\n = ",(join '',@final),"\n\n"; } ################################################################################ sub power_of_two{ my ($input,$color)=@_; my $big_int = Math::BigInt->new( '2' );#tar_print $x->bpow(15); tar_print "\n\n*** Power of 2:\t2^$input = ", $big_int->bpow($input),"\n\n"; &given_coord($color ,"$input 0-$input"); my $sum = join ' + ', tartaglia_row($input); tar_print "$sum = ",eval $sum,"\n\n"; } ################################################################################ sub bin_exp{ #plagiarized from crazyinsomniac at http://www.perlmonks.org/?node_id=68056 my $n = shift; tar_print "\n\n*** Binomial expansion:\t(a+b)^$n =\n\n"; my @coefficient = tartaglia_row($n); for my $j (0 .. $n) { my $nj=$n-$j; tar_print $coefficient[$j]; tar_print $_ = ($nj!=0)?( ($nj>1)?(' * a^'.$nj):(' * a') ):''; tar_print $_ = ($j!=0)?( ($j==1)?(' * b'):(' * b^'.$j) ):''; tar_print $_ = ($j!=$n)?(" +\n"):("\n"); } tar_print "\n\n" ; } ################################################################################ sub col_eval { my $color = shift; my $to_eval = shift; if ($to_eval =~ /system|exec|`/){tar_print "not safe\n";return} foreach my $row (0..$row_num) { my @vals = &tartaglia_row($row); my $i = 0; map { my $val = $_; ( my $str = $to_eval) =~ s/\$_/$val/e; eval $to_eval ? ( &tar_print ("$str TRUE AT $row - $i\n") and &colorize ($tkcache[$row][$i], $color) ) : 0; $i++; } @vals; } } ################################################################################ # UTILITY SUBROUTINES ################################################################################ sub create_experiment{ my ($input, $color, $title, $help, $sub_ref) = @_; my $frame = $scrolled_top->Frame(-borderwidth => 2, -relief => 'groove')->pack(-side=>'top',-anchor=>'w',-pady=>5); $frame->Button(-text => "?",-borderwidth => 2, -command => sub {&help($help)} )->pack(-side => 'left',-expand => 1); $frame->Label(-text => (pack 'A25', $title) )->pack(-side => 'left',-expand => 1); $frame->Entry(-width => 25,-borderwidth => 4,-textvariable => $input)->pack(-side => 'left',-expand => 1); $frame->Optionmenu(-options => [@posible_colors],-variable => $color)->pack(-side => 'left',-expand => 1); $frame->Button(-text => "Colorize",-borderwidth => 4, -command => $sub_ref)->pack(-side => 'left',-expand => 1); $frame->Button(-text => "Clear",-borderwidth => 4, -command => \&decolorize)->pack(-side => 'left',-expand => 1); } ################################################################################ sub tar_print{ &check_output(); $out->insert('end', "@_"); $out->see('end'); 1; # or col_eval will not call colorizes } ################################################################################ sub check_prime { #http://www.perlmonks.org/?node_id=1054405 my ($i,$j,$h,$sentinel) = (shift,0,0,0); # if $i is an even number, it can't be a prime if($i%2==0){return 0} else{ $h=POSIX::floor(sqrt($i)); $sentinel=0; # since $i can't be even -> only divide by odd numbers for($j=3; $j<=$h; $j+=2){ if($i%$j==0){ $sentinel++; # $i is not a prime, we can get out of the loop $j=$h; } } if($sentinel==0){ return 1; print "$i \n"; } } } ################################################################################ sub decolorize { foreach my $it(@colorized){ #tar_print "CLEAR call colorize: $it\n" if $debug; &colorize( $it,'gray') ; } @colorized=(); return; } ################################################################################ sub colorize { my $ref = shift; return 0 unless $ref; return 0 unless $ref->can('configure'); my $color = shift; unless ($color eq 'gray'){push @colorized, $ref; } $ref->configure(-background =>$color); $tart_win->update; } ################################################################################ sub given_coord { my $color = shift; my $to_color = shift; my @group = split /,/,$to_color; foreach my $pair (@group){ $pair =~ s/^\s+//;$pair =~ s/\s+$//; $pair =~ s/\s+/ /; map { my ($x,$y) = split /\s+/,$_; $tkcache[$x][$y] ? &colorize ($tkcache[$x][$y], $color) : ($debug ? tar_print "skipping $x - $y (outside the triangle)\n" :0); } &exp_coord($pair); } } ################################################################################ sub exp_coord { my ($r,$c)=split /\s/,"@_"; unless (defined $r and defined $c) {tar_print "Both must be defined. Received:",map{defined $_ ? "$_ " : 'UNDEF '}($r,$c);return} my @r; my @c; my @expanded; @r = $r=~/^(.*\d)-(.+)$/ ? ($1..$2) : ($r); @c = $c=~/^(.*\d)-(.+)$/ ? ($1..$2) : ($c); for my $rc (@r) { for my $cc (@c) { push @expanded, "$rc $cc" } }; return @expanded; } ################################################################################ sub destroy_tri { if (Exists($tart_win)) { $tart_win->destroy(); undef @colorized; } #tar_print "MainWindow geometry: ",$mw->geometry(),"\n"; #tar_print "Triangle geometry: ",$tart_win->geometry(),"\n"; #tar_print "output geometry: ",$ow->geometry(),"\n"; } ################################################################################ sub draw_triangle { my $scrolledframe; if (! Exists($tart_win)) { $tart_win = $mw->Toplevel(); $tart_win->Icon(-image => $mw->Pixmap(-data => &tart_icon)); $tart_win->geometry("300x450+708+0"); $scrolledframe = $tart_win->Scrolled('Frame', -background=>'black', -scrollbars => 'osoe', )->pack(-expand => 1, -fill => 'both'); $tart_win->title(" Tartaglia's triangle "); $tart_win->optionAdd('*Button.font' => 'Arial '.$size_tile.' '.($bold_tile ? 'bold' : ''), 20); #'Courier 13 bold' tar_print "\nDRAWING a tartaglia's triangle of ".($row_num + 1)." rows (with dots if $dot_after or more digits)\n\n"; } else { $tart_win->deiconify( ) if $tart_win->state() eq 'iconic'; $tart_win->raise( ) if $tart_win->state() eq 'withdrawn'; return; } #draw the triangle foreach my $row( 0..$row_num ){ my $frame = $scrolledframe->Frame->grid; my ($first,@rest) = &tartaglia_row ($row); my @others; foreach my $i (0..$#rest) { my $n = $rest[$i]; $tkcache[$row][$i + 1] = $frame->Button(-command => sub{tar_print "HIT ($row - ".($i + 1).") VALUE $n\n";}, -text => &shrinkn($n) , -background => 'gray' ); $others[$i] = $tkcache[$row][$i + 1]; } $tkcache[$row][0] = $frame->Button( -command => sub{tar_print "HIT ($row - 0) VALUE 1\n"}, #print $tkcache[$row][0]->fontActual('font'),"\n"; -text => &shrinkn($first), -background => 'gray' )->grid( @others ); } tar_print "\n\n"; } ################################################################################ #{ # my @tartaglia ; #AoA used as CACHE sub tartaglia { my ($x,$y) = @_; #tar_print "\t\treceiving ".($y)." $x\t"; if ($x == 0 or $y == 0) { $tartaglia[$x][$y]=1 ; tar_print "\tFORCED: 1\n" if $debug;return 1}; tar_print ""."\tCACHE: ",(defined $tartaglia[$x][$y] ? "$tartaglia[$x][$y]" : ' -not present- '),"\n" if $debug; my $ret ; foreach my $yps (0..$y){ #tar_print "\tCACHE:", ( $tartaglia[$x-1][$yps] ? " HIT " : ' -not present- '),"for ".($x - 1)." $yps\n"; $ret += ( $tartaglia[$x-1][$yps] || &tartaglia($x-1,$yps) ); } $tartaglia[$x][$y] = $ret; return $ret; } #} ################################################################################ sub tartaglia_row { my $y = shift; my $x = 0; my @row; tar_print "ROW:".' '.($y)."\n" if $debug; $row[0] = &tartaglia($x,$y+1); foreach my $pos (0..$y-1) {push @row, &tartaglia(++$x,--$y)} return @row; } ################################################################################ sub shrinkn { my $num = shift; my $rex = qr(\d{$dot_after}); if ($num =~ $rex){ return join '','..' x ($dot_after - 1).($dot_after == 1 ? '..' :'')} else {return $num;} } ################################################################################ sub check_output { #my $txt; if (! Exists($ow)) { $out = &outwin } $ow->deiconify( ) if $ow->state() eq 'iconic'; $ow->raise( ) if $ow->state() eq 'withdrawn'; } ################################################################################ sub outwin { $ow = $mw->Toplevel( ); $ow->Icon(-image => $mw->Pixmap(-data => &tart_icon)); my $chars = 'Courier '.$size_out.' '.($bold_out ? 'bold' : ''); $ow->geometry("755x429+708+490"); $ow->optionAdd('*Text.font' => $chars, 20); #'Courier 13 bold' $ow->title(" output "); my $txt = $ow->Scrolled('Text', -scrollbars => 'osoe', -background => 'black', -foreground => 'green', #NO -data => \$cont, )->pack(-expand => 1, -fill => 'both'); #tie *STDOUT, $txt, $txt; return $txt; } ################################################################################ sub help { my @helps = @_; my $hw = $mw->Toplevel( ); $hw->Icon(-image => $mw->Pixmap(-data => &tart_icon)); my $chars = 'Courier '.$size_help.' '.($bold_help ? 'bold' : ''); $hw->geometry("900x450+0+0"); $hw->optionAdd('*Text.font' => $chars, 20); #'Courier 13 bold' #$hw->optionAdd( '*Text.background'=> 'royalblue', 20 ); $hw->title(" help "); my $txt = $hw->Scrolled('Text', -background=>'white', -scrollbars => 'osoe', -background => 'blue3', -foreground => 'gold2', #NO -data => \$cont, )->pack(-expand => 1, -fill => 'both'); $txt->Contents(map {&{$_}} @helps); $txt->Subwidget("yscrollbar")->configure(-background => 'black'); $hw->update; } ################################################################################ # HELP TEXTS SUBROUTINES ################################################################################ sub help_eval { return <<'EOH' * Evaluation * USAGE: enter valid Perl code. ** USE WITH CARE ** This experiment is dedicated mostly to Perl writer that can evaluate some code against any number in the triangle. While traversing the triangle numbers '$_' will be the current number. $_ == 13 will colorize only 13, while $_ == 13 or $_==14 14 too $_ % 7 == 0 will show numbers divisible by 7, reveiling some Sierpinski's pattern too. $_ > 0 can change the background color of the Tartaglia's triangle. EOH } ################################################################################ sub help_com { return <