collatz_triangle.pl 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. #!/usr/bin/perl
  2. # Author: Daniel "Trizen" Șuteu
  3. # License: GPLv3
  4. # Date: 21 May 2015
  5. # https://github.com/trizen
  6. #
  7. ## Generate a triangle with the collatz numbers
  8. #
  9. # Each pixel is highlighted based on the path frequency;
  10. # For example: 4 2 1 are the most common number paths and
  11. # they have the highest frequency and a hotter color (reddish),
  12. # while a less frequent path is represented by colder color (bluish);
  13. # in the middle lies the average frequency, represented by a greenish color.
  14. use 5.010;
  15. use strict;
  16. use warnings;
  17. use GD::Simple;
  18. use List::Util qw(max sum);
  19. my %collatz;
  20. sub collatz {
  21. my ($n) = @_;
  22. while ($n > 1) {
  23. if ($n % 2 == 0) {
  24. $n /= 2;
  25. }
  26. else {
  27. $n = $n * 3 + 1;
  28. }
  29. $collatz{$n}++;
  30. }
  31. return 1;
  32. }
  33. my $k = 10000; # maximum number (duration: about 2 minutes)
  34. for my $i (1 .. $k) {
  35. collatz($i);
  36. }
  37. my $i = 1;
  38. my $j = 1;
  39. my $avg = sum(values %collatz) / scalar(keys %collatz);
  40. say "Avg: $avg";
  41. my $max = max(keys %collatz);
  42. my $limit = int(sqrt($max)) - 1;
  43. # create a new image
  44. my $img = GD::Simple->new($limit * 2, $limit + 1);
  45. my $white = 0;
  46. for my $m (reverse(0 .. $limit)) {
  47. $img->moveTo($m, $i - 1);
  48. for my $n ($j .. $i**2) {
  49. if (exists $collatz{$j}) {
  50. my $v = $collatz{$j};
  51. my $ratio = $avg / $v;
  52. my $red = 255 - int(255 * $ratio);
  53. my $blue = 255 - int(255 / $ratio);
  54. $red = 0 if $red < 0;
  55. $blue = 0 if $blue < 0;
  56. $img->fgcolor($red, 255 - (int(($red + $blue) / 2)), $blue);
  57. $white = 0;
  58. }
  59. elsif (not $white) {
  60. $white = 1;
  61. $img->fgcolor('white');
  62. }
  63. $img->line(1);
  64. ++$j;
  65. }
  66. ++$i;
  67. }
  68. open my $fh, '>:raw', 'collatz.png';
  69. print $fh $img->png;
  70. close $fh;