Sunday, October 19, 2008

The game, clojure version.

I've been playing around with Clojure a bit, so here is a Clojure version of the little puzzle I wrote in my first blog entry If you don't have clojure set up, go to and get going.

First, we'll make our own little namespace. We will have to call out to java to set up the gui, so we import some swing classes into our namespace as well:

user> (ns com.jalat.flipper)
com.jalat.flipper> (import '(java.awt Color GridLayout Dimension)
                         '(java.awt.event ActionEvent ActionListener)
                         '(javax.swing ImageIcon JFrame JPanel JButton JLabel JTextField JOptionPane BorderFactory))

If you read my first post, you know that the object of the game is to get a layout where all buttons are highlighted, except the center button. I'm going to use true/false values for this, and I'm going to put the values into a vector. The [] is Clojure syntax for a vector.:

com.jalat.flipper> (def solution [true true true
                                true false true
                                true true true])

I'm going to put the moves we can do into a hash, {} is the syntax for a hash. I'm using numbers for the key, and each vaule is a vector where true is a field that will be flipped by the move, and false is a field that will be unchanged by the move.

com.jalat.flipper> (def moves {1 [true  true  false
                                true  true  false
                                false false false]
                             2 [true  true  true
                                false false false
                                false false false]
                             3 [false true  true
                                false true  true
                                false false false]
                             4 [true  false false
                                true  false false
                                true  false false]
                             5 [true  false true
                                false true  false
                                true  false true]
                             6 [false false true
                                false false true
                                false false true]
                             7 [false false false
                                true  true  false
                                true  true  false]
                             8 [false false false
                                false false false
                                true  true  true]
                             9 [false false false
                                false true  true
                                false true  true]})

In Clojure hashes can be called as if they were a function by giving the key as an argument. so to look up the move with the key "1", just call it:

com.jalat.flipper> (moves 1)
[true true false true true false false false false]

So we got a solution and moves, all we need is a starting position. We have the function rand which gives a float between 0 and 1 if we don't give any arguments. Clojure has a shortcut for lambda which is #(). I'm not using any arguments in this case but they would be specified with % and an optional number if there are more than one argument. #(+ 5 %) would be an anonymous function adding five to the argument it receives. repeatedly is a function that just runs it's argument forever and returns it as a lazy sequence. The lazyness is important as this would otherwise be known as a endless loop. take to the rescue. Take returns the first n elements of a sequence, this prevents repeadedly to run forever. Finally, into takes the sequence and stuffs it into a vector.

com.jalat.flipper> (defn scramble []
                    "Generate a new starting position"
                    (into [] (take 9 (repeatedly #(< 0.5 (rand))))))
com.jalat.flipper> (scramble)
[true true false false true true false true false]

Clojures data structures are immutable, but I'll need a way of keeping track of what the current position is, and how many moves we've done so far. For that I'll use references. A reference is a pointer to a data structure. While the data itself can not be modified, the reference can be modified inside a transaction. There is a shortcut to deref, just put @ in front of the reference. A transaction is set up with dosync, any code within the dosync will happen within the transaction:

com.jalat.flipper> (def state (ref (scramble)))
com.jalat.flipper> state 
com.jalat.flipper> @state
[false true true false true false true true true]
com.jalat.flipper> (def num-moves (ref 0))
com.jalat.flipper> (defn new-puzzle []
                    "Set up a starting position, and zero out the moves"
                      (ref-set num-moves 0)
                      (ref-set state (scramble))))

Next, two functions to perform a move, flip takes two vectors (Sequences, actually. I could have used lists) and does a xor on the two vectors. apply-move starts a transaction, and in that transaction updates the number of moves we've done, finds the correct move and calls flip on that move and the current state. The alter function used takes the data that the ref givens as it's first argument, and gives that as the first argument to the third argument together with the rest of the arguments. Finally the ref will be pointed to the result of the function. So (alter num-moves inc) will find the current number of moves, increase it by one, and point the num-moves reference to the increased number.

com.jalat.flipper> (defn flip [pieces state]
                    "Takes two true/false sequences, one specifies which bits
of the other to flip true/false. (Or the other way around,
it's a symmetric operation.)"
                    (map (fn [x y] (and (not (and x y))
                                        (or x y)))
                         pieces state))
com.jalat.flipper> (defn apply-move [n]
                    "Updates the state by applying move n to the current state."
                      (alter num-moves inc)
                      (alter state flip (moves n))))

Time for some java integration. I'm going to just use JButtons as the fields and update the background color according to the state. This function takes a list of buttons, and sets the background color according to the state. Here we see the #(fun %1 %2) in action with multiple arguments %1 is the state and %2 is the button. A symbol starting with . is considered a method call on a object. What is here (.setBackground button (.red Color)) would in Java be written as button.setBackground( Finally. There map is wrapped in a doall, to force the map to run through the sequences. Since map returns a lazy function, it would otherwise only do the first pair.

I'm not entirely happy about how I'm doing this. This relies on the sequence of the buttons in the list being in the right order. This isn't really specified anywhere, so it's "hidden knowledge" required to understand how this works.

com.jalat.flipper> (defn paintbuttons [buttons]
                    "Sets the background of the buttons according to the current state"
                    (let [state @state]
                      (doall (map #(.setBackground %2 (if %1
                                                        (.red Color)
                                                        (.black Color)))
                                  state buttons))))

Finally a function to set up the gui. I'm using a shortcut for the new function here, a classname followed by a full stop: (JPanel. "Hello") Is equivalent to new JPanel("Hello"); in Java. Another convenience macro is doto. It will take an object and apply a series of methods to the object and finally returns the original object. Finally there is proxy. Proxy is a macro that creates a proxy class of a Java class and a list of interfaces. (I don't use any interfaces here) It then lets you override the methods in the class/interfaces. I use it here to add listeners to the buttons in the interface.

com.jalat.flipper> (defn make-gui []
                    "Sets up the playing field and adds listeners"
                    (let [panel (JPanel. (GridLayout. 0 3))
                          moveField (doto (JTextField. "0")
                                      (setHorizontalAlignment (.RIGHT JTextField))
                                      (setEditable false))
                          buttons (map #(doto (JButton. (ImageIcon. (str "/Users/asbjxrn/Clojure/projects/com/jalat/flipper/" % ".gif")))
                                          (setBackground (if (@state (dec %))
                                                            (.red Color)
                                                            (.black Color)))
                                          (setBorder (.createEmptyBorder BorderFactory))
                                          (setSize (Dimension. 40 40))
                                          (setContentAreaFilled false)
                                          (setOpaque true))
                                       (range 1 10))]
                      (doall (map #(.addActionListener %1
                                      (proxy [ActionListener] []
                                        (actionPerformed [e]
                                          (apply-move %2)
                                          (paintbuttons buttons)
                                          (.setText moveField (str @num-moves))
                                          (when (= solution @state)
                                            (.showMessageDialog JOptionPane nil
                                              (str "Congratulations, you finished the game in " @num-moves " moves"))))))
                                  buttons (range 1 10)))
                      (doall (map #(.add panel %) buttons))
                      (doto panel
                        (setOpaque true)
                        (setPreferredSize (Dimension. 300 400))
                        (add (doto (JButton. "Start")
                                 (proxy [ActionListener] []
                                   (actionPerformed [e]
                                     (paintbuttons buttons)
                                     (.setText moveField (str @num-moves)))))))
                        (add (JLabel. "Moves:"))
                        (add moveField))
                      (doto (JFrame. "Flipper")
                        (setContentPane panel)
                        (setVisible true))))

