Kishima's Hateda log

はてなダイアリー記事の保管庫

Kawasaki.rb #3でmrubyの簡単な紹介をしてきた。


ものすごく時間が立ってしまいましたが、8/28のKawasaki.rb*1でmrubyの簡単な紹介と、そのちょっとしたサンプルとして、webrubyを使って作った抽選スクリプトの紹介をしてきました。
その資料を置いておきます。

webruby & enchant.jsを使って作ったスクリプトの実物は下記にあります。

http://silentworlds.info/webruby/

ソースコードはこんな感じ

# -*- coding: utf-8 -*-
class Candidates
  def parse
     ret = 
'user01,abcd,0
 user02,efgh,1
 user03,ijkl,0
 '.strip.split("\n").map{|line| line.strip.split(",")}
    ret.each {|d|
       d.map!{|e| e.strip }
    }
    return ret
  end
  def initialize
    @list = parse()
  end
  def name(i)
    @list[i][0]
  end
  def angle(i)
    w = @list[i][1]
    hashno = w.hash>=0 ? w.hash : w.hash*-1
    hashstr = sprintf("%04d",hashno%10000).to_s
    hashstr[0..1].to_i
  end
  def velocity(i)
    w = @list[i][1]
    hashno = w.hash>=0 ? w.hash : w.hash*-1
    hashstr = sprintf("%04d",hashno%10000).to_s
    v = hashstr[2..3].to_i
    v = v*2 if @list[i][2]=="1"
    v
  end
  def flag(i)
    @list[i][2]
  end
  def max
    @list.size
  end
end

#=================================
class Enchant
  def initialize
    @root=MrubyJs.get_root_object
    @stage_x = 640
    @stage_y = 320
  end
  def set_position(name,x,y)
    @root.call(name,x,y)
  end  
  def stop_loop
    @root.call('stopTimerLoop')
  end
  def update_ranking(text)
    @root.call('updateRanking',text)
  end
  def update_mbox(text)
    @root.call('updateMbox',text)
  end
  def update_sub(text)
    @root.call('updateSub',text)
  end
  def invisible
    @root.call('invisibleKuma')
  end
  attr_accessor :stage_x, :stage_y
end

#=================================
class Log
  def put(msg)
  	root = MrubyJs.get_root_object
    box = root.call('$', '#container')
    box.call('append', "<p>"+msg+"</p>")
  end
end

#=================================
class Target
  def initialize(a,v)
    @angle = (20.0+60.0*a/100.0) * Math::PI / 180.0
    @velocity = 12.0* 100.0*((v/100.0)**(0.3))/100.0
    @x = 0.0
    @ground = 400.0
    @y = @ground
    @root = MrubyJs.get_root_object
    @flag=false
    @enchant = Enchant.new
  end
  def update(count)
    t = count
    g = 0.3
    @x = 1.0 * @velocity * Math::cos(@angle) * t
    @y = @ground - (@velocity * Math::sin(@angle)*t - 0.5*g*t*t)
    #@x=0 if @x>@enchant.stage_x
    if @y>@ground
      @y=@ground
      @flag=true
    end
    #Log.new.put("count="+count.to_s+" x="+x.to_s)
    @enchant.set_position(:setKuma,x,y)
  end
  def finish?
    @flag
  end
  attr_accessor :angle, :velocity, :x, :y
end
#=================================
class RankingList
  def initialize
    @max = 2 #**** max LT talker number ****
    @list={}
  end
  def add(name,record)
    @list.store(name,record)
  end
  def sort
    @list.to_a.sort{|a, b|
      (b[1] <=> a[1]) * 2 + (a[0] <=> b[0])
    }
  end
  def get_top(n)
    sorted = sort()
    return sorted[n]
  end
  def to_s
    text="[Ranking]<br>"
    length = @max > @list.length ? @list.length : @max
    (1..length).each{|n|
      r = get_top(n-1)
      text = text + "No."+n.to_s+" : "+r[0]+" さん / "+r[1].round.to_s+"m<br>"
    }
    text
  end
  def rank(name)
    sorted = sort()
    (1..sorted.length).each{|n|
      return n if sorted[n-1][0] == name
    }
  end
  attr_reader :max
end
#=================================
class EventState
  def initialize
    @state = :init
    @l=Log.new
    @count = 0
    @js_state
    @change_flag=true
    @changed_count = -1
    @enchant = Enchant.new
    @ranking = RankingList.new
    @candidates = Candidates.new
     #--------------
    @target_no=0 
  end

  def act(c,js)
    @count = c
    @js_state = js

    if(@state==:init)
       do_init
    elsif(@state==:throwing_start)
       do_throwing_start
    elsif(@state==:throwing)
       do_throwing
    elsif(@state==:throwing_end)
       do_throwing_end
    elsif(@state==:finish_choosing)
       do_finish_choosing
    else
    end
    @change_flag=false if @change_flag==true && @changed_count!=@count
  end

  def change(n)
    @l.put("change state : "+@state.to_s+" -> "+n.to_s)
    @state=n

    @change_flag=true
    @changed_count = @count
  end

  def check(n)
    @state==n
  end
  
  def do_init
    @enchant.update_mbox('Lets start Chusen<br>atari =
    '+RankingList.new.max.to_s+"<br>Press Enter")
    if @js_state == 1
      change(:throwing_start)
    end
  end

  #-------
  def do_throwing_start
    if(@change_flag)
      @enchant.update_mbox("")
      @enchant.update_sub(@candidates.name(@target_no)+"さん")
      @init_count=@count
    end
    change(:throwing) if @count-@init_count>40
  end

  #------
  def do_throwing
    if(@change_flag)
      @l.put("init")
      no = @target_no
      @l.put(@candidates.name(no))
      @l.put(@candidates.angle(no).to_s)
      @l.put(@candidates.velocity(no).to_s)
    
      d1=@candidates.angle(no)
      d2=@candidates.velocity(no)
      @init_count=@count
      @target = Target.new(d1,d2)
    end
    change(:throwing_end) if @target.finish?
    @target.update(@count-@init_count)    
  end
  
  #-------
  def do_throwing_end
    if(@change_flag)
      @ranking.add(@candidates.name(@target_no),@target.x)
      @l.put @ranking.to_s
      @enchant.update_ranking(@ranking.to_s)
      @enchant.update_mbox( "Rank=>"+@ranking.rank(@candidates.name(@target_no)).to_s)
      @init_count=@count
    end
    # @enchant.update_sub("")
    if @count-@init_count<60
      return
    end
    candidates = Candidates.new
    @target_no += 1
    if @target_no >= candidates.max
      change(:finish_choosing)
    else
      change(:throwing_start)
    end
  end
  
  #--------
  def do_finish_choosing
    @l.put("do_finish_choosing")
    @enchant.invisible
    @enchant.stop_loop
    @enchant.update_mbox("")
    @enchant.update_sub("")
    @enchant.update_ranking("")
    @enchant.update_mbox("Result "+@ranking.to_s)
  end
  
end

#==========================
class CoreProcess
  def run(root)
    l=Log.new
    count=0.0
    state = EventState.new

    prc = Proc.new {|js_state|
      state.act(count,js_state)
      count+=1.0
    }
    root.call(:setEnterframeListener, prc)
    root.call(:timerloop)
  end
end

root = MrubyJs.get_root_object
core = CoreProcess.new
core.run(root)