パズルの自動生成(画像版)
こういう問題を出力するスクリプトができた。70行。
で書き換えているのはこの5行だけ
def item_renderer(i): def renderer(cont): return cont.trans(0.5, 0.5).pushpop( lambda cont:cont.rot(i * 3.141592 / 3).trans(0.3).circle(r=0.1) ).pushpop( lambda cont:cont.trans((0.25 * i) % 1 - 0.5).rect(width=0.25, height=0.25)) return renderer
0〜8のiについてそれぞれ違った図を描画する関数を返していて、それを四角の中に描画してクリッピングしている。クリッピングが一番大変だった(笑)
あとはここをもっと抽象化していけば問題がたくさん作れるな。いまは円と四角しかないけど、一度作った部品は再利用が出来るし。
パズルの自動生成とかでやったように、ランダムにモデルを選んでパラメータを決めて僕が知らない問題を作り出すところまで早くやりたいのだけど、そこはぐっと我慢してまずは集積サイトを作るべきなのかなぁ。むー。
とりあえずIQTest.dkの問題でも模倣してみるか。
def i2xy(i): return i % 3, i / 3 def item_renderer(i): def renderer(cont): # http://www.iqtest.dk/main.swf Q2 x, y = i2xy(i) for j in range(9): if y <= j <= x + y: fill = "gray" else: fill = "white" (cont.trans(0.5, 0.5).rot(CCW90 + 2 * pi * j / 9).trans(0.3) .circle(r=0.1, stroke_width=0.01, stroke="black", fill=fill)) return cont return renderer
def renderer(cont): # http://www.iqtest.dk/main.swf Q3 x, y = i2xy(i) for j in range(y + 1): (cont.trans(0.2 + x * 0.3 + 0.1 * j - 0.05 * y).path(d="M 0 0 L 0 1", stroke_width=0.02)) return cont return renderer
def draw_grid(cont, n): from string import Template tmpl = Template("M $v 0 L $v 1 M 0 $v L 1 $v") for i in range(1, n): v = 1.0 / n * i cont.path(d=tmpl.substitute(locals()), stroke_width=0.01) def item_renderer(i): def renderer(cont): # http://www.iqtest.dk/main.swf Q5 x, y = i2xy(i) cont.apply(draw_grid, 3) for j in range(x + 1): cont.trans(1.0 / 3 * (y % 3), 1.0 / 3 * j).rect(width=0.33, height=0.33, fill="url(#tube)") return cont return renderer
あと
cont.define_linear_gradient( "tube", [(0, "black", 1), (0.5, "white", 1), (1, "black", 1)])
def item_renderer(i): def renderer(cont): # http://www.iqtest.dk/main.swf Q8 x, y = i2xy(i) white = dict(fill="none", stroke_width=0.01, stroke="black") marks = [ lambda cont: cont.trans(0.5, 0.5).circle(r=0.4, **white), lambda cont: cont.trans(0.1, 0.1).rect(width=0.8, height=0.8, **white), lambda cont: cont.path(d="M 0.5 0.2 L 0.1 0.9 L 0.9 0.9 Z", **white), lambda cont: cont.trans(0.5, 0.5).circle(r=0.4), # black circle lambda cont: cont.trans(0.1, 0.1).rect(width=0.8, height=0.8), # black square lambda cont: cont.path(d="M 0.5 0.2 L 0.1 0.9 L 0.9 0.9 Z"), # black triangle ] if i < 9: j = (x + y) % 3 else: j = (2 + i - 9) % 6 cont.apply(marks[j]) return cont return renderer
誤答を作るのに苦労した。
from random import random buf = [int(random() * 6) for _i in range(9)] def item_renderer(i): def renderer(cont): # http://www.iqtest.dk/main.swf Q39 cont.apply(draw_grid, 3) for y in range(3): for x in range(3): cont.trans(1.0 / 3 * x, 1.0 / 3 * y).scale(1.0 / 3).apply( MARKS[(buf[(i + y * 3 + x) % 9] + i) % 6]) return cont return renderer
さっきのmarksは再利用すると思ったので関数の外に移動した。+iをつけない若干簡単バージョンも作ってみた。
簡単な方
難しい方
オリジナル問題