10

Click here to load reader

Ruby2.0でlazyな n-Queen

Embed Size (px)

Citation preview

Page 1: Ruby2.0でlazyな n-Queen

Ruby2.0 で

lazy な N-Queen

e-Zuka Tech Night山崎重一郎

Page 2: Ruby2.0でlazyな n-Queen

N-Queen

解  [2,4,1,3]

1 2 3 4

[1~N] の順列の生成、テスト

Page 3: Ruby2.0でlazyな n-Queen

Ruby で順列の生成

> [1,2,3,4].permutation=> #<Enumerator: [1, 2, 3, 4]:permutation>

> [1,2,3,4].permutation.to_a=> [[1, 2, 3, 4], [1, 2, 4, 3], [1, 3, 2, 4], [1, 3, 4, 2], [1, 4, 2, 3], [1, 4, 3, 2], [2, 1, 3, 4], [2, 1, 4, 3], [2, 3, 1, 4], [2, 3, 4, 1], [2, 4, 1, 3], [2, 4, 3, 1], [3, 1, 2, 4], [3, 1, 4, 2], [3, 2, 1, 4], [3, 2, 4, 1], [3, 4, 1, 2], [3, 4, 2, 1], [4, 1, 2, 3], [4, 1, 3, 2], [4, 2, 1, 3], [4, 2, 3, 1], [4, 3, 1, 2], [4, 3, 2, 1]]

Page 4: Ruby2.0でlazyな n-Queen

順列の生成方法

> [1,2,3,4].permutation=> #<Enumerator: [1, 2, 3, 4]:permutation>

> [*1..10].permutation.to_aなかなか返ってこない〜

Page 5: Ruby2.0でlazyな n-Queen

順列生成を Fiber にするf=->n{Fiber.new{[*1..n].permutation.each{|x|Fiber.yield x}}}

g=f[10]=> #<Fiber:0x00000126282090>

g.resume=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]g.resume=> [1, 2, 3, 4, 5, 6, 7, 8, 10, 9]

g=f[100]g.resume

Page 6: Ruby2.0でlazyな n-Queen

Ruby 2.0 の lazy順列を lazy に生成

Ruby 1.9の場合は gemで enumerable-lazyを入れてrequire 'enumerable/lazy'

[*1..4].permutation.lazy[*1..4].permutation.lazy.to_a=> [[1, 2, 3, 4], [1, 2, 4, 3], [1, 3, 2, 4], [1, 3, 4, 2], [1, 4, 2, 3], [1, 4, 3, 2], [2, 1, 3, 4], [2, 1, 4, 3], [2, 3, 1, 4], [2, 3, 4, 1], [2, 4,

1, 3], [2, 4, 3, 1], [3, 1, 2, 4], [3, 1, 4, 2], [3, 2, 1, 4], [3, 2, 4, 1], [3, 4, 1, 2], [3, 4, 2, 1], [4, 1, 2, 3], [4, 1, 3, 2], [4, 2, 1, 3], [4,

2, 3, 1], [4, 3, 1, 2], [4, 3, 2, 1]]

[*1..4].permutation.lazy.take(3).to_a=> [[1, 2, 3, 4], [1, 2, 4, 3], [1, 3, 2, 4]]

Page 7: Ruby2.0でlazyな n-Queen

Ruby 2.0順列生成を lazy にやる

f=->n{[*1..n].permutation.lazy}g=f[20]g.take(3).to_a=> [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 19], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 18, 20]]

g.take(4).to_a=> [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 19], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 18, 20], [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 20, 18]]

Page 8: Ruby2.0でlazyな n-Queen

Fiber 版 N-Queen#斜めチェックd=->b{->a{a.map.with_index{|x,i|x==b-i-1 or x==b+i+1}}}diag=->a{a==[]? true : (not(d[a[0]][a[1..-1]].any?) and diag[a[1..-1]])}#ファイバー生成関数f=->n{Fiber.new{[*1..n].permutation.each{|x|Fiber.yield x}}}g=f[10]queen=->{p;begin p=g.resume end until diag[p];p}

queen[]=> [1, 3, 6, 8, 10, 5, 9, 2, 4, 7] queen[]=> [1, 3, 6, 9, 7, 10, 4, 2, 5, 8]> queen[]=> [1, 3, 6, 9, 7, 10, 4, 2, 8, 5]

Page 9: Ruby2.0でlazyな n-Queen

lazy 版 N-Queend=->b{->a{a.map.with_index{|x,i|x==b-i-1 or x==b+i+1}}}diag=->a{a==[]? true : (not(d[a[0]][a[1..-1]].any?) and diag[a[1..-1]])}f=->n{[*1..n].permutation.lazy}queen=->n{->m{f[n].select{|p|diag[p]}.take(m).to_a}}# takeは、取り出す解の個数

queen[10][1]=> [[1, 3, 6, 8, 10, 5, 9, 2, 4, 7]]queen[10][2]=> [[1, 3, 6, 8, 10, 5, 9, 2, 4, 7], [1, 3, 6, 9, 7, 10, 4, 2, 5, 8]]queen[10][3]=> [[1, 3, 6, 8, 10, 5, 9, 2, 4, 7], [1, 3, 6, 9, 7, 10, 4, 2, 5, 8], [1, 3, 6, 9, 7, 10, 4, 2, 8, 5]]

Page 10: Ruby2.0でlazyな n-Queen

lazy 版 N-Queend=->b{->a{a.map.with_index{|x,i|x==b-i-1 or x==b+i+1}}}diag=->a{a==[]? true : (not(d[a[0]][a[1..-1]].any?) and diag[a[1..-1]])}f=->n{[*1..n].permutation.lazy}queen=->n{->m{f[n].take(m).select{|p|diag[p]}.to_a}}#takeの位置を変更して、候補の順列の生成回数にしてみる

queen[10][50000]=> []queen[10][60000]=> [[1, 3, 6, 8, 10, 5, 9, 2, 4, 7], [1, 3, 6, 9, 7, 10, 4, 2, 5, 8], [1, 3, 6, 9, 7, 10, 4, 2, 8, 5]]