GWTを使ってMATH QUIZを解くプログラムを作ってみる

先日、「これが解けたらIQ 125」という記事を見つけました。「9=72、8=56、7=42、6=30、5=20 のとき、3=?? の ?? にあてはまる数字は?」という問題です。

記事:解けたらIQ 125? Twitterである問題が話題に

そこで、GWT(Google Web Toolkit)を使って、IQ 125のプログラムを作ってみました! FireFox (ver.22) と InternetExplorer (ver.9) で動作することを確認しています

今回作成したプログラムの実行ページ

Condition(条件)に「9=72」「8=56」「7=42」「6=30」「5=20」を登録し、Question(問題)に「3」を入れ、Solve(計算)ボタンを押すと、答えが表示されます。

実行結果

ちゃんと、答えることができています!
まぁ、多項式の連立方程式を解いているだけなんですけどね。

この手の問題を考えていると、人間の直観的な考え方とコンピュータの数値計算の考え方には結構な違いがあるものだなと思ったりします。

追記:このクイズの内容について少しまじめに考えてみました。
ちょっとだけMATH QUIZを考察してみる

ちなみに、今回作成したプログラムのソースコードはこちら。
お遊びとして作っただけなので、コメントもなければ、コードの整理もしていません。

Polynomial.java
package jp.takedarts.gwt.polynomial.client;

import java.util.ArrayList;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

/**
 * A program for solving a polynomial simultaneous equation.
 *
 * @author Atsushi TAKEDA
 */