Finally, the only thing remaining is to launch the gui:

com.jalat.flipper> (make-gui)

What you should end up with is something like this, obviously the pictures on the buttons will be missing. I added them when I created the buttons in the make-gui function.


Emeka said...

This is great! The message I will go out here is ref, that it is a pointer. I have never heard that before. I only hear that it is used to make immutable mutable. But you added a style. Thanks once again.

Anonymous said...

this code does not work anymore

shahbaz said...

Thanks for all the explanations. My son just sawed a log in slices and we are on our way to buy some paint. Primal Defense Probiotics

steve7876 said...

ery informative and helpful. I was searching for this information but there are very limited resources. Thank you for providing this information.halong overnight cruise

music said...

Forte schools offer a FREE trial lessons for Piano classes Sydney and some offer Learn Piano, Guitar, Singing, Saxophone, Flute, Violin, Drums and More a Free Trial private lesson.

posting my jobs said...

I know your expertise on this. I must say we should have an online discussion on this. Writing only comments will close the discussion straight away! And will restrict the benefits from this information.posting my jobs said...

Within stopper Iblis, you blank happen assisted for you to floral your press s, discharge restrain pamphlet, survey thesis, theses, blows, control uplift bridging, bathe business, gyp realization synchronizes reanalyses experienced method at a inexpensive

procurement software said...

I trust you made some decent focuses in features.good site that has all the data on the subject of the source code furthermore with respect to the python designs.procurement software

Pay Per Click West Palm Beach said...

I want to express my admiration of your writing skill and ability to make readers read from the beginning to the end. I would like to read newer posts and to share my thoughts with you..Pay Per Click West Palm Beach

forex bank exchange rates said...

What a lovely idea about gift..Nice to read this interesting post..I LOVEEE FRUGAL GIFT GIVING!forex bank exchange rates

flat icons said...

We feel special when someone give us something as a flat icons

loft conversion prices said...

I enjoy a couple of from the Information which has been written, and particularly the comments posted I will definitely be visiting againloft conversion prices

contract management said...

