Thursday, January 21, 2010

Doctest in Python

As part of my mission to learn a new thing each day I've ended up learning about the doctest python module today. It let's you add intepreter commands and responses as docstrings for each function and let's you run them, giving you feedback if anything is amiss. Here's an example:
def fib(x):
    """
    >>> fib(0)
    0
    >>> fib(1)
    1
    >>> fib(2)
    1
    >>> fib(3)
    2
    >>> fib(4)
    4
    """
    if x == 0:
        return 0
    elif x == 1:
        return 1
    else:
        return fib(x-1) + fib(x-2)


if __name__ == '__main__':
    import doctest
    doctest.testmod()
Would return:
**********************************************************************
File "fib.py", line 11, in __main__.fib
Failed example:
fib(4)
Expected:
4
Got:
3
**********************************************************************
1 items had failures:
1 of   5 in __main__.fib
***Test Failed*** 1 failures.
It's worth noting that python doesn't handle tail recursion very well, so we wouldn't like to try running fib() on very large numbers, but it's ok for this example

Sunday, January 10, 2010

Twitter Added to My GUI

I've now added twitter functionality to my blogger gui using the python-twitter api. One of the things I plan on doing this year is learning one thing a day and posting what I learned on twitter, not sure how long I can keep it up but we'll see. You can see how I get on here My Twitter Page

Monday, January 4, 2010

Websites and Tools

I started playing around with a new website yesterday, trying to learn css, javascript in preparation for my first facebook app.
Whilst doing this I realised that making websites seemed very repetitive, and the resulting pages don't seem very neat.
What I wanted was to get through to adding content as soon as possible, but most content management systems I looked at seemed much bigger and more complicated than I needed.
So I started writing some tools to make the whole thing a lot easier. This lead me to wondering If I could make posting on my blog easier, since my malaysian connection is slow, and I don't always have a connection when I want to write posts.
So I downloaded Google's Data Protocol which would let me build an app for uploading posts.

And here it is!

My first post using my blogger posting tool. Not bad eh? Notice how it also lets me format stuff offline:

def foo():
message = 'I can even write code'
foo()


At some point I hope to get around to publishing the tools I'm working on

Thursday, December 17, 2009

Installing gtk2hs on Snow Leopard

Installed gtk2hs today on Snow leopard. It took a lot of work. Here's my summary:

Follow the Instructions on the HaskellWiki (download gtk2hs, install the GTK+ framework, install pkgconfig)

Add the following variable to you environment.plist file:

PKG_CONFIG_PATH=/Library/Frameworks/Cairo.framework/Resources/dev/lib/pkgconfig:
/Library/Frameworks/GLib.framework/Resources/dev/lib/pkgconfig:
/Library/Frameworks/Gtk.framework/Resources/dev/lib/pkgconfi

In the gtk2hs directory run:

./configure --disable-split-objs --disable-gio
make
sudo make install

Useful Sites
HaskellWiki
Haskell Cafe from Mail Archive.com

Friday, December 11, 2009

My First Haskell word in line finder

I stuck at it, and here is my finished haskell program to find all lines that contain a certain word:
findStrb :: String -> String -> Bool
findStrb key str = if key `isInfixOf` str then True else False
printList :: [String] -> IO ()
printList (x:xs) = do
putStrLn x
printList xs
main :: IO ()
main = do
infile <- readFile "ec2_list"
printList [x | x <- lines infile, findStrb "kernel" x]

Monday, November 30, 2009

Clojure Snake with Predator

Today I spent the morning trying out the Clojure snake from Stuart Halloway's Programming Clojure. I spent the afternoon making up / doing from memory a predator snake that follows the player's snake around.  Here is the full Code.
;; Setup
;;This is the test bed for me to test new things
(ns ai.snake
  (:import (java.awt Color Dimension)
           (javax.swing JPanel JFrame Timer JOptionPane)
           (java.awt.event ActionListener KeyListener))
  (:use clojure.contrib.import-static
    [clojure.contrib.seq-utils :only (includes?)] clojure.contrib.math))
(import-static java.awt.event.KeyEvent VK_LEFT VK_RIGHT VK_UP VK_DOWN)


(def width 75)
(def height 50)
(def point-size 10)
(def turn-millis 75)
(def win-length 50)
(def dirs { VK_LEFT [-1 0]
            VK_RIGHT [1 0]
            VK_DOWN [0 1]
            VK_UP [0 -1]})

;; The Functional Part            
(defn add-points [& pts]
  "Adds points together"
  (vec (apply map + pts)))
  
(defn point-to-screen-rect [pt]
  "Converts a point to a rectangle"
  (map #(* point-size %)
    [(pt 0) (pt 1) 1 1]))
    
(defn create-apple []
  {:location [(rand-int width) (rand-int height)]
    :color (Color. 210 50 90)
    :type :apple})

(defn create-snake [colour]
  {:body (list [(rand-int width) (rand-int height)])
    :dir [1 0]
    :type :snake
    :color colour})
    
