Hatena::ブログ(Diary)

’(mogo-mogo laboratory) このページをアンテナに追加 RSSフィード Twitter

info

2011-08-18

書籍「7つの言語7つの世界」Io言語2日目セルフスタディ

| 18:40 | 書籍「7つの言語7つの世界」Io言語2日目セルフスタディを含むブックマーク 書籍「7つの言語7つの世界」Io言語2日目セルフスタディのブックマークコメント

http://github.com/yppp/sevenlang

二次元配列の総和

dim2sum := method(n, n flatten sum)
dim2sum := method(n, n prepend(0) reduce(x, y, x = x + y sum))

Listに自分で定義した平均を求めるメソッドを追加、数字以外が混ざっていたら例外を投げるように

List myAvg := method(reduce(x, y, if(y proto != Number, Exception raise("二度と数字以外を入れるんじゃねーぞ、バーカ!"), x + y))  / size)

二次元配列を現わすプロトタイプを書くdimはxとyの大きさのリストを確保、ゲッターとセッター、transposeは行列で言う所の転置をするメソッド

Dim2list := Object clone do(
dim := method(x, y, result := list(); y repeat(nl := list(); x repeat(nl append(nil)); result append(nl)); self lis := result);
set := method(x, y, val, self lis at(y) atPut(x, val); self lis);
get := method(x, y, self lis at(y) at(x));
transpose := method(
                        result := Dim2list clone;
                        write(self lis at(0) size, self lis size, "\n");
                        result dim(self lis size, self lis at(0) size);
                        self lis at(0) size repeat(i,
                        self lis size repeat(j,
                        write(i,j,"\n");
                        result set(j, i, self get(i, j)))));
)

ファイルから二次元配列を読んだり書いたりする

maread := method(path, lis := list(); File open(path) readLines foreach(line, lis append(line split(" ") select(v, v != "") map(v, v asNumber))); File open(path) close; lis);
mawrite := method(path, lis, f := File open(path); lis foreach(v, f write(v join(" ") append("\n" at(0)))); File open(path) close;  lis);

数当てゲーム、前の答えより近づいたか遠くなったか答えるたび表示する

hitandblow := method(
           f := File standardInput
           num := (Random value(99) + 1) floor;
           prev := 0;
           10 repeat(i,
           in := f readLine asNumber;
           if(num == in, "hit!" println; break);
           if(prev != 0, if(prev > ((num - in) abs), "near" println, "far" println));
           prev = (num - in) abs;
           if(i == 9, write("fail ", "atarinumber ", num));
           );
)

2011-08-09

書籍「7つの言語7つの世界」Io言語やってみる

| 20:16 | 書籍「7つの言語7つの世界」Io言語やってみるを含むブックマーク 書籍「7つの言語7つの世界」Io言語やってみるのブックマークコメント

フィボナッチ数

fib := method(n, 
    if(n < 2, n, fib(n - 1) + fib(n - 2))
)

Io> fib(10)
==> 55

ループ版

fib := method(n,
    fir ::= 0
    sec ::= 1
    tmp ::= 0
    n repeat(
    tmp = sec
    sec = sec + fir
    fir = tmp
   )
fir
)

fib(31) println

分母がゼロの時答えがゼロになるように

Io> 42 type
==> Number

数字はNumberクラスなんだなぁ

んで

Number / := method(n, if(n == 0, 0, self / n))

これでは無限ループになってしまう

割り算のメソッドをコピーすればいいと思いついたまではよかったけど、どうやって取得できるかで詰まった

# div := / これじゃダメ
div := Number getSlot("/")

Number / := method(n, if(n == 0, 0, self div(n)))

未だに引数がいつ評価されるかわからない

2011-08-06

書籍「7つの言語7つの世界」Rubyの章の最後の問題

| 06:04 | 書籍「7つの言語7つの世界」Rubyの章の最後の問題を含むブックマーク 書籍「7つの言語7つの世界」Rubyの章の最後の問題のブックマークコメント

method_missingテクニックを使って、CSVの一行目にある物をメソッド名にしてあとの二行をその列にある物を表示させる、attr_accessorもこんなふうに実現してるのかなあ

githubリポジトリつくったよ

http://github.com/yppp/sevenlang

# -*- coding:utf-8 -*-

class CsvRow
  def initialize(header, row)
    @header = header.map{|x| x.strip}
    @row = row.map{|x| x. strip}
  end

  def method_missing name, *args
    namest =  name.to_s
    ret = nil
    @header.zip(@row) do |x, y|
      if namest == x then
        ret = y
        break
      end
    end
    super if ret.nil?
    ret
  end
end

