% "asennettu-predikaatti on osa keskenjäänyttä yritystä tehostaa ratkaisujen hakua. %:- dynamic(asennettu/4). % kiskon palan pituus (siirtymä xy-koordinaatistossa), kääntymissuunta ja -kulma kisko(suora, 220.0, 0.0). kisko(vasen, L, Kulma):- N = 8, % kaarrepalojen lukumäärä täydessä ympyrässä D = 410.0, %kaarrepaloista rakennetun ympyrän halkaisija Kulma is 2.0*pi/N, L is D*sin(Kulma/2.0). kisko(oikea, L, Kulma):- N = 8, % kaarrepalojen lukumäärä täydessä ympyrässä D = 410.0, %kaarrepaloista rakennetun ympyrän halkaisija Kulma is -2.0*pi/N, L is D*sin(-Kulma/2.0). % rata-alueen rajat millimetreinä xy-koordinaatistossa. % Tämän verran on lattialla tilaa. Rakentaminen aloitetaan pisteestä (0, 0) alue(X, Y):- X > -1000.0, X < 1000.0, Y > -600.0, Y < 600.0. % Radan piirtämisen avuksi pikkukaarre(Kulma, L):- N = 40, D = 410.0, Kulma is 2.0*pi/N, L is D*sin(Kulma/2.0). % Muut osat: Risteykset, sillat yms. pitäisi ottaa mukaan, % jos haluaisi tehdä jotain käytännön kannalta mielenkiintoista. % Nsuorat: Käytettävissä olevien suorien kiskojen lukumäärä % Nkaarteet: Käytettävissä olevien kaarteiden lukumäärä radat(Nsuorat, Nkaarteet):- % retractall(asennettu/4), % haetaan kaikki erilaiset radat setof(Rata, rata(Nsuorat, Nkaarteet, Rata), Radat), % seulotaan pois ne, jotka saa pyöräyttämällä jotain toista rataa erilaiset(Radat, Eril), nl, length(Radat, M), length(Eril, N), write(['kaikki vs. erilaiset ', M, N]), nl, kuvat(N), piirraRadat(Eril, 1, Nsuorat, Nkaarteet). % Ns0: käytettävissä olevien suorien kiskojen lukumäärä % Nk0: käytettävissä olevien kaarrekiskojen lukumäärä % Kiskot: Järjestetty luettelo käytetyistä kiskoista. Esim [suora, vasen, vasen, oikea, ...] rata(Ns0, Nk0, [suora|Kiskot]):- Ns0 > 0, !, Ns is Ns0 - 1, kisko(suora, L, Kulma), kiskot(Kulma, L, 0.0, Ns, Nk0, Kiskot). rata(0, Nk0, [vasen|Kiskot]):- Nk is Nk0 - 1, kisko(vasen, L, Kulma), X is L*cos(Kulma), Y is L*sin(Kulma), kiskot(Kulma, X, Y, 0, Nk, Kiskot). % kiskot(0.0, 0.0, 0.0, Ns, Nk, Rata). kiskot(Kulma, X, Y, Ns, Nk, []):- % Ollaanko origossa? round(X) =:= 0.0, round(Y) =:= 0.0, Nk < 4, Ns < 2, % Onko tehty nolla (=kahdeksikko) tai useampi tasakierros vastapäivään? kierrokset(Kulma), % write([Nk, Ns, Kulma, X, Y]), nl, % Laitetaan näytölle piste aina kun löydetään uusi ratkaisu put_char('.'), flush_output. kiskot(Kulma0, X0, Y0, Ns0, Nk0, [Suunta|Kiskot]):- Nk0 >= 0, Ns0 >= 0, riittaakokaaret(Kulma0, Nk0), riittaakokiskot(Nk0, Ns0, X0, Y0), kisko(Suunta, L, DKulma), kiskolkm(Suunta, Nk0, Ns0, Nk, Ns), Kulma is Kulma0+DKulma, X is X0+L*cos(Kulma), Y is Y0+L*sin(Kulma), alue(X, Y), % overlap(X0, X, Y0, Y), (epäonnistunut/keskeneräinen yritys tehostaa hakua) kiskot(Kulma, X, Y, Ns, Nk, Kiskot). kiskolkm(suora, Nk0, Ns0, Nk0, Ns):- Ns is Ns0 - 1. kiskolkm(oikea, Nk0, Ns0, Nk, Ns0):- Nk is Nk0 - 1. kiskolkm(vasen, Nk0, Ns0, Nk, Ns0):- Nk is Nk0 - 1. % Tavoite on 0 tai useampi kierros vastapäivään joten % on turha mennä niin pitkälle myötäpäivään, että kaaret loppuvat % kesken takaisinkääntymisen. (Vai rajaanko liikaa?) riittaakokaaret(Kulma0, Nk0):- Kulma0 + Nk0*pi/4.0 > -0.0001. % >=0 riittävä ehto % Ollaanko niin kaukana, ettei ole mitään mahdollisuutta päästä alkupisteeseen. riittaakokiskot(Nk, Ns, X, Y):- kisko(suora, Ls, _), kisko(vasen, Lk, _), L is sqrt(X**2+Y**2), Lmax is Ns*Ls + Nk*Lk, L < 1.001*Lmax. Keskeneräinen yritys rajata hakua. Ajatuksena oli välttää uuden kiskon asentaminen aiemmin asennetun päälle. Jokko ajatus tai toteutus on väärä. overlap(X0, X, Y0, Y):- Xr is round(X), Yr is round(Y), X0r is round(X0), Y0r is round(Y0), asennettu(X0r, Xr, Y0r, Yr), !, fail. overlap(X0, X, Y0, Y):- Xr is round(X), Yr is round(Y), X0r is round(X0), Y0r is round(Y0), asserta(asennettu(X0r, Xr, Y0r, Yr)). overlap(X0, X, Y0, Y):- Xr is round(X), Yr is round(Y), X0r is round(X0), Y0r is round(Y0), retract(asennettu(X0r, Xr, Y0r, Yr)). kierrokset(Kulma):- Kulma > -0.001, % Ei ole käännytty kierrostakaan negatiiviseen kiertosuuntaan % kommentoi seuraava, jos haluat muutakin kuin kahdeksikkoja Kulma < 0.001, % Ei ole käännytty kierrostakaan positiiviseen kiertosuuntaan % Täyskierrokset: kulman ja 2*pi:n jakojäännös on lähellä nollaa % Allaoleva ei ole välttämätön, jos ylläoleva ehto Kulma < 0.001 käytössä. Jaannos is round(10.0*Kulma) rem round(20.0*pi), Jaannos =:= 0. % Rekursion lopetusehto: kaikki radat tarkastettu % erilaisten ratkaisujen joukon alkuarvo on [] erilaiset([], []). erilaiset([A1|An], Eril):- length(A1, N), % N on radan pituus % rotatoidaan enintään N-1 kertaa rotate(A1, Ar, N), % Onko rotatoitu sama, kuin joku jäljelläolevista radoista? % ellei ole, member epäonnistuu ja ohjelma % peruuttaa hakemaan rotatelta toista vaihtoehtoa member(Ar, An), !, % Jos löytyy samanlainen, tarkastellaan jäljellä olevia ratoja erilaiset(An, Eril). % Ellei löytynyt samanlaista, ylläoleva failaa ja % tullaan tähän vaihtoehtoon. % Lisätään rata A1 ratkaisujen joukkoon ja siirrytään tarkastelemaan % jäljelläolevia erilaiset([A1|An], [A1|Eril]):- erilaiset(An, Eril), !. rotate(A, B, _):- rotatelist(A, B). rotate(A, B, N):- N > 2, M is N-1, rotatelist(A, Ar), rotate(Ar, B, M). rotatelist([H|T], R):- append(T, [H], R). demo:- erilaiset([[a, a, b, b], [a, b, a, b], [a, b, b, a], [b, a, b, a]], B), write(B), nl. piirraRadat([], _, _, _). piirraRadat([Rata1|Loput], M, Ns, Nk):- piirraRata(Rata1, M, Ns, Nk), !, N is M+1, piirraRadat(Loput, N, Ns, Nk). piirraRata(Rata, N, Ns, Nk):- open('tmp.dat', write, Fil), radanpisteet(Fil, 0, 0, 0, Rata, 5, Minx, Maxx, Miny, Maxy), close(Fil), % kasataan linux-komento cmdline(Cmd, Minx, Maxx, Miny, Maxy, N, Ns, Nk), % ja suoritetaan se. Jostain syystä popen toimii, mutta spawn ei. popen(Cmd, write, Kuva), close(Kuva). % Viimeinenkin kisko käsitelty; rekursion loppu. % Alkuarvo 0 x:n ja y:n ääriarvoille radanpisteet(Fil, X, Y, Kulma, [], _, 0, 0, 0, 0):- % pieni poikkiviiva kiskon loppuun tick(Fil, X, Y, Kulma). radanpisteet(Fil, X0, Y0, Kulma0, [suora|Loput], _, Minx, Maxx, Miny, Maxy):- !, % pieni poikkiviiva kiskon alkuun tick(Fil, X0, Y0, Kulma0), kisko(suora, L, _), X is X0 + L*cos(Kulma0), Y is Y0 + L*sin(Kulma0), tick(Fil, X, Y, Kulma0), radanpisteet(Fil, X, Y, Kulma0, Loput, 5, Minx0, Maxx0, Miny0, Maxy0), % toiminee myös: Minx = min(Minx0, X). min_list([Minx0, X], Minx), max_list([Maxx0, X], Maxx), min_list([Miny0, Y], Miny), max_list([Maxy0, Y], Maxy). % Pikkukäännöksistä viimeinen radanpisteet(Fil, X0, Y0, Kulma0, [vasen|Loput], 0, Minx, Maxx, Miny, Maxy):- !, tick(Fil, X0, Y0, Kulma0), radanpisteet(Fil, X0, Y0, Kulma0, Loput, 5, Minx, Maxx, Miny, Maxy). % Pikkukäännös vasemmalle radanpisteet(Fil, X0, Y0, Kulma0, [vasen|Loput], NPienetKaannokset, Minx, Maxx, Miny, Maxy):- write(Fil, X0), write(Fil, ' '), write(Fil, Y0), nl(Fil), pikkukaarre(DKulma, L), Kulma is Kulma0+DKulma, X is X0+L*cos(Kulma), Y is Y0+L*sin(Kulma), M is NPienetKaannokset-1, radanpisteet(Fil, X, Y, Kulma, [vasen|Loput], M, Minx0, Maxx0, Miny0, Maxy0), min_list([Minx0, X], Minx), max_list([Maxx0, X], Maxx), min_list([Miny0, Y], Miny), max_list([Maxy0, Y], Maxy). % Käännöksetn oikealle kuten vasemmallekin radanpisteet(Fil, X0, Y0, Kulma0, [oikea|Loput], 0, Minx, Maxx, Miny, Maxy):- !, tick(Fil, X0, Y0, Kulma0), radanpisteet(Fil, X0, Y0, Kulma0, Loput, 5, Minx, Maxx, Miny, Maxy). radanpisteet(Fil, X0, Y0, Kulma0, [oikea|Loput], NPienetKaannokset, Minx, Maxx, Miny, Maxy):- !, write(Fil, X0), write(Fil, ' '), write(Fil, Y0), nl(Fil), pikkukaarre(DKulma, L), Kulma is Kulma0-DKulma, X is X0+L*cos(Kulma), Y is Y0+L*sin(Kulma), M is NPienetKaannokset-1, radanpisteet(Fil, X, Y, Kulma, [oikea|Loput], M, Minx0, Maxx0, Miny0, Maxy0), min_list([Minx0, X], Minx), max_list([Maxx0, X], Maxx), min_list([Miny0, Y], Miny), max_list([Maxy0, Y], Maxy). tick(Fil, X, Y, Kulma):- L is 25, write(Fil, X), write(Fil, ' '), write(Fil, Y), nl(Fil), X1 is X + L*sin(Kulma), Y1 is Y - L*cos(Kulma), write(Fil, X1), write(Fil, ' '), write(Fil, Y1), nl(Fil), X2 is X - L*sin(Kulma), Y2 is Y + L*cos(Kulma), write(Fil, X2), write(Fil, ' '), write(Fil, Y2), nl(Fil), write(Fil, X), write(Fil, ' '), write(Fil, Y), nl(Fil). % Muodostetaan linux-komento radan piirtämistä varten cmdline(Cmd, Minx0, Maxx0, Miny0, Maxy0, RadanNumero, Ns, Nk):- Dx is abs(Minx0-Maxx0), Dy is abs(Miny0-Maxy0), Minx is 1.05*Minx0, Miny is 1.05*Miny0, % x- ja y-asteikon pitää olla samoja ettei kuva vääristy D = max(Dx, Dy), Maxx is D + Minx + 0.05*D, Maxy is D + Miny + 0.05*D, format_to_atom(Cmd, 'graph -h 0.8 -w 0.8 -u 0.1 -r 0.1 -T png -W 0.02 -L "max. ~d suoraa ja ~d kaarretta" --bg-color=yellowgreen -x ~f ~f -y ~f ~f tmp.dat > plotsTmp/plot~d.png', [Ns, Nk, Minx, Maxx, Miny, Maxy, RadanNumero]). % Apukomento rc:- consult(['junarata.prolog', 'kuvat.prolog']). rc1:- consult(['junarata.prolog']). rc2:- consult(['kuvat.prolog']).