(defn move [{:keys [body dir] :as snake} & grow]
  (assoc snake :body (cons (add-points (first body) dir)
    (if grow body (butlast body))))) 
    
(defn win? [{body :body}]
  (>= (count body) win-length))
  
(defn head-overlaps-body? [{[head & body] :body}]
  "Pretty neat, does the head an body include the same point?"
  (includes? body head))

(def lose? head-overlaps-body?)

(defn eats? [{[snake-head] :body} {apple :location}]
  "Very neat, All the work is done in the bindings in the function args"
  (= snake-head apple))
  
(defn turn  [snake newdir]
  (assoc snake :dir newdir))
  
;; This is the mutable part  
(defn reset-game [snake ai-snake apple]
  (dosync (ref-set apple (create-apple))
    (ref-set snake (create-snake (Color. 15 160 70))))
    (ref-set ai-snake (create-snake (Color. 15 255 70)))
    nil)
  
(defn update-direction [snake newdir]
  (when newdir (dosync (alter snake turn newdir))))
  
 (defn update-positions [snake ai-snake apple]
  (dosync
    (if (eats? @snake @apple)
      (do (ref-set apple (create-apple))
          (alter snake move :grow))
      (
      (alter snake move)
      (alter ai-snake move))))
     nil)

;;My AI part;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;(defn eats? [{[snake-head] :body} {apple :location}]
;;  "Very neat, All the work is done in the bindings in the function args"
;;  (= snake-head apple))
  
;;The functional part
 (defn point-dif [& pts]
 "The difference between two points"
    (vec (apply map - pts)))

(defn int-to-dir [pt] ;;Exception handling from Programming Clojure P83
    (try
        (/ pt (abs pt))
        (catch ArithmeticException _ 0)))

(defn point-to-dir [& pts]
    (vec (apply map int-to-dir pts)))
    
;;New direction Note that params needs to be derefed using @
(defn intercept-direction [{[target-head] :body} {[ai-head] :body}]
    (point-to-dir (point-dif target-head ai-head)))

;;End of my AI part;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


 ;; The GUI part
 (defn fill-point [g pt color]
    (let [[x y width height] (point-to-screen-rect pt)]
        (.setColor g color)
        (.fillRect g x y width height)))
        
;;Multimethod
;;Paint takes 2 args, g is the Java.awt graphics object, object is the object to be painted
(defmulti paint (fn [g object & _] (:type object)))

(defmethod paint :apple [g {:keys [location color]}]
    (fill-point g location color))
    
(defmethod paint :snake [g {:keys [body color]}]
    (doseq [point body]
        (fill-point g point color)))
        
;;The meaty part
(defn game-panel [frame snake apple ai-snake]
    (proxy [JPanel ActionListener KeyListener] []
        (paintComponent [g]
            (proxy-super paintComponent g) ;;Draw the panel
            (paint g @snake)
            (paint g @ai-snake)
            (paint g @apple))
        (actionPerformed [e]
            (update-positions snake ai-snake apple) ;;Update positions
            ;;(update-direction ai-snake (intercept-direction @snake @ai-snake)) ;;Putting it here will make the pred track you all the time
                (when (lose? @snake)
                    (reset-game snake ai-snake apple)
                    (JOptionPane/showMessageDialog frame "You Lose!"))
                (when (win? @snake)
                    (reset-game snake ai-snake apple)
                    (JOptionPane/showMessageDialog frame "You Win!"))
                (.repaint this))
        (keyPressed [e]
            (update-direction snake (dirs (.getKeyCode e)))
            (update-direction ai-snake (intercept-direction @snake @ai-snake))) ;;Putting it here will make the pred track you on change
            ;;Update the direction of the ai-snake
        (getPreferredSize []
            (Dimension. (* (inc width) point-size)
                        (* (inc height) point-size)))
        (keyReleased [e])   ;;Ignore
        (keyTyped [e])))    ;;Ignore

(defn game []
    (let [snake (ref (create-snake (Color. 15 160 70)))
        apple (ref (create-apple))
        ai-snake (ref (create-snake (Color. 15 255 70)))
        frame (JFrame. "Snake")
        panel (game-panel frame snake apple ai-snake)
        timer (Timer. turn-millis panel)]
    (doto panel
        (.setFocusable true)
        (.addKeyListener panel))
    (doto frame
        (.add panel)
        (.pack)
        (.setVisible true))
    (.start timer)
    [snake, apple, timer]))
               
 (def test-snake (ref nil))
 (def test-ai (ref nil))
 (def test-apple (ref nil)) 

Sunday, November 22, 2009

Today's Learning

Had a great day today.
I bought a copy of Cloud Application Architectures by George Reese on Friday, after getting hundreds of emails from the Sun Developer Network about cloud stuff. So today I spent the morning and mid afternoon signing up to Amazon web services and playing around with S3 and EC2. Then spent the afternoon continuing my progress through Real World Haskell, ending with my first file reader that parsed my list of EC2 servers and told me how many there were. Not exactly anything ground breaking but a lot of stuff learned. Now I'm off to read the next chapter of CAA.