module ActsAsCsv
  def self.included(base)
    base.extend ClassMethods
  end
  
  module ClassMethods
    def acts_as_csv
      include InstanceMethods
    end

    module InstanceMethods
      def read
        @csv_contents = []
        filename = self.class.to_s.downcase + '.txt'
        File::open(filename) do |f|
          @headers = f.gets.chomp.split(",")
          f.each do |row|
            @csv_contents << CsvRow::new(@headers, row.chomp.split(","))
          end
        end
      end

      def each(&block)
        @csv_contents.each &block
      end

      attr_accessor :headers, :csv_contents

      def initialize
        read
      end
    end
  end
end


class RubyCsv
  include ActsAsCsv
  acts_as_csv
end

m = RubyCsv::new
m.each{|row| puts row.one}
m.each{|row| puts row.two}
m.each{|row| puts row.teeeee}

読み込ませたcsv

one,two, teeeee
lions, tigers,cat
camel, alpaca,lama

2011-08-05

書籍「7つの言語7つの世界」でRubyの章を読み飛ばそうと思ったけど、一部の問題だけ解く

| 21:24 | 書籍「7つの言語7つの世界」でRubyの章を読み飛ばそうと思ったけど、一部の問題だけ解くを含むブックマーク 書籍「7つの言語7つの世界」でRubyの章を読み飛ばそうと思ったけど、一部の問題だけ解くのブックマークコメント

配列ハッシュにしろ

[1,2,3].zip([[4, 5, 6],5,6]).inject(Hash::new){|x, y| x[y[0]] = y[1]; x}

配列が入れ子じゃなかったら

Hash[*[1,2,3].zip([4,5,6]).flatten]

16個と4個の配列を4個と1個づつで表示させろ

eachを使って

te = Array::new(16){|x| x}
fo = Array::new(4){|x| x}

fo.each.with_index {|x, y| p [fo[y], te[x*4..x*4+3]]} 

each_sliceを使って

te = Array::new(16){|x| x}
fo = Array::new(4){|x| x}
te.each_slice(4).with_index{|x, y| p [fo[y], x]}  

Treeクラスを改造して、ハッシュ木構造に変換

class Tree
  attr_accessor :name, :children

  def initialize(arg)
    if arg[:rootname].nil? then
      @name = arg[:hash].keys[0]
      if arg[:hash].values[0].empty? then                                                                                                 
        @children = []
      else
        @children = arg[:hash].values[0].map do |x, y|                                                                                    
          Tree::new rootname: x,  hash: y
        end
      end                                                                                                                                 

    else
      @name = arg[:rootname]
      if arg[:hash].empty? then
        @children = []
      else
        @children = arg[:hash].map do |x, y|
          Tree::new rootname: x,  hash: y
        end                                                                                                                               
      end
    end
  end

  def visit(&block)
    block.call self
  end

  def visit_all(&block)
    visit &block
    children.each{|x| x.visit_all &block}
  end
end

tree = Tree::new(hash: {grandpa: {dad: {child1: [], child2: []}, uncle: {child3: [], child4: []}}})

tree.visit_all{|x| p x.name}

2011-08-01

RubyでBrainfuck処理系作ってみた

| 21:16 | RubyでBrainfuck処理系作ってみたを含むブックマーク RubyでBrainfuck処理系作ってみたのブックマークコメント

意味無いと思うけどジャンプテーブル構築時についでに命令文字をシンボルにコンパイルするようにしてる

https://github.com/yppp/brainf_ck

# -*- encoding:utf-8 -*-

class Brainfuck
  
  class ProgramError < StandardError
  end

  def initialize(src)
    @souce = src
    @program = []
    @tape = []
    @jmptab = {}
    @pc = 0
    @cur = 0
  end

  def compile
    stack = []

    @program = @souce.chars.map.with_index do |x, y|

      case x
        when '+'
        :inc
        when '-'
        :dec
        when '>'
        :next
        when '<'
        :prev
        when '['
        stack.push y
        :lb
        when ']'
        r = stack.pop
        raise ProgramError, "]が多すぎます" if r.nil?
        @jmptab[y] = r
        @jmptab[r] = y
        :rb
        when '.'
        :dot
        when ','
        :cor
      end

    end

    raise ProgramError, "[が多すぎます" unless stack.empty?
  end

  def exec
    until @program[@pc].nil?
      @tape[@cur] ||= 0
      case @program[@pc]
      when :inc
        @tape[@cur] += 1
      when :dec
        @tape[@cur] -= 1
      when :next
        @cur += 1
      when :prev
        @cur -= 1
      when :lb
        if @tape[@cur] == 0 then
          @pc = @jmptab[@pc]
        end
      when :rb
        if @tape[@cur] != 0 then
          @pc = @jmptab[@pc]
        end
      when :dot
        print @tape[@cur].chr
      when :cor    
        $stdin.getc
      end
      @pc += 1
    end
  end
end

bf = Brainfuck::new "+++++++++[>+++++++++[<[>>+>+<<<-]>>>[<<<+>>>-]<.><<-]>[-]<<-]"
bf.compile
bf.exec