Games::Puzzles::SendMoreMoneyを試してみた

30分プログラム、その679。Games::Puzzles::SendMoreMoneyを試してみた。
前に誰かが「CPANにはSEND+MORE=MONEYを解くためだけのモジュールがあるんだぜ。ちょううけるwww」と言っていたことを思いだしたので、試してみました。

サンプルコード

my $solver = Games::Puzzles::SendMoreMoney->new(
    values    => [0..9],
    puzzle    => "SEND + MORE = MONEY",
    reporter  => sub { print Dumper($_[0]) },
    validator => sub { return 0 if $_[0]->{S} == 0;
                       return 0 if $_[0]->{M} == 0;
                       return 1; },
);

$solver->solve();

おお、シンプル!
で、さっそく走らせてみたら、ファンがものすごい勢いで回転し始めました。うーん、あんまり頭よさそうじゃないね。

コードを軽く流し読みしてみたけど、普通に全候補を生成して、一個づつチェックしてるっぽい。別に覆面算に最適化されたコードがあるわけじゃないのね。

コマンド化してみました

とりあえず、式を変えるごとにコードを書き直すのは面倒なので、コマンドラインから試せるようにしてみました。

$ perl send-more-money.pl SEND + MORE = MONEY
$VAR1 = {
          'S' => 9,
          'O' => 0,
          'M' => 1,
          'D' => 7,
          'N' => 6,
          'R' => 8,
          'E' => 5,
          'Y' => 2
        };
^C

$ perl send-more-money.pl HACKER + HACKER + HACKER = ENERGY
$VAR1 = {
          'A' => 0,
          'N' => 1,
          'K' => 4,
          'E' => 6,
          'Y' => 9,
          'H' => 2,
          'C' => 5,
          'R' => 3,
          'G' => 8
        };
^C

ソースコード

#! /usr/bin/perl
# -*- mode:perl; coding:utf-8 -*-
#
# prelude.pl -
#
# Copyright(C) 2009 by mzp
# Author: MIZUNO Hiroki / mzpppp at gmail dot com
# http://howdyworld.org
#
# Timestamp: 2009/10/18 21:46:44
#
# This program is free software; you can redistribute it and/or
# modify it under MIT Lincence.
#
use strict;
use warnings;
use Games::Puzzles::SendMoreMoney;
use Data::Dumper;

sub scan($$){
    my ($s,$r) = @_;
    my @xs = ();
    while($s =~ m/$r/g){
	@xs = (@xs, $1);
    }
    @xs;
}

sub solve($){
    my ($s) = @_;
    my @cs = scan $s,'\b(\w)';

    my $solver = Games::Puzzles::SendMoreMoney->new(
	values    => [0..9],
	puzzle    => $s,
	reporter  => sub { print Dumper($_[0]) },
	validator => sub {
	    for my $c (@cs){
		return 0 if $_[0]->{$c} == 0;
	    }
	    return 1;
	});

    $solver->solve();
}

solve(join(" ",@ARGV));