せかいや

いまいるここを、おもしろく http://sekai-in-the-box.appspot.com/

【Ruby】【アルゴリズム】重複組み合わせ。師匠Ver

重複組み合わせはFor文でシンプルに書けてすごい!
と書いていたら師匠からメールが来た。

■以前のコード

i = 0
while i < 10
  j = i
  while j < 10
      k = j
      while k < 10
        m = k
        while m < 10
          result << "#{i},#{j},#{k},#{m}"
          m += 1
        end
        k += 1
      end
    j += 1
  end
  i += 1
end
p result.length


■師匠のメール

(1..9).each do |i|
  (i..9).each do |j|
    (j..9).each do |k|
      (k..9).each do |m|
        result << "#{i},#{j},#{k},#{m}"
      end
    end
  end
end
終わってくれることが保障されてるし、
制御変数を意識せんでいいしね。


なるほど!

確かにこのインクリメント変数、不細工だな~って思ってたんだよね。
それによく、インクリメントする値を「0」にtypoしてしまうし↓

m = 0
while m < 10
  p "hoge"
  m += 0  ←コレ
end

初期値を0と書くから、つられてインクリメントも「0」って書いちゃうんだよね。


ぷっ(自分でウケてる)


一つ賢くなった!
 

【SCSS】【Webデザイン】背景にグラデーションを入れる

昨晩はアルゴリズムを考えすぎたためか
謎の頭痛が治まらず、何回も吐いた位ひどかったので
今日はサイトのデザインとか、そういうふわっとしたことを勉強しています。

すごいよね。
考えすぎて吐くなんて。
今まで生きてきて経験ないわ。。


 
不思議なもので
楽しいことを考える(プリンとか)⇒頭痛くならない
アルゴリズムを考える(魔法陣とか)⇒死にそうに頭が痛くなる

 
っていう。
やばい。
まだ本調子ではない。


SCSSの導入

CSS3はマルチブラウザ対応が必要で記述が煩雑です↓

 .animefont {
  -moz-opacity: 0;
  -webkit-opacity: 0;
  -khtml-opacity: 0;
  opacity: 0;
}

SCSSを使うことですっきりしました

@mixin css3($property, $value) {
  @each $prefix in -webkit-, -moz-, -ms-, -o-, '' {
    #{$prefix}#{$property}: $value;
  }
}
.animefont {
  @include css3(opacity, 0);
}

興味があればこのコミットでいじっているので参照ください


 

背景をグラデーション

背景にちょっとグラデーションを加えたくなる。

■before↓
水色べた塗り。これも可愛くて悪くないけどね。
f:id:sekaiya:20130915132629j:plain

■理想の背景
ごくわずかにグラデーションをつけたい。


■おすすめ情報
Webのカラーを見るサイトはたくさんあるけれど、
ここが1番重宝してます
同色相で明度だけ変えたい、が1番見やすいと思う。


■嵌ったところ
グラデーションを指定するbodyに、高さを指定する必要がある。
bodyの高さは、htmlタグに依存するので、以下を加える↓

html {height:100%;}


 
■開発中の画面
こんな感じで、あえて始点をredにして、分かりやすくしているよ。
ちょっと禍々しい。
f:id:sekaiya:20130915132641j:plain


■htmlでheightを指定していないと、
こんな風にグラデーションが途中で切れちゃう↓
f:id:sekaiya:20130915132646j:plain


 
■グラデーションのCSS
FireFoxだけ記述が違うみたい。

