ルービックキューブ
今日中にできなかったら昼飯をおごるという約束でとりあえず作った。
全体をまわす処理ができていないのでカーソルはどこまでもいける。どこまでもな。
操作はカーソルキーでカーソル(白い四角)を動かして、シフト押しながらカーソルで回転。
まあ、アルゴリズムができただけで、終了判定もないわけだが、終了判定は難しすぎるのでパス。
お急ぎで作ったのでソースもぐちゃぐちゃでちょっと長いが、まあ、きちんと整理してサンプルにつけるように考えておこう。
なので証拠としてソースはあげておくが、これはあまり参考にしないように。
require 'dxruby' def createSquare(v, t) v = v.flatten t = t.flatten pa = Polygon.new pa.vertex = [v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8]] pa.tutv = [t[0], t[1], t[2], t[3], t[4], t[5]] pb = Polygon.new pb.vertex = [v[0], v[1], v[2] ,v[6], v[7], v[8], v[9], v[10], v[11]] pb.tutv = [t[0], t[1], t[4], t[5], t[6], t[7]] [pa, pb] end def createWall(pos, size, tutv) point = [[-1, -1, -1], [1, -1, -1], [1, -1, 1], [-1, -1, 1], [-1, 1, -1], [1, 1, -1], [1, 1, 1], [-1, 1, 1]] point.map! do |p1| [p1[0] * size / 2 + pos[0], p1[1] * size / 2 + pos[1], p1[2] * size / 2 + pos[2]] end pt = createSquare([point[0], point[1], point[2], point[3]], tutv[0]) pt.concat createSquare([point[3], point[2], point[6], point[7]], tutv[1]) pt.concat createSquare([point[0], point[3], point[7], point[4]], tutv[2]) pt.concat createSquare([point[1], point[0], point[4], point[5]], tutv[3]) pt.concat createSquare([point[2], point[1], point[5], point[6]], tutv[4]) pt.concat createSquare([point[7], point[6], point[5], point[4]], tutv[5]) pt end tutv = [] for i in 1..6 do tutv.push([i * 32, 0, i * 32 + 31, 0, i * 32 + 31, 31, i * 32, 31]) end image = Image.new( 32 * 8, 32 ) [[0, 0, 0], [0, 0, 200], [0, 200, 0], [0, 200, 200], [200, 0, 0], [200, 0, 200], [200, 200, 0], [200, 200, 200]].each_with_index do |c, i| image.boxFill(i * 32, 0, i * 32 + 31, 31, c).box(i * 32, 0, i * 32 + 31, 31, [0,0,0]) end mesh = Mesh.new(createWall([0,0,0], 100, tutv), image) class Parts attr_accessor :func, :angle, :matrix def initialize(x, y, z, mesh) @x = x @y = y @z = z @matrix = Matrix.createRotationX(0) @angle = 0 @mesh = mesh @func = Matrix.method(:createRotationX) end def draw Window.drawMesh(Matrix.createTranslation(@x, @y, @z) * @matrix * @func.call(@angle) * Matrix.createTranslation(250, 250, -1500), @mesh) end end cube = [[[],[],[]],[[],[],[]],[[],[],[]]] # キューブの3次元配列 for y in -1..1 for z in -1..1 for x in -1..1 cube[y+1][z+1].push(Parts.new(x * 100, y * 100, z * 100, mesh)) end end end def get_x_men(cube, index) # 縦に切った2次元配列を作る r = [[],[],[]] for i in 0..2 for j in 0..2 r[i].push(cube[i][j][index]) end end r end def set_x_men(cube, index, r) # 戻す for i in 0..2 for j in 0..2 cube[i][j][index] = r[i][j] end end end def rotation(c, v, func, cube) c.each do |line| line.each do |parts| parts.func = func parts.angle = 0 end end 0.step(90, 5) do |i| break if Input.update c.each do |line| line.each do |parts| parts.angle = i * v end end cube.flatten.each do |parts| parts.draw end Window.sync Window.update end c.each do |line| line.each do |parts| parts.angle = 0 parts.matrix *= func.call(90 * v) end end for i in 0..(v == 1 ? 0 : 2) c = c.transpose.reverse end return c end Window.view_matrix = Matrix.createView(Matrix.createTranslation(400,-500,0) * Matrix.createRotationY(20) * Matrix.createRotationX(20)) cursor_image = Image.new(30,30,[255,255,255]) x = y = 0 Window.create loop do break if Input.update dx = (Input.keyPush?(K_LEFT) ? -1:0) + (Input.keyPush?(K_RIGHT) ? 1:0) dy = (Input.keyPush?(K_UP) ? -1:0) + (Input.keyPush?(K_DOWN) ? 1:0) if Input.keyDown?(K_LSHIFT) or Input.keyDown?(K_RSHIFT) # シフト押しながらだと回転 if Input.keyPush?(K_LEFT) or Input.keyPush?(K_RIGHT) # 左右 cube[y] = rotation(cube[y], dx, Matrix.method(:createRotationY), cube) elsif Input.keyPush?(K_UP) or Input.keyPush?(K_DOWN) # 上下 set_x_men(cube, x, rotation(get_x_men(cube, x), -dy, Matrix.method(:createRotationX), cube)) end else x += dx y += dy end cube.flatten.each do |parts| parts.draw end Window.draw(x * 80 + 195, y * 80 + 185, cursor_image) Window.sync Window.update end