2014年1月23日木曜日

開発環境

Real World Haskell―実戦で学ぶ関数型言語プログラミング(Bryan O'Sullivan (著)、 John Goerzen (著)、 Don Stewart (著)、山下 伸夫 (翻訳)、伊東 勝利 (翻訳)、株式会社タイムインターメディア (翻訳)、オライリージャパン)の3章(型を定義し、関数を単純化する)、3.13(ガードの条件節の評価)、練習問題 12.をDartで解いてみる。

その他参考書籍

練習問題 12.

コード

sample.dart

import 'dart:html';

void main(){
  run.onClick.listen((MouseEvent){
    pre.text = window.navigator.userAgent + '\n';
    try{
      var nums = input_nums.value.split(',')
          .map((String s) => num.parse(s.trim()));
      if(nums.length % 2 != 0){
        throw '点の集合になっていない。';
      }
      List<Point> points = [];
      while(nums.length != 0){
        var pairs = nums.take(2);
        points.add(new Point(pairs.first, pairs.last));
        nums = nums.skip(2);
      }
      pre.text += '2次元平面上の点: $points\n';
      var a = grahamScan(points);
      pre.text += 'Graham scan: $a\n';
      pre.text += 'Directions: ${getDirections(a)}\n';
    } catch (e){
      pre.text += '$e\n';
    }
  });
  clear.onClick.listen((MouseEvent event) => pre.text = '');
}

InputElement input_nums = querySelector('#input_nums');
ButtonElement run = querySelector('#run_dart');
ButtonElement clear = querySelector('#clear');
PreElement pre = querySelector('#pre0');

List<Point> grahamScan(List<Point> points){
  var kernel = findLowestPoint(points);
  var sorted_points = sortedPoints(kernel, points);
  return grahamScanRecursive(kernel, sorted_points);
}

List<Point> grahamScanRecursive(Point kernel, List<Point> points){
  if(points.length < 2){
    throw 'エラー: grahamScanRecursive';
  }
  if(points.length == 2){
    var p1 = points[0];
    var p2 = points[1];
    var d = new Direction(p1, p2, kernel).direction;
    return d == 'Left turn' ? [p1, p2] : [p2];
  }
  var p1 = points[0];
  var p2 = points[1];
  var p3 = points[2];
  var new_points = points.sublist(3);
  List<Point> result = [];
  if(p1 == p2){
    result.addAll([p1, p3]);
  } else if(p1 == p3){
    result.add(p1);
  } else if(p2 == p3){
    result.addAll([p1, p2]);
  } else if(new Direction(p1, p2, p3).direction == 'Left turn'){
    result.addAll([p2, p3]);
    result.addAll(new_points);
    List<Point> new_result = [p1];
    new_result.addAll(grahamScanRecursive(kernel, result));
    return new_result;
  } else {
    result.addAll([p1, p3]);
  }
  result.addAll(new_points);
  return grahamScanRecursive(kernel, result);
}

Point findLowestPoint(List<Point> points){
  var lowest = points.first;
  for(var p in points.sublist(1)){
    lowest = lowest.lowerPoint(p);
  }
  return lowest;
}

List<Point> sortedPoints(Point kernel, List<Point> points){
  var new_points = points.toList();
  new_points.sort((Point p1, Point p2) => p1.comparePoint(kernel, p2));
  return new_points;
}

List<Direction> getDirections(List<Point> points){
  if(points.length < 3){
    return [];
  }
  var result = [];
  result.add(new Direction(points[0], points[1], points[2]));
  result.addAll(getDirections(points.sublist(1)));
  return result;
}

class Point{
  num x;
  num y;
  Point(this.x, this.y);
  bool operator ==(Point p) => x == p.x && y == p.y;
  Point lowerPoint(Point p){
    var py = p.y;
    if(y < py){
      return this;
    }
    if(y > py){
      return p;
    }
    var px = p.x;
    if(x < px){
      return this;
    }
    return p;
  }
  int comparePoint(Point kernel, Point p){
    if(this == p){
      return 0;
    }
    var cow = (x - kernel.x) * (p.y - kernel.y) -
        (y - kernel.y) * (p.x - kernel.x);
    if(cow > 0){
      return -1;
    }
    if(cow < 0){
      return 1;
    }
    if(x < p.x){
      return -1;
    }
    return 1;
  }
  String toString() => '($x, $y)';
}

class Direction{
  String direction;
  Direction(Point a, Point b, Point c){
    var cow = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
    direction = cow > 0 ?
        'Left turn' : cow == 0 ?
            'Collinear' : 'Right turn';
  }
  String toString(){
    return direction;
  }
}
















						

0 コメント:

コメントを投稿