stuff & things

-
Oct 25

Team composition

Team makeup

Pragmatist, Perfectionist, Crazy Smart

http://heroku.com/about

Interactions

A quote to start: This quote is the designers’ reflections on designing a programming language (SIMULA).

In the spring of 1967 a new employee at the NCC in a very shocked voice told the switchboard operator: “Two men are fighting violently in front of the blackboard in the upstairs corridor. What shall we do?” The operator came out of her office, listened for a few seconds and then said: “Relax, it’s only Dahl and Nygaard discussing SIMULA”.

The story is true. The SIMULA 67 language was the outcome of ten months of an almost continuous sequence of battles and cooperation in front of that blackboard - interrupted by intervals when we worked in our neighbouring offices (communicating by shouting through the wall if necessary) or at home. (The people arranging this conference asked us to provide material relating to the development of our respective languages. We felt that the best thing we could have done was to bring along that blackboard. But we did not know for certain whether we would be flying a wide-body aircraft.)

In some research teams a new idea is treated with loving care: “How interesting:”, “Beautiful:”. This was not the case in the SIMULA development. When one of us announced that he had a new idea, the other would brighten up and do his best to kill it off. Assuming that the person who got the idea is willing to fight, this is a far better mode of work than the mode of mutual admiration. We think it was useful for us, and we succeeded in discarding a very large number of proposals.

