#!/usr/bin/env perl use strict; use warnings; use constant DEBUG => 0; use constant FUZZINESS => 1e-15; use Scalar::Util 'looks_like_number'; my %vals = map { $_ => rand } 'a' .. 'z'; my @equations = ( 'x + y', 'x - y', 'x * y', 'x / y', 'x % y', 'x ^ y', 'x * (y + z)', 'x / (y + z)', '(x + y) * (x + y)', '(x + y) * (x - y)', ); EQUATION: for my $equation (@equations) { TRY: while (1) { print '-' x 40, "\n"; print "Base equation: $equation\n"; print 'Try/Skip/Quit (t/s/q) [t]: '; my $choice = <>; next EQUATION if $choice =~ /^s/i; last EQUATION if $choice =~ /^q/i; print 'Equivalent equation: '; my $try = <>; chomp $try; if (equivalent($equation, $try)) { print "'$equation' and '$try' are equivalent.\n"; print 'Try again (y/n) [n]: '; my $choice = <>; next TRY if $choice =~ /^y/i; last TRY; } else { print "'$equation' and '$try' are not equivalent.\n"; next TRY; } } } sub equivalent { my ($equation, $try) = @_; my $eqn_val = get_value($equation); return 0 unless defined $eqn_val; my $try_val = get_value($try); return 0 unless defined $try_val; return abs($eqn_val - $try_val) < FUZZINESS ? 1 : 0; } sub get_value { my $in_equation = shift; print "get_value($in_equation)\n" if DEBUG; (my $equation = $in_equation) =~ s/([a-z])/$vals{$1}/g; $equation =~ s/\^/**/g; print "SUBS: $equation\n" if DEBUG; my $value = eval { eval $equation; }; if ($@) { warn $@; return undef; } if (not defined $value && length $value && looks_like_number $value) { warn "!!! BAD EQUATION: '$in_equation'\n"; return undef; } print "VALUE: $value\n" if DEBUG; return $value; }