Solving coin problems: Difference between revisions

→‎{{header|Perl}}: step 3: cut down on copy/paste boiler-plate, streamline initialization, clarify need for MAXIMA
(→‎{{header|Perl}}: step 2: much terser output)
(→‎{{header|Perl}}: step 3: cut down on copy/paste boiler-plate, streamline initialization, clarify need for MAXIMA)
Line 504:
 
=={{header|Perl}}==
Coin-type 'word problems' are analyzed into their constituent algebraic relationships, in a format suitable for processing by MAXIMA, a free computer algebra system. NB: MAXIMA <b>must</b> be locally installed for this task to function.
The following code reads a file containing coin problems line-by-line. It echoes comment lines starting with a hashmark and blank lines. Remaining lines are interpreted as coin problems, one per line.
<lang perl>use strict;
use warnings;
 
use List::Util qw(sum uniq);
The program works by matching the english input against patterns for the parts of the coin schema (a)-(e) in the task description. Patterns are expressed as perl regular expressions. It then translates these parameters into a MAXIMA program. MAXIMA is a free, open-source computer algebra system (CAS). It executes the MAXIMA script, extracts the solution, and prints it. By using perl regexes to read the input and MAXIMA to solve the resulting equations, the program may be kept fairly short.
 
ourmy %nums = (
This program has been tested with 28 coin problems (shown below). Here is the program:
zero => 0, one => 1, two => 2, three => 3,
<lang perl>
four => 4, five => 5, six => 6, seven => 7,
# coin.pl
eight => 8, nine => 9, ten => 10, eleven => 11,
# Description: Solve math word problems involving coins.
twelve => 12, thirteen => 13, fourteen => 14, fifteen => 15,
# Usage: perl -CDSA coin.pl coin-problems.txt > output.txt
sixteen => 16, seventeen => 17, eighteen => 18, nineteen => 19,
# Algorithm: NLP processor loosely inspired by Bobrow (1964) transforms
twenty => 20,
# english language coin problems into solvable equations that are
);
# piped into the Maxima computer algebra system.
# Input: File must be UTF-8 text file. One coin problem per line in english.
# Blank lines and comment lines beginning with hash mark ``#'' are OK.
# Output: STDOUT contains original problem, transformed equations and solutions.
 
my(@words,@eqns,@vars,@types);
use strict;
ourmy $float = qr/(?:(?:[1-9][0-9]*\.?[0-9]*)|(?:0?\.[0-9]+))(?:[Ee][+-]?[0-9]+)?/;
use utf8;
use List::Util qw(sum);
use List::MoreUtils qw(uniq);
 
our $first = 0;
our %nums = (
zero => 0, one => 1, two => 2, three => 3,
four => 4, five => 5, six => 6, seven => 7,
eight => 8, nine => 9, ten => 10, eleven => 11,
twelve => 12, thirteen => 13, fourteen => 14, fifteen => 15,
sixteen => 16, seventeen => 17, eighteen => 18, nineteen => 19,
twenty => 20, thirty => 30, forty => 40, fifty => 50,
sixty => 60, seventy => 70, eighty => 80, ninety => 90,
hundred => 100, thousand => 1_000, million => 1_000_000,
billion => 1_000_000_000, trillion => 1_000_000_000_000,
# My ActiveState Win32 Perl uses e-notation after 999_999_999_999_999
quadrillion => 1e+015, quintillion => 1e+018);
 
# Groupings for thousands, millions, ..., quintillions
our $groups = qr/\d{4}|\d{7}|\d{10}|\d{13}|1e\+015|1e\+018/;
 
# Numeral or e-notation
our $num = qr/\d+|\d+e\+\d+/;
 
our $float = qr/(?:(?:[1-9][0-9]*\.?[0-9]*)|(?:0?\.[0-9]+))(?:[Ee][+-]?[0-9]+)?/;
our $count = 0;
our $total = 0;
our @words = ();
our @eqns = ();
our @vars = ();
our @types = ();
 
sub add_type {
Line 560 ⟶ 529:
 
while (<DATA>) {
chomp;
chomp; # chop trailing newline
my ($origcount,$total) = $_(0, 0);
@words = @eqns = @vars = @types = ();
@eqns = ();
@vars = ();
@types = ();
$count = 0;
$total = 0;
 
next if /^\s*$/ or /^\s*#.*$/; # skip blank and comment lines
s/^(|)// if !$first++; # skip utf8 control seq e.g., "" that starts file
next if /^\s*$/; # skip blank lines
# echo comment lines
if( /^\s*#.*$/ ) {
print $_, "\n";
next;
}
s/-/ /g; # convert hyphens to spaces
s/\s\s+/ /g; # remove duplicate whitespace, convert ws to space
s/ $//g; # remove trailing blank
s/^ //g; # remove leading blank
$_ = lc($_); # convert to lower case
 
# tokenize sentence boundaries
s/([\.\?\!]) / $1\n/g;
Line 602 ⟶ 559:
s/(\d) , (\d)/$1 $2/g;
s/(\d) and (\d)/$1 $2/g;
 
s/\b(\d) 100 (\d\d) (\d) (${groups})\b/($1 * 100 + $2 + $3) * $4/eg;
 
s/\b(\d) 100 (\d\d) (${groups})\b/($1 * 100 + $2) * $3/eg;
s/\b(\d) 100 (\d) (${groups})\b/($1 * 100 + $2) * $3/eg;
s/\b(\d) 100 (${groups})\b/$1 * $2 * 100/eg;
 
s/\b100 (\d\d) (\d) (${groups})\b/(100 + $1 + $2) * $3/eg;
s/\b100 (\d\d) (${groups})\b/(100 + $1) * $2/eg;
s/\b100 (\d) (${groups})\b/(100 + $1) * $2/eg;
s/\b100 (${groups})\b/$1 * 100/eg;
 
s/\b(\d\d) (\d) (${groups})\b/($1 + $2) * $3/eg;
s/\b(\d{1,2}) (${groups})\b/$1 * $2/eg;
 
s/\b(\d\d) (\d) 100\b/($1 + $2) * 100/eg;
s/\b(\d{1,2}) 100\b/$1 * 100/eg;
 
# anomolous cases: nineteen eighty-four and twenty thirteen
s/\b(\d{2}) (\d{2})\b/$1 * 100 + $2/eg;
 
s/((?:${num} )*${num})/sum(split(" ",$1))/eg;
2,392

edits