Ajattelin ottaa tavaksi keksiä jonkin lyhyen ohjelmointiharjoituksen noin kerran kuussa. Tarkoituksena olisi pysyä tasolla, jonka kokenut harrastaja voi tehdä yhdessä illassa tai nopeammin. Hupi olisi siinä, että saisi esitellä suosikkikieltään, eliittisiä koodaustaitojaan, tai miksei vaikkapa kykyä tehdä selkeä ja ymmärrettävä ohjelma. Kieli, tyyli ym. ovat vapaat.
Tämän kerran tehtävä on tehdä lyhyt ohjelma, joka tulostaa merkkigrafiikalla Mandelbrotin joukon kuvan. Detaljit saa itse päättää, kuten käytetyt merkit ja koko tulostuksen koon. Niihin voi olla hyvä antaa vaikuttaakin. Ihan miten kukin itse haluaa.
Aloitan esimerkillä, joka on nyt GoldenDragonin iloksi tehty juhlavasti Common Lisp -kielellä.
(defvar *height* 40) (defvar *width* 60) (defun iterate (z c &optional (iterations 50)) (loop for iter from 1 to iterations when (>= (abs z) 2) return iter do (setf z (+ c (* z z))) finally (return 0))) (defun make-scaling-fn (maxx maxy) (lambda (x y) (let ((x-fraction (coerce (/ x maxx) 'float)) (y-fraction (coerce (/ y maxy) 'float))) (values (- (* 3 x-fraction) 2) (- (* 2 y-fraction) 1))))) (defun mandelbrot-char (val) (if (zerop val) #\# (schar ".-=*%" (floor (1- val) 10)))) (defvar scale (make-scaling-fn *width* *height*)) (dotimes (y *height*) (dotimes (x *width*) (multiple-value-bind (sx sy) (funcall scale x y) (princ (mandelbrot-char (iterate 0 (complex sx sy)))))) (princ #\newline))
Ohjelman tulostus on seuraavan näköinen.
.....................................-.-#................... .....................................-=-.................... .....................................*=-.................... ..................................-%-=#--................... ...................................-####-................... ...................................=####*................... ..................................--####--.....-............ ............................-%--#=######=*-%...-............ ............................-%#-=##########=-----........... ............................-##################=............ ...........................--##################=............ ..........................=#=#################*-............ ...............-..........-=###################-.-.......... ...............-...--....-#######################-.......... ...............--=--*--..-=#####################-........... ................-#=###=---######################-........... ...............--#######--######################*........... ............-.--#########=######################=........... ............---=#########*######################............ ...........--##%###############################-............ .#############################################-............. ...........--##%###############################-............ ............---=#########*######################............ ............-.--#########=######################=........... ...............--#######--######################*........... ................-#=###=---######################-........... ...............--=--*--..-=#####################-........... ...............-...--....-#######################-.......... ...............-..........-=###################-.-.......... ..........................=#=#################*-............ ...........................--##################=............ ............................-##################=............ ............................-%#-=##########=-----........... ............................-%--#=######=*-%...-............ ..................................--####--.....-............ ...................................=####*................... ...................................-####-................... ..................................-%-=#--................... .....................................*=-.................... .....................................-=-....................
Älkää kuitenkaan kaikki lähettäkö näitä kuvia erikseen. Pelkkä ohjelma riittää ja jos harrastusta riittää parempiin kuviin asti, ne voi laittaa muualle, sekä linkittää. Tämä tekee säikeen lukemisesta mukavampaa. Voit myös mainita, mistä käyttämäsi kielen toteutuksen saa, jos se ei ole yleisesti käytetty kieli.
Jos olet kokematon ohjelmoija ja haluat erikseen palautetta koodista, kerro siitä viestisi yhteydessä. Emme me sorra aloittelijoita täällä Putkassa, emmehän.
Koodini pitäisi toimia kaikilla yhteensopivilla ANSI CL-ympäristöillä, mutta käytin itse Windowsin clispiä, enkä osaa niitä standardeja, kun on tuo CL-harrastus ollut sangen vähäistä. Olin hieman laiska, enkä vielä selvittänyt, miten Common Lisp -toteutuksessani saa komentoriviargumentit käyttöön, joten koodasin tulsotuksen koon defvareilla suoraan. Pysyipä ohjelma lyhyenä ainakin.
Ja palautetta saa antaa minunkin koodistani. En käyttänyt rekursiota, koska en kirjoittanut Schemeä :-)
Olkaa hyvä, jatkakaa tästä, jos innostusta löytyy. Wikipediassa ja muualla on juttua tuosta laskennasta, jos yo. koodin logiikka ei aukea.
(Jos aihe saa tarpeeksi suosiota, keksin ensi kuussa jotain hieman vaativampaa vaihtelun vuoksi.)
Koodin pituus pääsi hiukan kasvamaan, kun tuli tehtyä tuohon noita perinteisiä zoomaustoimintoja, mutta onneksi siinä on sitäkin vähemmän kommentteja.
http://www.niksula.hut.fi/~jasainio/
Binäärikin niille, jotka haluavat kokeilla.
http://www.niksula.hut.fi/~jasainio/
Ooks mä vähän elite ku mä osaan käyttää pdcurses-kirjastoa. Joo, piti opetella ihan tätä varten.
Hee, tyylikäs vekotin. Kiitoksia.
Huomasin nyt jälkikäteen, että kuvasuhde näillä Putkan asetuksilla on aivan erilainen kuin dossi-lootassa ja tuo minun mantelileipäni näyttää pahasti läsähtäneeltä. Pahoitteluni niille, joiden esteettinen silmä mustuu. En viitsi uutta pistää paremmalla kuvasuhteella, koska se vain veisi liikaa tilaa.
Toiveikkaana odotan muidenkin kontribuutioita tähän perinteiseen ohjelmointiharjoitukseen :-)
Oli näköjään vähän laiskasti ohjelmoitu tuo mun ohjelma eikä se ottanut huomioon eri kokoisia konsoleita. Etenkin kun se oli optimoitu minun käyttämälleni hyvin epästandardille 90x30 eikä 80x25 konsolille. No nyt se näyttää toimivan ja on aika hieno 200x100 konsolilla. Ehkä mä en ollutkaan niin elite tuon curses-kirjaston kanssa.
http://www.niksula.hut.fi/~jasainio/
Kommentoidaan nyt tuota sinunkin koodia. Eihän ohjelmointikieli voi olla hyvä, jos funktiomäärittelytkin ovat kirjaimellisesti 'ei kiva'. Niin ja tuosta iterate metodista näyttää puuttuvan sulkuja, kyllä scheme vaan on loogisempi :) Mutta tosiaan aika lyhyesti tuolla saa tuon ohjelmoitua, vaikka alkaa jo vaatimaa aika paljon keskittymistä, että pystyy seuraamaan mitä missäkin tapahtuu.
delouse - poistaa täit (verbi)
defun - poistaa hupi (verbi)
Noinhan se menee. Mutta hupi tulee takaisin tuossa kohdassa, missä on funcall, eli hupikutsu. Tasapaino on säilytettävä.
Nyt kun korjaillaan puutteita, niin korjaillaan sitten perusteellisesti. Ei taida montaa lukijaa kiinnostaa, mutta sanonpa kuitenkin. Oli puute.
Schemen harrastajana en muistanut, että funktiot pitää määritellä funktioiksi. Pitäisi siis olla
(defun make-scaling-fn (maxx maxy) #'(lambda (x y) (let ((x-fraction (coerce (/ x maxx) 'float)) (y-fraction (coerce (/ y maxy) 'float))) (values (- (* 3 x-fraction) 2) (- (* 2 y-fraction) 1)))))
Tuo #' tekee siitä funktion. Se on lyhenne (function ...)-rakenteelle itse asiassa. Mutta koska sitä palautettua sisäfunktiota käytettiin vain funcall-kutsussa, tämä virhe ei mahdollisesti haitannut (tai sitten clisp oli armollinen). Mutta olisihan se näin parempaa tyyliä ja varmasti standardin mukaista.
Tämä on taas yksi niitä asioita, mikä saa schemettäjät kauhistumaan. Miten te lispistit *voitte* pitää muuttujat ja funktiot eri nimiavaruuksissa? Niin, en minä tiedä, en ole oikea lispisti. Jotenkin ne kestävät tuon tuskan, että pääsevät defmacrolla ja CLOS:illa leikkimään :-)
Aihe ei saanut suurta suosiota, joten en kiusaa vastaavilla teitä enää. Tarjoan kuitenkin Pythonin FAQ -tiedostosta lainatun koodinpätkän aiheen tiimoilta. Se on vaan niin kaunis, vaikka ei yhtä ultimaattisen über toiminnaltaan kuin FooBatin oivallinen ohjelma.
print (lambda Ru,Ro,Iu,Io,IM,Sx,Sy:reduce(lambda x,y:x+y,map(lambda y, Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,Sy=Sy,L=lambda yc,Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,i=IM, Sx=Sx,Sy=Sy:reduce(lambda x,y:x+y,map(lambda x,xc=Ru,yc=yc,Ru=Ru,Ro=Ro, i=i,Sx=Sx,F=lambda xc,yc,x,y,k,f=lambda xc,yc,x,y,k,f:(k<=0)or (x*x+y*y >=4.0) or 1+f(xc,yc,x*x-y*y+xc,2.0*x*y+yc,k-1,f):f(xc,yc,x,y,k,f):chr( 64+F(Ru+x*(Ro-Ru)/Sx,yc,0,0,i)),range(Sx))):L(Iu+y*(Io-Iu)/Sy),range(Sy ))))(-2.1, 0.7, -1.2, 1.2, 30, 80, 24)
(Kohta siellä FAQ-tiedostossa oli kysymys siitä, voiko Pythonilla tehdä obfuskoitua koodia :-)
Aihe on jo aika vanha, joten et voi enää vastata siihen.