Wishful Coding

Didn't you ever wish your
computer understood you?

Clojure Rock-Paper-Scissors using a Markov chain

A long time ago I saw a challenge on a Python forum about writing a Rock-Paper-Scissors bot that performs better than a random bot.

As strange as it might seem, Rock-Paper-Scissors is anything but random. As long as it's played by people, they'll always try to come up with a winning move. I've been told there are even championships with this game.
Clojure Rock-Paper-Scissors using a Markov chain
So while trying to improve my Clojure skills I came up with the idea of using a Markov chain to write a Rock-Paper-Scissors bot.

Markov chains - as I recently learnt - are a random process where every step is only based on the previous. I'm not a psychologist, but when I play Rock-Paper-Scissors, I usually go like "I just lost using paper, so lets try rock" or "I won using rock, lets do it again", so I think it suits the challenge.

I use this map to define the probability of certain actions:
{:won {:same 1, :inferior 0, :superior 0}, :lost {:same 0, :inferior 1, :superior 0}, :draw {:same 0, :inferior 0, :superior 1}}

So with this example data, If I used rock, and won. I'll choose rock again, now I lose, so I choose the item inferior to rock: scissors. Draw, so I'll choose the item superior to scissors: rock.

The roulette function takes a map like {:same 1, :inferior 2, :superior 4} and returns one of the keys with the probability of the value. Calling this 7 times should approximately return 4 times :superior, 2 times :inferior and :same only once.

The guess function uses the Markov map to predict my action, and take the item that wins from mine.

Then there is the check function, which just returns if I won or lost based on the 2 items, and the relation fn which does the same for determining which of the 2 items is better.

Then there is the play function which focuses on getting your input, comparing results, and updating the Markov data to represent your actual actions.

You should update the map with the map that is printed at the end of the game, to improve the learning process of my bot. If you collect a lot of data, it could be interesting to send it in, so I can improve my bot to have a proper data set to start with.

Have fun!

(ns markov-stone)

;{:won {:same 0, :inferior 0, :superior 0}, :lost {:same 0, :inferior 0, :superior 0}, :draw {:same 0, :inferior 0, :superior 0}}

(defn roulette [slices]
  (let [slices (sort-by val slices)
        total (reduce + (vals slices))
        r (rand total)
        cumulative (map vector (keys slices) (reductions + (vals slices)))]
    (first (first (drop-while #(< (last %) r) cumulative)))))

(defn guess [markov prev state]
  (let [inferior {:s :p, :p :r, :r :s}
        superior (clojure.set/map-invert inferior)
        pred (->> markov
                  state
                  roulette)]
    (case pred
          :same (superior prev)
          :superior (inferior prev)
          :inferior prev)))

(defn check [user cpu]
  (if (= user cpu)
    :draw
    (if (= user (cpu {:s :p, :p :r, :r :s}))
      :lost
      :won)))

(defn relation [prev cur]
  (if (= prev cur)
    :same
    (if (= prev (cur {:s :p, :p :r, :r :s}))
      :superior
      :inferior)))

(defn play [markov prev state score]
  (println "Choose your weapon[r/p/s]!")
  (if-let [user (#{:r :p :s} (keyword (read-line)))]
    (let [names {:r "ROCK" :p "PAPER" :s "SCISSORS"}
          cpu (guess markov prev state)
          result (check user cpu)
          score (case result
                      :won (inc score)
                      :lost (dec score)
                      :draw score)]
      (println (names cpu))
      (println "Game is" (name result) "- Score:" score)
      (recur (update-in markov [result (relation prev user)] inc) user result score))
    (do
      (println "Invalid input; Final score:" score)
      markov)))

(println (play {:won {:same 20, :inferior 17, :superior 16}, :lost {:same 16, :inferior 13, :superior 38}, :draw {:same 23, :inferior 18, :superior 21}} :r :draw 0))
Published on

Restore the old iTunes icon

Since the last keynote, where Apple announced iTunes 10, I've heard a lot of complaints about the vertical close buttons and the new icons.

For the close buttons you should keep an eye on http://hints.macworld.com/, but at least I solved the problem of the ugly icon.

Before updating, save the old icon by right-clicking on iTunes, and then on "Show package contents", then browse to Content/Resources and copy iTunes.icns somewhere safe.

Now upgrade iTunes, and do the same thing in reverse, so you'll overwrite the new iTunes.icns. Below is a video and the original icon, in case you are to late to copy it yourself. You might need to start and stop iTunes a few times, or even reboot to se the "new" icon.

[[posterous-content:xcKOWzC5uTfI2Lgl3rky]]

[[posterous-content:nGbvjkjyCfDKW1Svw1lV]]

[update] Posterous doesn't like my icon. Download it from Dropbox instead: http://dl.dropbox.com/u/10094764/iTunes.icns

Also, about the control buttons: defaults write com.apple.iTunes full-window -1

http://hints.macworld.com/article.php?story=20100901223846748

A smile for web standards

We all love web standards. While I was implementing a little easter egg(which are also very lovable) on http://coverontwerp.nl/ with a good deal of CSS3 love, I thought it would be nice to turn as many clicks as possible into a smile for web standards, a mini ACID test if you will.

Bellow you'll find a CSS snippet that, when included on your site, will flash a smile for every link clicked in a supporting browser.  It is totally unobtrusive, and only blinks the moment anyone clicks a link, thus spreading some positive feelings to all supporters of web standards.

Example implementations can be found here and on http://coverontwerp.nl/. Show some standards love, by including the snippet below on your site!

a:active:after {
	display: inline-block;
	margin-left: 5px;
	font-weight: bold;
	content: ":)";
	-webkit-transform: rotate(90deg); 
	-moz-transform: rotate(90deg);
	-o-transform: rotate(90deg);
}

Other selectors, styling and ASCII arts are encouraged!