Rubik-kocka forgatás

Színek

orange :: Color
orange = rgb 1 0.5 0
colors :: [Color]
colors = [red, blue, orange, green, white, yellow]

Koordináta-rendszer

A tér pontjainak reprezentációja:

type R3 = (Double, Double, Double)   -- (x, y, z)

(A type kulcsszó után típusok “rövidítését” adhatjuk meg. Akinek ennyi nem elég magyarázat az itt tudhat meg többet.)

Példa:
Az origótól az x tengelyen pozitív irányában az origótól 1 egységre az (1,0,0) pont van:

x1 :: R3
x1 = (1,0,0)

A koordináta rendszer, amelyben az ábrák lesznek (a z tengely felénk mutat):

xyz

Feladat: Forgatások az origó körül

Legyen a left függvény egy olyan forgatás, amely az y tengely pontjait fixen hagyja, és a z tengelyt átviszi az x-be. (Ez jobbra forgatásnak tűnik, de left-nek nevezzük, mert később paraméter-transzformációra használjuk, amely miatt így megfordul az irány.)

left :: R3 -> R3

Test>
(0.0, 1.0, 0.0) :: R3
Test>
(1.0, 0.0, 0.0) :: R3
Test>
(0.0, 0.0, -1.0) :: R3
Test>
(0.5, -3.2, -1.2) :: R3

Legyen right a left függvény inverze!
(Definiálhatjuk right-ot a left segítségével is!)

right :: R3 -> R3

Test>
(0.0, 1.0, 0.0) :: R3
Test>
(0.0, 0.0, 1.0) :: R3
Test>
(-1.0, 0.0, 0.0) :: R3
Test>
(-0.5, -3.2, 1.2) :: R3

Legyen az up függvény egy olyan forgatás, amely az x tengely pontjait fixen hagyja, és a y tengelyt átviszi a z-be. (Ez lefelé forgatásnak tűnik, de a későbbiek miatt up-nak nevezzük.)

Definiáljuk a down-t is, amely az up inverz művelete.

up, down :: R3 -> R3

Test>
(1.0, 0.0, 0.0) :: R3
Test>
(0.0, 0.0, 1.0) :: R3
Test>
(0.0, -1.0, 0.0) :: R3
Test>
(1.0, 0.0, 0.0) :: R3
Test>
(0.0, 0.0, -1.0) :: R3
Test>
(0.0, 1.0, 0.0) :: R3

A Rubik-kocka reprezentációja

A Rubik-kocka egy adott állását úgy fogjuk reprezentálni, hogy megmondjuk minden kis lap színét (6*9 darab kis lap van a kockán).

A kis lapok színeit megadhatnánk akár egy listában is, de ekkor pontosan meg kellene határoznunk, hogy a listaindexek melyik kis lapnak felelnek meg.

Ehelyett a következőt tesszük:

Tehát a Rubik-kocka nem más, mint egy függvény:

type Cube = R3 -> Color

A kockát leíró függvénynek elegendő csak a kis lapok középpontjához színeket rendelni, de az sem baj, ha a tér minden pontjához rendel színeket.

Például a standard Rubik-kocka leírható a következő függvénnyel:

standard :: Cube
standard (x,y,z)
   | abs x > abs y && abs x > abs z  = if x < 0 then green  else blue
   | abs y > abs x && abs y > abs z  = if y < 0 then yellow else white
   | otherwise                       = if z < 0 then orange else red

A függvény nem kezel 6*9 esetet külön, hanem 6 térszögre osztja a teret és minden térszöget homogén módon színez. Ezekben a térszögekben természetesen benne vannak a kis lapok középpontjai is. A függvény úgy működik, hogy kiválasztja a kapott pont legnagyobb abszolút értékű koordinátáját, és annak az előjele alapján állapítja meg a színt.

Példa:

Test>
Color "blue" :: Color

A display függvénnyel megjeleníthetünk egy kockát:

display :: Cube -> Diagram

Példa:

Test>

Az ábrán egyetlen Rubik-kocka látható. A kocka hátsó lapjait balra “kihúztuk”, hogy láthatóak legyenek.

Feladat: A kocka forgatása

Definiáljuk a cube nevű függvényt, amely megkap egy Rubik-kockát és egy tértranszformáló függvényt (tipikusan a left, right, up, down függvényeket, és paraméter-transzformációval előállít egy újabb Rubik-kockát!

Segítség:
A megoldás nagyon rövid.
A paraméter-transzformáció jelentése: egy függvényhívás előtt módosítjuk a függvény paraméterét. (Gondoljunk arra, hogy a Rubik-kocka is egy függvény!)

Megjegyzés:
Az ellenőrzést szemmel (és próbálgatással) kell végezni, mert a rendszer egyelőre nem tudja eldönteni az ábrák egyenlőségét.
Az ellenőrzés gombra kattintva megjelenik egy beviteli mező, ahol a saját definíciónkat tesztelhetjük.

infixl 7 `cube`
cube :: Cube -> (R3 -> R3) -> Cube

Test>
Test>
Test>

Megjegyzés azoknak, akik tanulták a függvénykompozíciót:
standard `cube` up `cube` left `cube` left rövidíthető így:
standard `cube` left . left . up

Feladat: A felső sor forgatása

Definiáljunk egy top nevű függvényt, amely a Rubik-kocka felső sorát transzformálja egy megadott függvény szerint (amely tipikusan left vagy right)!

Segítség: Egy Cube típusú függvényt kell visszaadnunk, amely vizsgálja meg a kapott pontot, és ha annak az y koordinátája nagyobb, mint 0,5, akkor végezzen egy változó-transzformációt!

infixl 7 `top`
top :: Cube -> (R3 -> R3) -> Cube

Test>
Test>
Test>

Megjegyzés:
Bár a típusrendszer megengedi, a következő kifejezés hibás Rubik-kocát állít elő (így ne használjuk): standard `top` up

Feladat: Az alsó sor forgatása

Definiáljunk egy bottom nevű függvényt, amely a Rubik-kocka felső sorát transzformálja egy megadott függvény szerint (amely tipikusan left vagy right)!

Próbáljuk meg bottom-ot a cube és a top segítségével definiálni! (Tipp: fordítsuk át a kockát, aztán a felső sort mozgassuk, aztán vissza a kockát. A kapott f irány inverze az f háromszori alkalmazása)

infixl 7 `bottom`
bottom :: Cube -> (R3 -> R3) -> Cube

Test>
Test>

Feladat: A középső sor forgatása

Definiáljunk egy middle nevű függvényt, amely a Rubik-kocka középső sorát transzformálja egy megadott függvény szerint (amely tipikusan left vagy right)!

Próbáljuk meg a middle-t az előző függvényekkel definiálni!

infixl 7 `middle`
middle :: Cube -> (R3 -> R3) -> Cube

Test>
Test>

Szorgalmi feladat

Állítsuk elő a következő konfigurációt!

Test>