public class Polynomial
  implements EntryPoint
{
  private ArrayList _conditions = new ArrayList();

  private final VerticalPanel _mailPanel = new VerticalPanel();

  private final Label _conditionLabel = new Label("-- Condition");

  private final HorizontalPanel _conditionAddPanel = new HorizontalPanel();

  private final VerticalPanel _conditionViewPanel = new VerticalPanel();

  private final Label _questionLabel = new Label("-- Question");

  private final HorizontalPanel _questionPanel = new HorizontalPanel();

  private final VerticalPanel _answerPanel = new VerticalPanel();

  private final Button _clearButton = new Button("CLEAR");

  private final TextBox _conditionAddKeyTextBox = new TextBox();

  private final Label _conditionAddEqualLabel = new Label("=");

  private final TextBox _conditionAddValueTextBox = new TextBox();

  private final Button _conditionAddButton = new Button("ADD");

  private final TextBox _questionKeyTextBox = new TextBox();

  private final Label _questionExclamationLabel = new Label(" = ?");

  private final Button _questionSolveButton = new Button("SOLVE");

  /**
   * This is the entry point method.
   */
  public void onModuleLoad()
  {
    _mailPanel.setSpacing(2);
    RootPanel.get().add(_mailPanel);
    _conditionLabel.setStyleName("title-label");

    _mailPanel.add(_conditionLabel);

    _mailPanel.add(_conditionViewPanel);
    _conditionAddPanel.setSpacing(2);

    _mailPanel.add(_conditionAddPanel);
    _conditionAddKeyTextBox.setVisibleLength(3);
    _conditionAddPanel.add(_conditionAddKeyTextBox);
    _conditionAddPanel.setCellVerticalAlignment(_conditionAddKeyTextBox, HasVerticalAlignment.ALIGN_MIDDLE);
    _conditionAddPanel.add(_conditionAddEqualLabel);
    _conditionAddPanel.setCellVerticalAlignment(_conditionAddEqualLabel, HasVerticalAlignment.ALIGN_MIDDLE);
    _conditionAddValueTextBox.setVisibleLength(3);
    _conditionAddPanel.add(_conditionAddValueTextBox);
    _conditionAddPanel.setCellVerticalAlignment(_conditionAddValueTextBox, HasVerticalAlignment.ALIGN_MIDDLE);
    _conditionAddButton.addClickHandler(new ClickHandler() {
      public void onClick(ClickEvent event)
      {
        _performAddButonClicked(event);
      }
    });
    _conditionAddPanel.add(_conditionAddButton);
    _conditionAddPanel.setCellVerticalAlignment(_conditionAddButton, HasVerticalAlignment.ALIGN_MIDDLE);
    _questionLabel.setStyleName("title-label");

    _mailPanel.add(_questionLabel);
    _questionPanel.setSpacing(2);

    _mailPanel.add(_questionPanel);
    _questionKeyTextBox.setVisibleLength(3);
    _questionPanel.add(_questionKeyTextBox);
    _questionPanel.setCellVerticalAlignment(_questionKeyTextBox, HasVerticalAlignment.ALIGN_MIDDLE);
    _questionPanel.add(_questionExclamationLabel);
    _questionPanel.setCellVerticalAlignment(_questionExclamationLabel, HasVerticalAlignment.ALIGN_MIDDLE);

    _mailPanel.add(_answerPanel);
    _clearButton.addClickHandler(new ClickHandler() {
      public void onClick(ClickEvent event)
      {
        _performClearButtonClicked(event);
      }
    });
    _mailPanel.add(_questionSolveButton);
    _questionSolveButton.addClickHandler(new ClickHandler() {
      public void onClick(ClickEvent event)
      {
        _performSolveButtonClicked(event);
      }
    });

    _mailPanel.add(_clearButton);
  }

  private void _performAddButonClicked(ClickEvent event)
  {
    String key = _conditionAddKeyTextBox.getText();
    String val = _conditionAddValueTextBox.getText();

    if (key.length() == 0 || val.length() == 0) {
      return;
    }

    try {
      Label label = new Label();

      _conditions.add(new Condition(Double.parseDouble(key), Double.parseDouble(val)));

      label.setText("[cond." + _conditions.size() + "] " + key + " = " + val);
      label.setStyleName("cond-label");

      _conditionViewPanel.add(label);
      _conditionAddKeyTextBox.setText("");
      _conditionAddValueTextBox.setText("");
    }
    catch (NumberFormatException ex) {
    }
  }

  private void _performSolveButtonClicked(ClickEvent event)
  {
    String key = _questionKeyTextBox.getText();

    if (_conditions.size() < 2 || key.length() == 0) {
      return;
    }

    _questionKeyTextBox.setText("");
    _answerPanel.clear();

    try {
      Resolver resolver = new Resolver(_conditions.size());

      for (Condition condition : _conditions) {
        resolver.add(condition.getKey(), condition.getValue());
      }

      Label title_label = new Label();
      Label answer_label = new Label();

      title_label.setText("-- Answer");
      title_label.setStyleName("title-label");
      answer_label.setStyleName("answer-label");

      if (resolver.resolve(Double.parseDouble(key))) {
        answer_label.setText(key + " = " + resolver.getAnswer());
      }
      else {
        answer_label.setText("N/A");
      }

      _answerPanel.add(title_label);
      _answerPanel.add(answer_label);
    }
    catch (NumberFormatException ex) {
    }
  }

  private void _performClearButtonClicked(ClickEvent event)
  {
    _conditions.clear();
    _conditionViewPanel.clear();
    _conditionAddKeyTextBox.setText("");
    _conditionAddValueTextBox.setText("");
    _questionKeyTextBox.setText("");
    _answerPanel.clear();
  }

  private static class Condition
  {
    private double _key = 0.0;

    private double _value = 0.0;

    public Condition(double key, double value)
    {
      _key = key;
      _value = value;
    }

    public double getKey()
    {
      return _key;
    }

    public double getValue()
    {
      return _value;
    }
  }

  private static class Resolver
  {
    private double[][] _matrix = null;

    private double[] _factors = null;

    private int _count = 0;

    private double _answer = 0;

    private boolean _resolved = false;

    private boolean _caluclated = false;

    public Resolver(int factors)
    {
      _matrix = new double[factors][factors + 1];
      _factors = new double[factors];
    }

    public void add(double key, double value)
    {
      int dimension = _matrix[_count].length - 1;

      for (int i = 0; i < dimension; i++) {
        _matrix[_count][i] = 1;

        for (int j = 0; j < i; j++) {
          _matrix[_count][i] *= key;
        }
      }

      _matrix[_count][dimension] = value;

      _count++;
    }

    public boolean resolve(double key)
    {
      if (_caluclated) {
        return _resolved;
      }

      _caluclated = true;
      _resolved = false;
      _answer = 0.0;

      for (int i = 0; i < _matrix.length - 1; i++) {
        for (int j = i + 1; j < _matrix.length; j++) {
          double r = _matrix[j][i] / _matrix[i][i];

          _matrix[j][i] = 0;

          for (int k = i + 1; k < _matrix[j].length; k++) {
            _matrix[j][k] -= _matrix[i][k] * r;
          }
        }
      }

      for (int i = _matrix.length - 1; i >= 0; i--) {
        double v = _matrix[i][_matrix[i].length - 1];

        if (_matrix[i][i] == 0) {
          return _resolved;
        }

        for (int j = 0; j < _factors.length; j++) {
          v -= _matrix[i][j] * _factors[j];
        }

        _factors[i] = v / _matrix[i][i];
      }

      for (int i = 0; i < _factors.length; i++) {
        double v = _factors[i];

        for (int j = 0; j < i; j++) {
          v *= key;
        }

        _answer += v;
      }

      _resolved = true;

      return _resolved;
    }

    public double getAnswer()
    {
      return _answer;
    }
  }
}
カテゴリー: 雑記 タグ: , , パーマリンク