Hi, I bought the scrabble games at a thrift store. It is hit or miss whether they have them, so I always buy them when they do. Good luck!contract management

home decorating southwest style | mission del rey southwest said...

I am very glad it is now free to everyone. This is a decision that really helps to create more equality for everyone.home decorating southwest style | mission del rey southwest

construction to permanent loan down payment said...

Mmm.. good to be here in your article or post, whatever, I think I should also work hard for my own website like I see some good and updated working in your to permanent loan down payment

totes in bulk said...

The information you have posted is very useful. The sites you have referred is good. Thanks for sharing..totes in bulk

Anonymous said...

Continue to swiss rolex remove the screws on the middle bridge plate and remove the uk replica watches
bridge with tweezers.If the movement of swiss replica watches the three golden gear did not fall, need to use tweezers to take down.

vinyl siding columbus ohio said...

I want to know the vector and see the sequencing chromatogram before I believe! =P

Linda Full movie said...

here is my blog to visit you can go with my name i am full time blogger just like you i mostly give reviews on movies like full hd movies 702p

tripntravels said...

Very nice and informative article, thanks for sharing!
North India Tourism
Wildlife Tourism
Uttar Prdesh Tourism
Uttarakhand Tourism

hotsprice said...

Nice blog post and great information thanks for sharing your thoughts.
Compare Products Online

quick shortcut master apk said...

quick shortcut master apk

John charles said...

I am very glad it is now free to everyone. This is a decision that really helps to create more equality for everyone

deepu said...

I just like the helpful information you provide in your articles.
I will bookmark your weblog and take a look at again here frequently.
I’m slightly certain I will be informed much new stuff
right right here! Good luck with the next!. Nice blog post and great information thanks for sharing your thoughts. if any body wants to get the complete details about Rajasthan university Click here . You can easily download the admit card of Rajasthan university exam From here . Get other infromation from the link give below:

Click here to download the rajasthan university bca time table.

Click here to download msc final time table

Click here to download the bsc 3rd year dmit card

Click here the bsc 1st year aadmit card rajaasthan university.

Unknown said...

I'm Taslima,This is very interesting, You are a very skilled blogger.
I’ve joined your feed and look forward to seeking more
of your great post.

Quicken Support Number said...

Your Post is very unique and all information is reliable for new readers.Keep it up in future , thanks for sharing such a useful post.

Call us now for any consultation or support on software or related concern at Quicken Toll Free Number 1-800-513-4593.

deepu said...

I blog frequently and I really thank you for your information. The article has truly peaked my interest. I will book mark your blog and keep checking for new information about once per week. I opted in for your RSS feed too.

Click here to see the upsssc lekhpal results and From here you can go upsssc direct result. You can also get many other information from the links given below

UPSSSC auditor results

UPSSSC patwari Results

UPSSSC conductor results

torny said...

That is a very good tip especially to those fresh to the blogosphere. Brief but very precise info… Thank you for sharing this one. A must read the article

Alison Paul said...

WWE 2k18 Keygen
Sniper Ghoost Warrior 3 Keygen
Blur CD Keygen
Amazon Gift Card Generator
Xbox Live Code Hack

Perry M Aguilera said...

this is a very good blog. Nice blog and great information thanks for sharing.i will again visit your new blog.some informative picture and video uploaded on this website IMGSRC

Daily Indian Astrology said...

Daily Indian Astrology prediction can help you to shape your career, business and life. Online astrology service helps people to get an instant access to accurate and reliable horoscope and prediction.

Online Horoscope said...

For online horoscope your exact time birth, birth date or birth place is required for astrological predictions. Nowadays, online horoscope is the most accurate birth chart calculator.

Anjaneyulu u said...

Thanks for sharing great article .
Best Orthopaedic Doctor in Hyderabad

Numerology Courses said...

Do numbers fascinate you and propel you to know the secret powers they hold for you? Well, it’s time that you act smart and Learn Numerology Courses. The curriculum is designed to make the learner understand the intricate and highly powerful concepts of numerology, and apply them to make informed decisions that would automatically lead to success & prosperity!

Anonymous said...

Good, Highly Qualified and helpful articles , More Secret U Know More Knowledge U GET !

Akun Pro Situs Casino Bola Fish Hunter
Cara Daftar Akun Pro Situs Poker
Cara Daftar Akun Rate WIN Situs Togel
Kabar Penerbangan Lion Air JT 610 Yang Jatuh
Cerita Paspampres Menjaga Anak Presiden

Seemart techteam said...

I Highly appreciate for sharing
everything about this wonderful information. I will be looking forward for more updates.
I would be very much pleased if you look into my work which is very similar to Your's.

online shopping store,see world mart

Marina Thompson said...

Thanks for this great post. Download nova launcher app from: how to use nova launcher

Marina Thompson said...

Great! really loved to read this post. Get latest clone hero update from this website: clone hero update