background: -moz-linear-gradient(top, #4ccfff, #00bfff); 
background: -webkit-gradient(linear, left top, left bottom, from(#4ccfff), to(#00bfff)); 

 
■after
わずかにグラデーションが入ってます。
控えめなのがおしゃれの秘訣!
f:id:sekaiya:20130915132703j:plain

 
と思ったけれども、
今のサイトは、クリックされたメニューによって高さが動的に変わる作りだから
グラデーションは複雑になる。。

ということで取りやめ。
変わりに、コンテンツボックスの色を少し明るくすることで
おしゃれ感を取り入れました。


http://sekai-in-the-box.appspot.com/

 
っていうか頭痛いときにアニメーションは、、辛い。

【Ruby】【アルゴリズム】逆ポーランド記法

テンパズルを解くために下準備中。

おなじみ、テンパズルとは。

1から9までの、1桁の数字がかかれたカードが4枚ある。
この数字をそれぞれ1回ずつ使い、10になるように計算する。

あれです。
駅の切符とか、ナンバープレートとかで暇つぶしにやるあれ。

え?自分は当然そんな習慣ないです。
そんなことばっかり考えてる男性ってなんか辛気臭い。みたいな。

髪のチェックとかしてるよ。
女子だから。


まずは、逆ポーランドから。

逆ポーランド記法(ぎゃくポーランドきほう、英語:Reverse Polish Notation, RPN)とは、数式やプログラムを記述する方法(記法)の一種。演算子(オペレータ)を被演算子オペランド)の後(右)に記述することから、後置記法(Postfix Notation)とも言う。

http://ja.wikipedia.org/wiki/%E9%80%86%E3%83%9D%E3%83%BC%E3%83%A9%E3%83%B3%E3%83%89%E8%A8%98%E6%B3%95

"15+23+*" ⇒30

 

実装したコード

10分で書けた!すごい!

def _calc(num1, num2, operator)
  raise "argument is not correct" if num1.nil? || num2.nil?
  a = num1.to_f ; b = num2.to_f
  return a + b if operator == "+"
  return a - b if operator == "-"
  return a * b if operator == "*"
  return a / b if operator == "/"
end
def calculate(str)
  num_stack = []
  datas = str.split("")
  datas.each do |data|
    if data =~ /\d/
      num_stack << data 
    else
      a = num_stack.pop
      b = num_stack.pop
      num_stack << _calc(b, a, data)
    end
  end
    raise "argument is not correct" if num_stack.length != 1
    num_stack
end

p calculate("15+23+*")

■実行結果

30.0

【Ruby】【アルゴリズム】10パズルを解く。全ての数式を逆ポーランドで作る編

4桁の数字から全ての数式のパターンを列挙する。
数式は逆ポーランド記法で記述する。
(例)"12+3+4+"


 
すごい!30分で書けた!
もう再帰は見切ったぞ。

 

dupでコピーをとりながら再帰を回す(必要に応じて深いコピー)
・終了条件を満たしたものをresult配列に詰め込む

のポイントだけ押さえれば、後は応用が効く。
 
吐きながら勉強した甲斐があった><

 

コード

class Calc
  def self.make_expression(str)
    @@data = str.split("")
    @@operatars = ["+","-","*","/"]
    _make_rpn([], [], [0,0,0,0], 0, 0)
  end
  def self._make_rpn(result, candidate, is_uesd, num_count, ope_count)
    return result << candidate.join('') if num_count+ope_count == 7
    return if  num_count+ope_count > 7
    if num_count - ope_count >=2
      @@operatars.each do |ope|
        tmp = candidate.dup
        tmp << ope
        self._make_rpn(result, tmp, is_uesd, num_count, ope_count + 1)
      end
    end
    if num_count < 4
      is_uesd.each_with_index do |isused, idx|
        if isused == 0
          tmp = is_uesd.dup
          tmp2 = candidate.dup
          tmp[idx] = 1
          tmp2 << @@data[idx]
          self._make_rpn(result, tmp2, tmp, num_count + 1, ope_count)
        end
      end
    end
    result
  end
end

p Calc.make_expression("1234")


 

ポイント

・与えられた数字を、最初は定数化しようと思ったけれどもRubyはメソッド内では定数が定義できない。
 ⇒クラスを作ってクラス定数に。


 
■実行結果

["12+3+4+", "12+3+4-", "12+3+4*",
 "132+/4-", "132+/4*", "132+/4/",
 "143*2**", "143*2*/", "143*2/+",
 "23*4-1/", "23*4*1+", "23*4*1-",
 "2413/-+", "2413/--", "2413/-*",
 "32-1+4-", "32-1+4*", "32-1+4/", 
などなど。

【Ruby】【アルゴリズム】10パズルを解く。ファイナルアンサー。回答全部入り。

振り返り。テンパズルとは。

1から9までの、1桁の数字がかかれたカードが4枚ある。
この数字をそれぞれ1回ずつ使い、10になるように計算する。

あれです。
駅の切符とか、ナンバープレートとかで暇つぶしにやるあれ。

方法

1.計算順序を考えるのは大変なので、逆ポーランド記法でパターンを列挙する
 ⇒この記事でやりました
2.逆ポーランド記法を計算するメソッドを作る
 ⇒この記事でやりました
3.4つの数の組み合わせを列挙するメソッドを作る
 ⇒この記事でやりました


ここまできたらあとは計算するだけなので、先が見えています。

ポイント

0で割り算するとinfinityとなり、to_iメソッドを呼び出すとエラーになります。
0で割り算するときは答えが0になると定義しました。

コード

class Calc
  def self.make_expression(str)
    @@data = str.split("")
    @@operatars = ["+","-","*","/"]
    _make_rpn([], [], [0,0,0,0], 0, 0)
  end
  def self._make_rpn(result, candidate, is_uesd, num_count, ope_count)
    return result << candidate.join('') if num_count+ope_count == 7
    return if  num_count+ope_count > 7
    if num_count - ope_count >=2
      @@operatars.each do |ope|
        tmp = candidate.dup
        tmp << ope
        self._make_rpn(result, tmp, is_uesd, num_count, ope_count + 1)
      end
    end
    if num_count < 4
      is_uesd.each_with_index do |isused, idx|
        if isused == 0
          tmp = is_uesd.dup
          tmp2 = candidate.dup
          tmp[idx] = 1
          tmp2 << @@data[idx]
          _make_rpn(result, tmp2, tmp, num_count + 1, ope_count)
        end
      end
    end
    result
  end
  def self.exe(str)
    num_stack = []
    datas = str.split("")
    datas.each do |data|
      if data =~ /\d/
        num_stack << data 
      else
        a = num_stack.pop
        b = num_stack.pop
        tmp = _calc(b, a, data) 
        if tmp
          num_stack << tmp 
        else
          return "0"
        end
      end
    end
      raise "argument is not correct" if num_stack.length != 1
      num_stack[0]
  end
  def self._calc(num1, num2, operator)
    raise "argument is not correct" if num1.nil? || num2.nil?
    a = num1.to_f ; b = num2.to_f
    return a + b if operator == "+"
    return a - b if operator == "-"
    return a * b if operator == "*"
    if operator == "/"
      return a / b if b !=0
      return false
    end
  end
end

candidates =  Calc.make_expression("1234")
answers = []
candidates.each do |cand|
  answers << cand if Calc.exe(cand).to_i == 10
end
p "there are #{answers.length} answers"
p answers


■実行結果

"there are 48 answers"
["99*9+9/", "99*9+9/", "999*+9/", "999*+9/", "99*9+9/", "99*9+9


この答えの数から、難易度の高い組み合わせを見つけられそうですね。
「最も難しいテンパズル」。
面白そうだけどそこまで興味がないので見送ります。
と思ったけど、ついでなので全回答を作りました。

https://gist.github.com/sekaiya/6569856/



これで切符をニヤニヤみるような彼氏が出来ても、
このgistにアクセスすれば、

あ、9999?。答えは48個あるみたいだね。

ってすぐに会話が終わっちゃう。

っていうかそんな辛気臭い彼氏要らんわ。


やった!
飲んでくる!