#!/usr/bin/env perl use strict; use warnings; use 5.024; use utf8; use experimental 'signatures'; use open ':std','utf8'; # see http://images.math.cnrs.fr/Dobble-et-la-geometrie-finie.html package FiniteProjectivePlane { use Moo; use experimental 'signatures'; has mod => (is=>'ro',required=>1); sub Inf() { 0+'Inf' } sub multadd($self,$x,$a,$m) { return $a if $x == Inf; return ($x*$a+$m) % $self->mod; } sub range($self) { return 0..($self->mod-1); } sub line($self,$a,$m) { my @ret; if ($a == Inf) { # vertical line @ret = map { [$m,$_] } $self->range; push @ret, [Inf,Inf]; # odd one out } else { @ret = map { [$_,$self->multadd($_,$a,$m)] } $self->range,Inf; } return @ret; } sub scan_lines($self) { my %lines; for my $a ($self->range,Inf) { for my $m ($self->range) { $lines{"$a-$m"} = [ $self->line($a,$m) ]; } } $lines{"Inf-Inf"} = [ $self->line(Inf,Inf) ]; return \%lines; } }; package CardsTable { use Moo; use experimental 'signatures'; has symbols => (is=>'lazy'); has _symbol_for => (is=>'ro',default=>sub{ +{} }); has _last_symbol_used => (is=>'rw',default=>0); has padding => (is=>'ro',default=>0); around BUILDARGS => sub($orig,$self,@args) { my $args = $self->$orig(@args); delete $args->{symbols} unless defined $args->{symbols}; return $args; }; sub _build_symbols($self) { return [ split //, q{🌃🌈🌉🌍🌙🌞🌟🌧🌰🌷🌶🍁🍄🍇🍋🍒🍔🍕🍞🍟🍨🍩🍰🍵🍺🎅🎉🎜🎡🎥🎨🎮🎲🎷🎸🎺🎻🏠🐌🐍🐔🐖🐘🐙🐞🐢🐧🐨🐫🐵🐼👂👁💋👅👒👓👕👖👜👟💉💊💎💲📚📸📱🔋🔦🔩🖂🗹🚀🚁🚲🁂✀✐☃☢☣☺⚽♛⛺😈👼👾💀💄}, ]; } sub _next_symbol($self) { my $l = $self->_last_symbol_used; my $symbol = $self->symbols->[$l]; $self->_last_symbol_used($l+1); return [$symbol,$l]; } sub symbol_for($self,$point) { my $pointid = join ',',$point->@*; if (my $s = $self->_symbol_for->{$pointid}) { return $s; } else { my $s = $self->_next_symbol; $self->_symbol_for->{$pointid} = $s; return $s; } } sub _build_table($self,$lines,$row_coderef) { my @ret = (); # this thing is isomorphic to its dual! we don't need to pivot # lines/points, it's all the same for my $line (sort keys $lines->%*) { my @row; for my $point ($lines->{$line}->@*) { my $symbol = $self->symbol_for($point); my $column = $symbol->[1]; $row[$column] = $symbol->[0]; } push @ret, $row_coderef->( $self->padding ? @row : grep { $_ } @row ); } return \@ret; } sub html_table($self,$lines) { my $ret = $self->_build_table( $lines, sub { return ( '