(from http://www.oberon2005.ru/paper/kn1978-01e.pdf via http://lambda-the-ultimate.org/node/3107)

Isn’t that fantastic? You know that the “idea-defender” here would need to quickly detach himself from any silly latent emotional attachment to an idea. Any idea in that situation is going have to live on its own merits.

If you’ve got someone who you know will rip into your shitty ideas with pointed criticism, then:

  1. you’re not going to do dumb stuff; and
  2. you’re going to know that you’ve got a winner when you get them on board.

That kind of relationship is a huge asset. It’s one thing that turns you into (the very cliched) “more than the sum of your parts”. If you can do this, you’re really combining your 2+ brains effectively.

Drop your ego, cultivate these relationships, and then hang on to them for dear life.


Comments (View)
Jul 25

Really? REALLY? wtf.

js> x = [];

js> x[0] = "num0";
num0
js> x[1] = "num1";
num1
js> x[2] = "num2";
num2
js> x
num0,num1,num2
js> x["1"] = "str";
str
js> x
num0,str,num2
js>

Someone please tell me there’s a way to avoid this idiotic behaviour.


Comments (View)
Feb 9
ImgBurn rocks the shizzle.

ImgBurn rocks the shizzle.


Comments (View)
Jan 28
Huzzah!

Huzzah!


Comments (View)
Nov 15

First Clojure program

So, I watched a few of Rich’s videos on Clojure a couple months back, but I finally got an afternoon to spend trying it out.

I skimmed through Ruby Quiz to find an interesting but simple problem, and I decide to write a Sokoban clone.

My initial thought was to do it as a gui app, but I haven’t written any Java code since JDK 1.0-alpha in late 1995, and honestly, I didn’t really feel like putting effort into learning the Java GUI API only to end up with a bizarrely emulated, slightly broken GUI.

So, I grabbed Compojure off of git, and made the UI a hack webapp. (Yes, it’s bizarrely emulated and slightly broken still, but at least it was easy to write).

First, have a look at the result: Clojban!

If you care, the (probably horrible and un-idiomatic) code follows.

(ns clojban
  (:use (compojure html
                   http
                   file-utils)
        (clojure.contrib str-utils
                         seq-utils)
        (clojure set))
  (:import (java.util.regex Pattern)))

(defstruct pos :x :y)
(defstruct level
           :player ; pos
           :boxes  ; set-of-pos
           :goals  ; set-of-pos
           :walls  ; set-of-pos
           )

(defn explode
  "return a pos/type seq for each char in the line"
  [y line]
  (map (fn [x y type] (vector (struct pos x y) type))
       (iterate inc 0) (repeat y) line))

(defn line-explode
  "call explode on each line with the appropriate y"
  [lines]
  (let [linesplit (. Pattern compile "\n" (. Pattern MULTILINE))] ; must be a better way?
    (reduce into
            (map explode
                 (iterate inc 0)
                 (. linesplit split lines)))))

(defn filter-level
  "extracts a set of the pos's that match types"
  [expl-level type1 type2 & type3]
  (set (map first
            (filter (fn [item]
                      (or (= (second item) type1)
                          (= (second item) type2)
                          (= (second item) type3)))
                    expl-level))))

(defn load-levels
  "load and return seq of level's"
  [filename]
  (let [contents (slurp filename)
        levelsplit (. Pattern compile "^$\n" (. Pattern MULTILINE)) ; each level separated by blank line
        levels (seq (. levelsplit split contents))]

    (map (fn [levelstr]
           (let [expl-level (line-explode levelstr)]
             (struct-map level
                         :player (first (filter-level expl-level \@ \+))
                         :boxes (filter-level expl-level \o \*)
                         :goals (filter-level expl-level \. \* \+)
                         :walls (filter-level expl-level \# \#))))
         levels)))

(def Levels (load-levels "sokoban_levels.txt"))
(def LvlWidth 19)
(def LvlHeight 16)
(def PlayerRenderOpen "♦")
(def PlayerRenderGoal "♦")
(def BoxRenderOpen "▨")
(def BoxRenderGoal "▨")
(def WallRender "█")
(def GoalRender "░")

(defn level-index [x y] (+ (* y LvlWidth) x))



(defn render-level-layer
  "my, what an insane level representation i have here"
  [target items if-empty if-full]
  (loop [target target
         remain (seq items)]
    (if remain
      (let [x (:x (first remain))
            y (:y (first remain))
            i (level-index x y)
            at (target i)]
        (recur (assoc target i (if (= at \space) if-empty if-full))
               (rest remain)))
      target)))

(defn render-level
  [lvl]
  (let [finallevel (reduce (fn [lvl data] (render-level-layer lvl (nth data 0) (nth data 1) (nth data 2))) ; todo how to splat `data'
                           (vec (replicate (* LvlWidth LvlHeight) \space))
                           `((~(:walls lvl) ~WallRender ~WallRender)
                             (~(:goals lvl) ~GoalRender ~GoalRender)
                             (~(:boxes lvl) ~BoxRenderOpen ~BoxRenderGoal)
                             (~(set (list (:player lvl))) ~PlayerRenderOpen ~PlayerRenderGoal)))]
    (dotimes y LvlHeight
      (print "")
      (dotimes x LvlWidth
        (print "")
        (print (finallevel (level-index x y)))
        (print ""))
      (print ""))))

(def AsciiToDx {72 -1,
                76  1,
                75  0,
                74  0})
(def AsciiToDy {72  0,
                74  1,
                75  -1,
                76  0})

(defn do-player-move
  "handle player movement, input is int ascii code for HJKL."
  [level input]
  (let [dx (get AsciiToDx input)
        dy (get AsciiToDy input)
        curpos (:player level)
        candidatepos (struct pos (+ (:x curpos) dx) (+ (:y curpos) dy))
        pastcandidatepos (struct pos (+ (:x curpos) dx dx) (+ (:y curpos) dy dy))
        walls (:walls level)
        boxes (:boxes level)]
    (if (walls candidatepos)
      level
      (if (boxes candidatepos)
        (if (or (walls pastcandidatepos) (boxes pastcandidatepos))
          level
          (assoc
            (assoc level :boxes (conj (disj boxes candidatepos) pastcandidatepos)) ; move box
            :player candidatepos)) ; and player
        (assoc level :player candidatepos))))) ; only player

(def JSCode "
function postwith (p) {
  var myForm = document.createElement('form');
  myForm.method='post';
  myForm.action='/';
  for (var k in p) {
    var myInput = document.createElement('input');
    myInput.setAttribute('name', k);
    myInput.setAttribute('value', p[k]);
    myForm.appendChild(myInput);
  }
  document.body.appendChild(myForm) ;
  myForm.submit() ;
  document.body.removeChild(myForm) ;
}

function handlekey(e) {
  if (!e) var e = window.event
  if (e.keyCode) code = e.keyCode;
  else if (e.which) code = e.which;
  if (code == 37) code = 72;
  if (code == 38) code = 75;
  if (code == 39) code = 76;
  if (code == 40) code = 74;
  if (code == 72 || code == 74 || code == 75 || code == 76 || code == 82 || code == 65 || code == 90) postwith({'code': code});
}
")

(defn restart-level [session]
  (alter session assoc :curlevel (or (session :curlevel) 0))
  (alter session assoc :complete (or (session :complete) (set nil)))
  (alter session assoc :nummoves 0)
  (alter session assoc :level (nth Levels (or (session :curlevel) 0))))

(defn next-level [session]
  (alter session assoc :curlevel (min
                                   (inc (session :curlevel))
                                   (- (count Levels) 1)))
  (restart-level session))

(defn prev-level [session]
  (alter session assoc :curlevel (max (dec (session :curlevel)) 0))
  (restart-level session))

(defservlet clojban-servlet
  (POST "/"
        (dosync
          (let [prevlevel (session :level)
                keycode (. Integer parseInt (params :code))]
            (if (= keycode 82)
              (restart-level session)
              (if (= keycode 65)
                (prev-level session)
                (if (= keycode 90)
                  (next-level session)
                  (let [moveresult (do-player-move prevlevel keycode)]
                    (if (= 0 (count (difference (:boxes moveresult) (:goals moveresult))))
                      (do
                        (alter session assoc :complete (conj (session :complete) (session :curlevel)))
                        (next-level session))
                      (do
                        (alter session assoc :nummoves (inc (session :nummoves)))
                        (alter session assoc :level moveresult)))))))))
        (redirect-to "/"))
  (GET "/"
       (let [levelstate (or (session :level) (dosync (restart-level session) (session :level)))]
         [{"Content-Type" "text/html"}
          (html
            (doctype :xhtml-transitional)
            [:html {:xmlns "http://www.w3.org/1999/xhtml" :lang "en"}
             [:head
              [:title "Clojban!"]
              [:meta {:http-equiv "Content-Type", :content "text/html; charset=utf-8"}]
              [:script {:type "text/javascript"} JSCode]]
             [:body {:onkeydown "handlekey(event);" :style "font-family: arial; font-size: 13px;"}
              [:h1 {:style "font-family: arial;"} "Clojban"]
              [:p "This is a silly Sokoban implemented in " (link-to "http://clojure.org" "Clojure") ". It's hitting the server every time you move (rather than Javascript) so it might not respond too quickly. The unicode box drawing craziness looks OK in FF, and reasonable in IE, but not so hot in Chrome/Webkit. Sorry."]
              [:table {:style "border-style: none; font-size: 36px; font-family: courier; padding: 0px 0px 0px 0px; margin:0px 0px 0px 0px; line-height: 1em;"
                       :border "0"
                       :cellpadding "0"
                       :cellspacing "0"}
               (with-out-str (render-level levelstate))]
              [:p "Use arrow keys or hjkl to move all the boxes into the goals. Press r to restart level, or a/z to give up and skip through levels."]
              [:p "Level: " (session :curlevel)]
              [:p "Moves: " (session :nummoves)]
              [:p "Completed: " (str-join " " (map (fn [i]
                                                     (let [complete (session :complete)]
                                                       (format "%d"
                                                               (if (complete i) "green" "#ccc")
                                                               i)))
                                                   (range (count Levels))))]
              ]])]))
  (ANY "*"
       (page-not-found)))

Comments (View)
Nov 10

Configuring Vim, some more

As an addendum to http://items.sjbach.com/319/configuring-vim-right

Here’s a few more that I think are un-live-able-without:

" ease of use keyboard mappings (why do I care about top/bottom of screen?)
map H ^
map L $

" buffer switching/management, might as well use those keys for something useful
map <Right> :bnext<CR>
imap <Right> <ESC>:bnext<CR>
map <Left> :bprev<CR>
imap <Left> <ESC>:bprev<CR>
map <Del> :bd<CR>

" get rid of stupid scrollbar/menu/tabs/etc
set guioptions=a

" don't need /g after :s or :g
set gdefault

" i prefer this to visualbell
set noerrorbells
" Hide the mouse pointer while typing
set mousehide

I’ve used all of these for longer than I can remember, probably time to troll through recent help files and vim.org to find new and exciting juicy settings.

EDIT: forgot the one I miss the most when I don’t have my .vimrc:

cab o find

so that :o does something useful. I’d like one of the emacs-style smart-fuzz-file-opener command line thing, I should probably hunt around for a plugin to do that.


Comments (View)
Aug 24

Bill C-61

Canada’s Bill C-61 is an even-worse version of the United States’ DMCA.

For more information, http://www.michaelgeist.ca/ is a reasonable starting point. I rolled up my sleeves and had a go at http://www2.parl.gc.ca/HousePublications/Publication.aspx?Docid=3570473&file=4 which is relatively readable.

Here’s the letter I just posted (yes, on actual paper, in an envelope!) to my MP.

If you’re Canadian, please read the above links and if you don’t agree with this Bill, as I’m confident you won’t, phone or write to your MP (especially if your MP is a Conservative Party member!)

————————————

Office of the Honourable Dr. Hedy Fry, P.C., M.P.
Confederation Building House of Commons
Ottawa, Ontario
K1A 0A6

Hello Dr. Fry

I am a resident of Vancouver Centre, and I’m writing to you to express my absolute horror at the current state of Bill C-61.

I am employed as a software engineer in the entertainment industry, and as such, fully respect and understand the need for copyright reform in Canada.

However, from reading this bill (at http://www2.parl.gc.ca/HousePublications/Publication.aspx?Docid=3570473), the reproduction rights afforded to Canadians are absolutely useless because of section 29.21(c). This section subordinates any time-shifting and media-shifting rights that should be allowed, merely by having any kind of digital lock mechanism on the content. But, virtually all media sold in Canada now contains a digital lock of some sort, so it’s almost pointless to “grant” these rights.

Inevitably, the devices or internet services which control the digital lock access fail, go out of business, or otherwise are not maintained. If we are unable to legally shift to other formats, and the media become un-unlockable, they are effectively gone. Will all of the companies and individuals controlling the locks exist in 5 years? Maybe. 50 years? Unlikely.

I would also like to especially point out that this does not solely concern things that could perhaps be considered “frivolous”, like pop-consumer-ish music and video. Over the next 10-15 years, it is all but guaranteed that most books, and crucially text books, will be delivered and consumed in electronic form. My wife is a high school teacher employed by the Vancouver School Board, and I would be horrified to find that our already underfunded education system had lost access to teaching resources, simply because the company controlling a digital lock had failed.

I sincerely hope you will make sure that this Bill is heavily modified, or defeated, when the time comes.

Thank you for your time,





Scott Graham
<my address removed>


Comments (View)
Aug 9

Braid

Braid is very cool. I often enjoyed reading The Inner Product in GDMag, but always got the impression Jonathan was a little “ivory tower”. Turns out, I don’t know shit. Congrats to Mr Blow! (just grabbed the full 360 version: it’s fantastic).


Comments (View)
Aug 6

floating point

Floating-point tends to chafe my ass. I was thinking perhaps I’d try to really understand it. These look interesting:

http://citeseer.ist.psu.edu/goldberg91what.html

http://www.cant.ua.ac.be/ieeecc754.html

http://fluorescence.fjfi.cvut.cz/~adamek/nm/ieee754.pdf

Only way to understand something is to implement it though…

[Update]: even better by the looks of it: http://docs.sun.com/source/806-3568/ncgTOC.html


Comments (View)
Jul 29

Second “das keyboard”

So, I just got my second http://www.daskeyboard.com/ in the mail. The first one I had was the “original”, and I loved and continue to love it. I’ve been using it as my work keyboard (where I do the majority of my coding) for the last 3 years or so.

I just got a second one, but it’s the “new” version (the only one they offer now). It’s cleaner design-wise, but there’s some things that I think they’ve made worse.

The first is that the keyboard is just too thick. It’s gotten half an inch (or so) thicker. It feels more solid now, and is quite a bit heavier (so it doesn’t move around at all, which is nice), but the angle of my forearms is slightly higher, which inevitably means my wrists are more crooked when I get more tired and drop my arms, and slouch, etc. Don’t like that very much, especially as I’ve had some wrist and arm pain recently.

They also seem to have killed the variable resistance on keys (or at least tuned them differently). The only key I notice that’s harder resistance is the backspace key, whereas the space key used to have a lot more resistance, and doesn’t all now. Perhaps the resistance has changed over time on my original one, so it’s just a matter of getting used to this one, or breaking it in more. Maybe it’s more expensive to do the bands of keys with different resistances, but I’m pretty sad about it, especially since this one ended up being about 30% more expensive than the original.

Oh, and the F and J have icky bumps instead of being nicely scooped. :( I’m guessing that one was a concession to people who weren’t very good typists, and couldn’t find the home row, but I prefer the scoops, since we are going for “stealth” here, after all. They just felt nicer on your finger tips too.

The sound of the switches has changed too, but that’s just… different, not really better or worse.

I’m going to guard my old one even more carefully now with the knowledge that they’re not really replaceable. Hopefully I’ll grow to love the new one as much, but the jury’s still out.


Comments (View)
Page 1 of 4