<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1789861069162129577</id><updated>2011-11-13T17:00:48.770-08:00</updated><category term='Boggle'/><category term='MORGE'/><category term='Discriminated Union'/><category term='html5'/><category term='Pi'/><category term='Javascript'/><category term='Review'/><category term='Pi Day'/><category term='Physics Engine'/><category term='F#'/><category term='Tutorial'/><category term='Effect FX'/><category term='Multiplication'/><category term='Algorithm'/><category term='Game Theory'/><category term='Nvidia'/><category term='Tetris'/><category term='Breakout'/><category term='Primitives'/><category term='XNA 3.0'/><category term='2D Classics'/><category term='Interview Question'/><category term='canvas'/><category term='Book'/><category term='Autodesk'/><category term='sort'/><title type='text'>Intrinsic Programming by Erik Schulz</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>29</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-2036745149441768046</id><published>2011-03-16T19:18:00.000-07:00</published><updated>2011-03-16T19:56:36.292-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Boggle'/><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='Interview Question'/><title type='text'>Solving Boggle</title><content type='html'>&lt;p&gt;Trie&lt;/p&gt;&lt;pre class="brush: jscript"&gt;function Trie(dictionary) {&lt;br /&gt;  var trie = {};&lt;br /&gt;  &lt;br /&gt;  function insert(word, trie) {&lt;br /&gt;    var word_length = word.length;&lt;br /&gt;    &lt;br /&gt;    if (word_length) {&lt;br /&gt;      var next = trie;&lt;br /&gt;      &lt;br /&gt;      for (var i = 0; i &lt; word_length; i++) {&lt;br /&gt;        var char = word[i];&lt;br /&gt;        &lt;br /&gt;        if (char in next) {&lt;br /&gt;          next = next[char];&lt;br /&gt;        } else {&lt;br /&gt;          var child = {};&lt;br /&gt;          next[char] = child;&lt;br /&gt;          next = child;      &lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;      &lt;br /&gt;      next['|'] = null;&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  for (var i = 0, length = dictionary.length; i &lt; length; i++) {&lt;br /&gt;    insert(dictionary[i], trie);&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  // returns true for a word, null for a segment and false otherwise&lt;br /&gt;  this.test = function(str) {&lt;br /&gt;    var next = trie;&lt;br /&gt;    &lt;br /&gt;    for (var i = 0, str_length = str.length; i &lt; str_length; i++) {&lt;br /&gt;      var char = str[i];&lt;br /&gt;&lt;br /&gt;      if (char in next) {&lt;br /&gt;        next = next[char];&lt;br /&gt;      } else {&lt;br /&gt;        return null;&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    return '|' in next;    &lt;br /&gt;  }; &lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;Boggle Search&lt;/p&gt;&lt;pre class="brush: jscript"&gt;// main workhorse, depth first&lt;br /&gt;function start_search(start_x, start_y, length_x, length_y, segment, trie, board, visited, results) {&lt;br /&gt;  var min_y = Math.max(0, start_y - 1), &lt;br /&gt;      min_x = Math.max(0, start_x - 1),&lt;br /&gt;      max_y = Math.min(length_y - 1, start_y + 1),&lt;br /&gt;      max_x = Math.min(length_x - 1, start_x + 1);&lt;br /&gt;      &lt;br /&gt;  for (var y = min_y; y &lt;= max_y; y++) {&lt;br /&gt;    var visited_y = visited[y],&lt;br /&gt;        board_y = board[y];&lt;br /&gt;        &lt;br /&gt;    for (var x = min_x; x &lt;= max_x; x++) {&lt;br /&gt;      if (!visited_y[x]) {&lt;br /&gt;        var segment_new = segment + board_y[x],&lt;br /&gt;            test = trie.test(segment_new);&lt;br /&gt;        &lt;br /&gt;        if (test === true) {&lt;br /&gt;          results[segment_new] = true;&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        if (test !== null) {&lt;br /&gt;          visited_y[x] = true;&lt;br /&gt;          start_search(x, y, length_x, length_y, segment_new, trie, board, visited, results);&lt;br /&gt;          visited_y[x] = false;&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function search(trie, board) {&lt;br /&gt;  var length_y = board.length,&lt;br /&gt;      length_x = board[0].length;&lt;br /&gt;  &lt;br /&gt;  var visited = [];&lt;br /&gt;  for (var y = 0; y &lt; length_y; y++) {&lt;br /&gt;    visited[y] = [];&lt;br /&gt;    for (var x = 0; x &lt; length_x; x++) {&lt;br /&gt;      visited[y][x] = false;&lt;br /&gt;    }&lt;br /&gt;  }    &lt;br /&gt;    &lt;br /&gt;  var results = {};&lt;br /&gt;  for (var y = 0; y &lt; length_y; y++) {&lt;br /&gt;    var visited_y = visited[y],&lt;br /&gt;        board_y = board[y];&lt;br /&gt;          &lt;br /&gt;    for (var x = 0; x &lt; length_x; x++) {&lt;br /&gt;      visited_y[x] = true;&lt;br /&gt;      start_search(x, y, length_x, length_y, board_y[x], trie, board, visited, results);&lt;br /&gt;      visited_y[x] = false;&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  var result_array = [];&lt;br /&gt;  for (var word in results) {&lt;br /&gt;    if (results.hasOwnProperty(word)) {&lt;br /&gt;      result_array.push(word);&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  result_array.sort();&lt;br /&gt;  &lt;br /&gt;  return result_array;  &lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;Example Execution&lt;/p&gt;&lt;pre class="brush: jscript"&gt;function solve_boggle(dictionary) {&lt;br /&gt;  var board = [&lt;br /&gt;      ["d", "g", "f", "k"],&lt;br /&gt;      ["o", "z", "a", "c"],&lt;br /&gt;      ["b", "w", "k", "e"],&lt;br /&gt;      ["b", "w", "k", "e"]&lt;br /&gt;    ],&lt;br /&gt;    trie = new Trie(dictionary),&lt;br /&gt;    results = search(trie, board);&lt;br /&gt;  &lt;br /&gt;  $(".results").text(results.join(", "));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;if (window.localStorage !== null &amp;&amp; window.localStorage.dictionary) {&lt;br /&gt;  solve_boggle(window.localStorage.dictionary.split(","), callback);&lt;br /&gt;} else {&lt;br /&gt;  function dictionary_load(data) {&lt;br /&gt;    if (window.localStorage !== null) {&lt;br /&gt;       window.localStorage.dictionary = data.join(",");&lt;br /&gt;    }&lt;br /&gt;    solve_boggle(data, callback);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  $.getScript("http://goo.gl/8EhgZ");&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div id="solving-boggle"&gt;&lt;/div&gt;&lt;script type="text/javascript" src="http://www.gradient.info/blog/solving-boggle.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-2036745149441768046?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/2036745149441768046/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=2036745149441768046' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/2036745149441768046'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/2036745149441768046'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2011/03/solving-boggle.html' title='Solving Boggle'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-5999880599180532939</id><published>2010-12-17T09:52:00.000-08:00</published><updated>2010-12-17T09:52:36.941-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Multiplication'/><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='Interview Question'/><title type='text'>Product Array - Interview Question</title><content type='html'>&lt;p&gt;Given an array of numbers return an array where each item is replaced by the product of all the other items in the array.&lt;/p&gt;&lt;p&gt;A trivial solution would be to multiply the elements repeatedly for each result giving an O(n^2) solution.&lt;/p&gt;&lt;pre class="brush: jscript"&gt;var productOfOthers = function(input) {&lt;br /&gt;    var length = input.length;&lt;br /&gt;    &lt;br /&gt;    var result = [];&lt;br /&gt;    for (var i = 0; i &lt; length; i++) {&lt;br /&gt;        result[i] = 1;&lt;br /&gt;        for (var j = 0; j &lt; length; j++) {&lt;br /&gt;            if (i != j) {&lt;br /&gt;                result[i] *= input[j];&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    return result;&lt;br /&gt;};&lt;/pre&gt;&lt;p&gt;You could get the total product first and then divide by each element for O(n) but you may introduce floating point error and you have to deal with dividing by zero.&lt;/p&gt;&lt;pre class="brush: jscript"&gt;var productOfOthers = function(input) {&lt;br /&gt;    var length = input.length;&lt;br /&gt;    &lt;br /&gt;    var product = 1;&lt;br /&gt;    for (var i = 0; i &lt; length; i++) {&lt;br /&gt;        product *= input[i];&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    var result = [];&lt;br /&gt;    for (var i = 0; i &lt; length; i++) {&lt;br /&gt;        result[i] = product / input[i];&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    return result;&lt;br /&gt;};&lt;/pre&gt;&lt;p&gt;Taking advantage of Multiplications Associative property you can get minimal error in O(n) by making two runners, one forward and one backward, to calculate the result by result[i] = forward[i-1] * backward[i+1]. &lt;/p&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_9tQTRFC8wPE/TQueDdpqxkI/AAAAAAAAAek/AuvecZ9Vfms/s1600/visualize_multiply.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_9tQTRFC8wPE/TQueDdpqxkI/AAAAAAAAAek/AuvecZ9Vfms/s1600/visualize_multiply.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;pre class="brush: jscript"&gt;var productOfOthers = function(input) {&lt;br /&gt;    var length = input.length;&lt;br /&gt;    &lt;br /&gt;    if (length &lt;= 1) {&lt;br /&gt;        if (length == 1) {&lt;br /&gt;            return [input[0]];&lt;br /&gt;        } else {&lt;br /&gt;            return [];          &lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;        &lt;br /&gt;    var forward = [];&lt;br /&gt;    var product = 1;&lt;br /&gt;    for (var i = 0; i &lt; length; i++) {&lt;br /&gt;        product *= input[i];&lt;br /&gt;        forward[i] = product;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    var backward = [];&lt;br /&gt;    var product = 1;&lt;br /&gt;    for (var i = length - 1; i &gt;= 0; i--) {&lt;br /&gt;        product *= input[i];&lt;br /&gt;        backward[i] = product;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    var result = [];&lt;br /&gt;    for (var i = 1; i &lt; length - 1; i++) {&lt;br /&gt;        result[i] = forward[i - 1] * backward[i + 1];&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    result[0] = backward[1];&lt;br /&gt;    result[length - 1] = forward[length - 2];   &lt;br /&gt;    &lt;br /&gt;    return result;&lt;br /&gt;};&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-5999880599180532939?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/5999880599180532939/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=5999880599180532939' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/5999880599180532939'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/5999880599180532939'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2010/12/product-array-interview-question.html' title='Product Array - Interview Question'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_9tQTRFC8wPE/TQueDdpqxkI/AAAAAAAAAek/AuvecZ9Vfms/s72-c/visualize_multiply.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-7325634030233781066</id><published>2010-12-16T09:00:00.000-08:00</published><updated>2010-12-16T09:00:45.283-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='Interview Question'/><category scheme='http://www.blogger.com/atom/ns#' term='Game Theory'/><title type='text'>Pots of Gold - Interview Question</title><content type='html'>&lt;p&gt;Given n pots of gold arranged in a line containing different quantities of coins.  You are allowed to remove one pot of gold from either end and then another player gets to remove one.  This is repeated until no pots remain.  Write an algorithm to find the set of moves for collecting the most coins in a two player game.  Assume your opponent also takes optimal moves.&lt;/p&gt;&lt;pre class="brush: jscript"&gt;var max_gold = function(pots) {&lt;br /&gt;  var length = pots.length;&lt;br /&gt;  if (length &lt;= 1) {&lt;br /&gt;    if (length == 1) {&lt;br /&gt;      return {first: [pots[0]], second: []};&lt;br /&gt;    } else {&lt;br /&gt;      return {first: [], second: []};&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  var left = max_gold(pots.slice(1));&lt;br /&gt;  var right = max_gold(pots.slice(0, -1));&lt;br /&gt;  &lt;br /&gt;  var left_pot = pots[0]; &lt;br /&gt;  var right_pot = pots[length - 1];&lt;br /&gt;  &lt;br /&gt;  var left_total = left_pot + sum(left.second);&lt;br /&gt;  var right_total = right_pot + sum(right.second);&lt;br /&gt;&lt;br /&gt;  if (left_total &gt;= right_total) {&lt;br /&gt;    return {&lt;br /&gt;      first: [left_pot].concat(left.second), &lt;br /&gt;      second: left.first&lt;br /&gt;    };&lt;br /&gt;  } else {&lt;br /&gt;    return {&lt;br /&gt;      first: [right_pot].concat(right.second),&lt;br /&gt;      second: right.first&lt;br /&gt;    };&lt;br /&gt;  }&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;// sample input &lt;br /&gt;[11, 19, 18, 16, 1, 4, 7, 3, 6, 2]&lt;br /&gt;// sample output&lt;br /&gt;{first: [11, 18, 2, 3, 4], second: [19, 16, 6, 7, 1]}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;This can be easily optimized from O(2^n) into O(n^2) by moving to array indexes and memoization.  Note: I'm ignoring the cost of sum, slice and concat for BigO.  If you only wanted the total then you could just keep track of it instead of an array and save a bunch of memory.&lt;/p&gt;&lt;pre class="brush: jscript"&gt;var max_gold = memoize(function(pots, start, stop) {&lt;br /&gt;  if (start &gt;= stop) {&lt;br /&gt;    if (start == stop) {&lt;br /&gt;      return {first: [pots[start]], second: []};&lt;br /&gt;    } else {&lt;br /&gt;      return {first: [], second: []};&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  var left = max_gold(pots, start + 1, stop);&lt;br /&gt;  var right = max_gold(pots, start, stop - 1);&lt;br /&gt;  &lt;br /&gt;  var left_pot = pots[start]; &lt;br /&gt;  var right_pot = pots[stop];&lt;br /&gt;  &lt;br /&gt;  var left_total = left_pot + sum(left.second);&lt;br /&gt;  var right_total = right_pot + sum(right.second);&lt;br /&gt;&lt;br /&gt;  if (left_total &gt;= right_total) {&lt;br /&gt;    return {&lt;br /&gt;      first: [left_pot].concat(left.second), &lt;br /&gt;      second: left.first&lt;br /&gt;    };&lt;br /&gt;  } else {&lt;br /&gt;    return {&lt;br /&gt;      first: [right_pot].concat(right.second),&lt;br /&gt;      second: right.first&lt;br /&gt;    };&lt;br /&gt;  }&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;var memoize = function(f) {&lt;br /&gt;  var store = {};&lt;br /&gt;  return function(pass_through, x, y) {&lt;br /&gt;    var value;&lt;br /&gt;    if (x in store) {&lt;br /&gt;      if (y in store[x]) {&lt;br /&gt;        value = store[x][y]; &lt;br /&gt;      } else {&lt;br /&gt;        value = f(pass_through, x, y);&lt;br /&gt;        store[x][y] = value;&lt;br /&gt;      }&lt;br /&gt;    } else {&lt;br /&gt;      value = f(pass_through, x, y);&lt;br /&gt;      store[x] = {};&lt;br /&gt;      store[x][y] = value;&lt;br /&gt;    }&lt;br /&gt;    return value;&lt;br /&gt;  }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;You can remove the memoization with dynamic programming for extra speed at the cost of some readability.&lt;/p&gt;&lt;pre class="brush: jscript"&gt;var max_gold_dynamic = function(pots) {&lt;br /&gt;  var length = pots.length;&lt;br /&gt;  var gold_array = [];&lt;br /&gt;  for (var start = length - 1; start &gt;= 0; start--) {&lt;br /&gt;    gold_array[start] = [];&lt;br /&gt;    for (var stop = start; stop &lt; length; stop++) {&lt;br /&gt;      if (start &gt;= stop) {&lt;br /&gt;        if (start == stop) {&lt;br /&gt;          gold_array[start][stop] = {first: [pots[start]], second: []};&lt;br /&gt;          continue;&lt;br /&gt;        } else {&lt;br /&gt;          gold_array[start][stop] = {first: [], second: []};&lt;br /&gt;          continue;&lt;br /&gt;        }&lt;br /&gt;      }&lt;br /&gt;      &lt;br /&gt;      var left = gold_array[start + 1][stop];&lt;br /&gt;      var right = gold_array[start][stop - 1];&lt;br /&gt;    &lt;br /&gt;      var left_pot = pots[start]; &lt;br /&gt;      var right_pot = pots[stop];&lt;br /&gt;      &lt;br /&gt;      var left_total = left_pot + sum(left.second);&lt;br /&gt;      var right_total = right_pot + sum(right.second);&lt;br /&gt;    &lt;br /&gt;      if (left_total &gt;= right_total) {&lt;br /&gt;        gold_array[start][stop] = {&lt;br /&gt;          first: [left_pot].concat(left.second), &lt;br /&gt;          second: left.first&lt;br /&gt;        };&lt;br /&gt;      } else {&lt;br /&gt;        gold_array[start][stop] = {&lt;br /&gt;          first: [right_pot].concat(right.second),&lt;br /&gt;          second: right.first&lt;br /&gt;        };&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  return gold_array[0][length - 1];&lt;br /&gt;};&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-7325634030233781066?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/7325634030233781066/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=7325634030233781066' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/7325634030233781066'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/7325634030233781066'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2010/12/pots-of-gold-interview-question.html' title='Pots of Gold - Interview Question'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-3410415845895429221</id><published>2010-07-07T14:03:00.000-07:00</published><updated>2010-07-07T14:28:39.571-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='html5'/><category scheme='http://www.blogger.com/atom/ns#' term='canvas'/><category scheme='http://www.blogger.com/atom/ns#' term='sort'/><title type='text'>Beating Quick Sort - Cartesian Tree Merge</title><content type='html'>&lt;p&gt;After looking at skew heap, merge sort and Cartesian tree, I figured there has to be a way to combine all three.  My idea is to start with a cartesian tree, take its root as the first element and then merge its leafs in a way that skews them to the right.  Children swapping is employed to keep the tree shallow.  The number of comparisons required for this sort is consistently less than quick sort.  I also changed the Cartesian tree generator to use a stack instead of a parent node to save memory.&lt;/p&gt;&lt;div id="cartesianTreeMergeSort"&gt;&lt;img src="http://gradient.info/blog/img/cartesian_tree_skew.png"/&gt;&lt;/div&gt;&lt;br style="clear:both"/&gt;&lt;br /&gt;&lt;p&gt;A second test with partially sorted data.&lt;/p&gt;&lt;div id="cartesianTreeMergeSortB"&gt;&lt;/div&gt;&lt;br style="clear:both"/&gt;&lt;br /&gt;&lt;pre class="brush: jscript"&gt;algorithms.sort.cartesian_tree_merge = function(array, predicate) {&lt;br /&gt;    var length = array.length;&lt;br /&gt;    if (length &lt;= 1) return;&lt;br /&gt;    &lt;br /&gt;    var root = {"value": array[0], "left": null, "right": null};&lt;br /&gt;    var last = root;&lt;br /&gt;    var stack = [];&lt;br /&gt;    &lt;br /&gt;    for (var i = 1; i &lt; length; i++) {&lt;br /&gt;        while(!predicate(last.value, array[i])) {&lt;br /&gt;            if (stack.length) {&lt;br /&gt;                last = stack.pop();&lt;br /&gt;            } else {&lt;br /&gt;                last = null;&lt;br /&gt;                break;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        if (last) {&lt;br /&gt;            last.right = {"value": array[i], "left": last.right, "right": null};&lt;br /&gt;            stack.push(last);&lt;br /&gt;            last = last.right;&lt;br /&gt;        } else {&lt;br /&gt;            root = {"value": array[i], "left": root, "right": null};&lt;br /&gt;            last = root;&lt;br /&gt;            stack.push(last);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    var swapChildren = function(node) {&lt;br /&gt;        var temp = node.left;&lt;br /&gt;        node.left = node.right;&lt;br /&gt;        node.right = temp;&lt;br /&gt;    };      &lt;br /&gt;                &lt;br /&gt;    var merge = function(left, right) {&lt;br /&gt;        if (!left) {&lt;br /&gt;            return right;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        if (!right) {&lt;br /&gt;            return left;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        if (predicate(left.value, right.value)) {&lt;br /&gt;            var insert = right;&lt;br /&gt;            var next = left;&lt;br /&gt;        } else {&lt;br /&gt;            var insert = left;&lt;br /&gt;            var next = right;&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        swapChildren(next);&lt;br /&gt;        next.right = merge(insert, next.right);&lt;br /&gt;        return next;&lt;br /&gt;    };&lt;br /&gt;&lt;br /&gt;    i = 0;&lt;br /&gt;    while (root) {&lt;br /&gt;        array[i] = root.value;&lt;br /&gt;        i++;       &lt;br /&gt;        root = merge(root.left, root.right);&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;script type="text/javascript" src="http://gradient.info/blog/canvas.js"&gt;&lt;/script&gt;&lt;script type="text/javascript" src="http://gradient.info/blog/cartesian_tree_merge.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-3410415845895429221?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/3410415845895429221/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=3410415845895429221' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/3410415845895429221'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/3410415845895429221'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2010/07/beating-quick-sort-cartesian-tree-merge.html' title='Beating Quick Sort - Cartesian Tree Merge'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-7789247187825227198</id><published>2010-06-28T11:36:00.000-07:00</published><updated>2010-06-28T11:37:52.050-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='html5'/><category scheme='http://www.blogger.com/atom/ns#' term='canvas'/><category scheme='http://www.blogger.com/atom/ns#' term='sort'/><title type='text'>Cartesian Tree Sort - Skew Heap</title><content type='html'>&lt;p&gt;Since any heap tree, including Cartesian trees, degrade into sorted linked list when they are fully unbalanced it makes sense to try and unbalance the Cartesian tree.  It turns out that a &lt;a href="http://en.wikipedia.org/wiki/Skew_heap"&gt;Skew heap&lt;/a&gt; works great for this.  The following Cartesian skew tree now approaches the speed of quick sort (number of compares) for random data while maintaining linear time for nearly sorted data.&lt;/p&gt;I added a quick sort for comparison.&lt;br /&gt;&lt;div id="cartesianTreeSkewSort"&gt;&lt;img src="http://gradient.info/blog/img/cartesian_tree_skew.png"/&gt;&lt;/div&gt;&lt;br style="clear:both"/&gt;&lt;br /&gt;&lt;div id="cartesianTreeSkewSortB"&gt;&lt;/div&gt;&lt;br style="clear:both"/&gt;&lt;br /&gt;&lt;pre class="brush: jscript"&gt;algorithms.sort.cartesian_tree_skew = function(array, predicate, profile) {&lt;br /&gt;    var swapChildren = function(node) {&lt;br /&gt;        var temp = node.left;&lt;br /&gt;        node.left = node.right;&lt;br /&gt;        node.right = temp;&lt;br /&gt;    };&lt;br /&gt;    &lt;br /&gt;    var length = array.length;&lt;br /&gt;    if (length &lt;= 1) return;&lt;br /&gt;    &lt;br /&gt;    // parent could be removed with the use of a stack&lt;br /&gt;    var root = {"parent": null, "value": array[0], "left": null, "right": null};&lt;br /&gt;    var last = root;&lt;br /&gt;    for (var i = 1; i &lt; length; i++) {&lt;br /&gt;        while(last &amp;&amp; !predicate(last.value, array[i])) {&lt;br /&gt;            last = last.parent;&lt;br /&gt;        }&lt;br /&gt;        if (last) {&lt;br /&gt;            last.right = {"parent": last, "value": array[i], "left": last.right, "right": null};&lt;br /&gt;            last = last.right;&lt;br /&gt;        } else {&lt;br /&gt;            root = {"parent": null, "value": array[i], "left": root, "right": null};&lt;br /&gt;            last = root;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    i = 0;&lt;br /&gt;    while (root) {&lt;br /&gt;        array[i] = root.value;&lt;br /&gt;        i++;&lt;br /&gt;&lt;br /&gt;        if (!root.left) {&lt;br /&gt;            root = root.right;&lt;br /&gt;            continue;&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        if (!root.right) {&lt;br /&gt;            root = root.left;&lt;br /&gt;            continue;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        if (predicate(root.left.value, root.right.value)) {&lt;br /&gt;            var insert = root.right;&lt;br /&gt;            root = root.left;&lt;br /&gt;        } else {&lt;br /&gt;            var insert = root.left;&lt;br /&gt;            root = root.right;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        var next = root;&lt;br /&gt;        do {&lt;br /&gt;            if (!next.right) {&lt;br /&gt;                next.right = insert;&lt;br /&gt;                break;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            if (predicate(next.right.value, insert.value)) {&lt;br /&gt;                next = next.right;&lt;br /&gt;            } else {&lt;br /&gt;                var temp = next.right;&lt;br /&gt;                next.right = insert;&lt;br /&gt;                swapChildren(insert);&lt;br /&gt;                insert = temp;&lt;br /&gt;            }&lt;br /&gt;        } while (true);&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;script type="text/javascript" src="http://gradient.info/blog/canvas.js"&gt;&lt;/script&gt;&lt;script type="text/javascript" src="http://gradient.info/blog/cartesian_tree_skew.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-7789247187825227198?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/7789247187825227198/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=7789247187825227198' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/7789247187825227198'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/7789247187825227198'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2010/06/cartesian-tree-sort-skew-heap.html' title='Cartesian Tree Sort - Skew Heap'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-4565833592719009424</id><published>2010-06-25T11:09:00.000-07:00</published><updated>2010-06-25T11:16:51.765-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='html5'/><category scheme='http://www.blogger.com/atom/ns#' term='canvas'/><category scheme='http://www.blogger.com/atom/ns#' term='sort'/><title type='text'>Cartesian Tree Sort - Revisited</title><content type='html'>&lt;p&gt;Thinking about Cartesian tree sort some more it seems logical to also use the Cartesian tree as the priority queue since it is already a heap.  Performance appears to be the same without the extra memory requirement of an external priority queue.&lt;/p&gt;&lt;div id="cartesianTreeErikSort"&gt;&lt;img src="http://gradient.info/blog/img/cartesian_tree_erik.png"/&gt;&lt;/div&gt;&lt;div id="cartesianTreeErikSortB"&gt;&lt;/div&gt;&lt;br style="clear:both"/&gt;&lt;br /&gt;&lt;pre class="brush: jscript"&gt;algorithms.sort.cartesian_tree_erik = function(array, predicate) {&lt;br /&gt;    var length = array.length;&lt;br /&gt;    if (length &lt;= 1) return;&lt;br /&gt;            &lt;br /&gt;    var root = {"parent": null, "value": array[0], "left": null, "right": null};&lt;br /&gt;    var last = root;&lt;br /&gt;    for (var i = 1; i &lt; length; i++) {&lt;br /&gt;        while(last &amp;&amp; predicate(last.value, array[i])) {&lt;br /&gt;            last = last.parent;&lt;br /&gt;        }&lt;br /&gt;        if (last) {&lt;br /&gt;            last.right = {"parent": last, "value": array[i], "left": last.right, "right": null};&lt;br /&gt;            last = last.right;&lt;br /&gt;        } else {&lt;br /&gt;            root = {"parent": null, "value": array[i], "left": root, "right": null};&lt;br /&gt;            last = root;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;            &lt;br /&gt;    var i = 0;&lt;br /&gt;    while (root) {&lt;br /&gt;        array[i] = root.value;&lt;br /&gt;        i++;&lt;br /&gt;&lt;br /&gt;        if (!root.left) {&lt;br /&gt;            root = root.right;&lt;br /&gt;            continue;&lt;br /&gt;        }&lt;br /&gt;                &lt;br /&gt;        if (!root.right) {&lt;br /&gt;            root = root.left;&lt;br /&gt;            continue;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        if (predicate(root.left.value, root.right.value)) {&lt;br /&gt;            var insert = root.left;&lt;br /&gt;            root = root.right;&lt;br /&gt;        } else {&lt;br /&gt;            var insert = root.right;&lt;br /&gt;            root = root.left;&lt;br /&gt;        }&lt;br /&gt;                &lt;br /&gt;        var next = root;&lt;br /&gt;        do {&lt;br /&gt;            if (!next.left) {&lt;br /&gt;                next.left = insert;&lt;br /&gt;                break;&lt;br /&gt;            }&lt;br /&gt;                    &lt;br /&gt;            if (!next.right) {&lt;br /&gt;                next.right = insert;&lt;br /&gt;                break;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            if (predicate(next.left.value, next.right.value)) {&lt;br /&gt;                if (predicate(next.left.value, insert.value)) {&lt;br /&gt;                    var temp = next.left;&lt;br /&gt;                    next.left = insert;&lt;br /&gt;                    insert = temp;&lt;br /&gt;                } else {&lt;br /&gt;                    next = next.left;&lt;br /&gt;                }&lt;br /&gt;            } else {&lt;br /&gt;                if (predicate(next.right.value, insert.value)) {&lt;br /&gt;                    var temp = next.right;&lt;br /&gt;                    next.right = insert;&lt;br /&gt;                    insert = temp;&lt;br /&gt;                } else {&lt;br /&gt;                    next = next.right;&lt;br /&gt;                }      &lt;br /&gt;            }&lt;br /&gt;        } while (true);&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;script type="text/javascript" src="http://gradient.info/blog/canvas.js"&gt;&lt;/script&gt;&lt;script type="text/javascript" src="http://gradient.info/blog/cartesian_tree_erik.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-4565833592719009424?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/4565833592719009424/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=4565833592719009424' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/4565833592719009424'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/4565833592719009424'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2010/06/cartesian-tree-sort-revisited.html' title='Cartesian Tree Sort - Revisited'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-565864948443435118</id><published>2010-06-24T20:55:00.000-07:00</published><updated>2010-06-24T21:16:38.468-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='html5'/><category scheme='http://www.blogger.com/atom/ns#' term='canvas'/><category scheme='http://www.blogger.com/atom/ns#' term='sort'/><title type='text'>Cartesian Tree Sort</title><content type='html'>&lt;p&gt;Cartesian tree sort solves heap sort's problem of not taking advantage of partially sorted data by building a Cartesian tree.  This tree is then traversed pre-prder inserting nodes into a priority queue.  The nodes are removed from the priority queue as they are being inserted.  Since the Cartesian tree is also a heap, nodes are not removed out of order.  In the case of partially sorted data, the Cartesian tree degrades into an unbalanced tree resembling a linked list.  Since there is only one element per row, the priority queue pushes and pops the same element without doing any comparisons.&lt;/p&gt;&lt;p&gt;This has &amp;#952;(n log n) worse case running time and &amp;#952;(n) running time for sorted data. Cartesian tree sort does require extra space for the tree and priority queue. Wikipedia on &lt;a href="http://en.wikipedia.org/wiki/Cartesian_tree#Application_in_sorting"&gt;Cartesian tree sort&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;This flattened Cartesian tree graph has a x-axis of the element index and a y-axis of the nodes depth. The root is the topmost dot.  Cartesian trees can be built in linear time and will return the original data in order if the tree is traversed &lt;a href="http://en.wikipedia.org/wiki/In-order_traversal"&gt;in-order&lt;/a&gt;.&lt;/p&gt;&lt;div id="cartesianTreeSort"&gt;&lt;img src="http://gradient.info/blog/img/cartesian_tree.png"/&gt;&lt;/div&gt;&lt;br style="clear:both"/&gt;&lt;br /&gt;&lt;pre class="brush: jscript"&gt;algorithms.sort.cartesian_tree = function(array, predicate) {&lt;br /&gt;    var queue = algorithms.queue.priority(function(a, b) {&lt;br /&gt;        return predicate(a.value, b.value);&lt;br /&gt;    });&lt;br /&gt;    &lt;br /&gt;    var length = array.length;&lt;br /&gt;    if (length &lt;= 1) return;&lt;br /&gt;    &lt;br /&gt;    var root = {"parent": null, "value": array[0], "left": null, "right": null};&lt;br /&gt;    var last = root;&lt;br /&gt;    &lt;br /&gt;    for (var i = 1; i &lt; length; i++) {&lt;br /&gt;        while(last &amp;&amp; predicate(last.value, array[i])) {&lt;br /&gt;            last = last.parent;&lt;br /&gt;        }&lt;br /&gt;        if (last) {&lt;br /&gt;            last.right = {"parent": last, "value": array[i], "left": last.right, "right": null};&lt;br /&gt;            last = last.right;&lt;br /&gt;        } else {&lt;br /&gt;            root = {"parent": null, "value": array[i], "left": root, "right": null};&lt;br /&gt;            last = root;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    queue.add(root);&lt;br /&gt;    array = [];&lt;br /&gt;    while(!queue.empty()) {&lt;br /&gt;        var node = queue.remove();&lt;br /&gt;        &lt;br /&gt;        array.push(node.value);&lt;br /&gt;        &lt;br /&gt;        if (node.left) {&lt;br /&gt;            queue.add(node.left);&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        if (node.right) {&lt;br /&gt;            queue.add(node.right);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;script type="text/javascript" src="http://gradient.info/blog/canvas.js"&gt;&lt;/script&gt;&lt;script type="text/javascript" src="http://gradient.info/blog/cartesian_tree.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-565864948443435118?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/565864948443435118/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=565864948443435118' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/565864948443435118'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/565864948443435118'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2010/06/cartesian-tree-sort.html' title='Cartesian Tree Sort'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-8608590104405828075</id><published>2010-06-21T16:47:00.000-07:00</published><updated>2010-06-21T16:47:14.211-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='html5'/><category scheme='http://www.blogger.com/atom/ns#' term='canvas'/><category scheme='http://www.blogger.com/atom/ns#' term='sort'/><title type='text'>Insertion Sort</title><content type='html'>&lt;p&gt;Insertion sort works by iterating over a list once starting from the left.  It looks at each element and the previous element swapping them if they are out of order and it keeps swapping the same element, moving it left, until the comparison is correct or it is in the first position. &lt;a href="http://en.wikipedia.org/wiki/Insertion_sort"&gt;Wikipedia on Insertion sort&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;An interesting thing about insertion sort is that it often runs faster than many &amp;#952;(n log n) algorithms for small datasets, 8-20 elements, even though its worse case runtime is &amp;#952;(n^2).&lt;/p&gt;&lt;div id="insertionSort"&gt;&lt;img src="http://gradient.info/blog/img/insertion.png"/&gt;&lt;/div&gt;&lt;br style="clear:both"/&gt;&lt;br /&gt;&lt;pre class="brush: jscript"&gt;algorithms.sort.insertion = function(array, predicate){&lt;br /&gt;    var length = array.length;&lt;br /&gt;    for (var start = 1; start &lt; length; start++) {&lt;br /&gt;        var i = start;&lt;br /&gt;        do {&lt;br /&gt;            if (predicate(array, i, i - 1)) {&lt;br /&gt;                array.swap(i, i - 1);&lt;br /&gt;            } else {&lt;br /&gt;                break;&lt;br /&gt;            }&lt;br /&gt;            i--;&lt;br /&gt;        } while (i);&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;script type="text/javascript" src="http://gradient.info/blog/canvas.js"&gt;&lt;/script&gt;&lt;script type="text/javascript" src="http://gradient.info/blog/insertion.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-8608590104405828075?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/8608590104405828075/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=8608590104405828075' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/8608590104405828075'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/8608590104405828075'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2010/06/insertion-sort.html' title='Insertion Sort'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-1529942061431178269</id><published>2010-06-10T22:34:00.000-07:00</published><updated>2010-06-10T22:43:14.004-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='html5'/><category scheme='http://www.blogger.com/atom/ns#' term='canvas'/><category scheme='http://www.blogger.com/atom/ns#' term='sort'/><title type='text'>Priority Queue &amp; Heap Sort</title><content type='html'>&lt;p&gt;A heap implementation of &lt;a href="http://en.wikipedia.org/wiki/Priority_queue"&gt;priority queue&lt;/a&gt; is very similar to heap sort and can easily be turned into one.  The difference implementation wise is that the queue doesn't know the final heap size so it has to build the heap from the ground up.  This requires finding parent nodes in the heap and not just child nodes.  Performance is nearly identical except the queue requires extra N space. Both of these heap implementations don't take advantage of partially sorted list.&lt;/p&gt;&lt;div id="heap_prioritySort"&gt;&lt;img src="http://gradient.info/blog/img/heap_priority.png"/&gt;&lt;/div&gt;&lt;br style="clear:both"/&gt;&lt;br /&gt;&lt;pre class="brush: jscript"&gt;algorithms.queue.priority = function(predicate) {&lt;br /&gt;    var siftDown = function(array, start, end) {&lt;br /&gt;        var root = start;&lt;br /&gt;        while (root * 2 + 1 &lt;= end) {&lt;br /&gt;            var child = root * 2 + 1;&lt;br /&gt;            if (child &lt; end &amp;&amp; predicate(array, child, child + 1)) {&lt;br /&gt;                child++;&lt;br /&gt;            }&lt;br /&gt;            if (predicate(array, root, child)) {&lt;br /&gt;                array.swap(root, child);&lt;br /&gt;                root = child;&lt;br /&gt;            } else {&lt;br /&gt;                return;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    };&lt;br /&gt;    var siftUp = function(array, start, end) {&lt;br /&gt;        var child = end;&lt;br /&gt;        while (child &gt; start) {&lt;br /&gt;            var parent = Math.floor((child - 1) / 2);&lt;br /&gt;            if (predicate(array, parent, child)) {&lt;br /&gt;                array.swap(parent, child);&lt;br /&gt;                child = parent;&lt;br /&gt;            } else {&lt;br /&gt;                return;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    };&lt;br /&gt;    var that = {&lt;br /&gt;        heap: [],&lt;br /&gt;        add: function(value) {&lt;br /&gt;            that.heap.push(value);&lt;br /&gt;            siftUp(that.heap, 0, that.heap.length - 1);&lt;br /&gt;        },&lt;br /&gt;        remove: function() {&lt;br /&gt;            that.heap.swap(0, that.heap.length - 1);&lt;br /&gt;            siftDown(that.heap, 0, that.heap.length - 2);&lt;br /&gt;            return that.heap.pop();&lt;br /&gt;        }&lt;br /&gt;    };&lt;br /&gt;    return that;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;algorithms.sort.heap_priority = function(array, predicate) {&lt;br /&gt;    var queue = algorithms.queue.priority(predicate);&lt;br /&gt;    var length = array.length;&lt;br /&gt;&lt;br /&gt;    // turn list into a heap&lt;br /&gt;    for (var i = 0; i &lt; length; i++) {&lt;br /&gt;        queue.add(array[i]);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // remove max value and restore heap property  &lt;br /&gt;    for (var i = 0; i &lt; length; i++) {&lt;br /&gt;        array[i] = queue.remove();&lt;br /&gt;    }   &lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;script type="text/javascript" src="http://gradient.info/blog/canvas.js"&gt;&lt;/script&gt;&lt;script type="text/javascript" src="http://gradient.info/blog/heap_priority.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-1529942061431178269?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/1529942061431178269/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=1529942061431178269' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/1529942061431178269'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/1529942061431178269'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2010/06/priority-queue-heap-sort.html' title='Priority Queue &amp; Heap Sort'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-589747486223861883</id><published>2010-06-09T17:36:00.000-07:00</published><updated>2010-06-10T23:08:37.208-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='html5'/><category scheme='http://www.blogger.com/atom/ns#' term='canvas'/><category scheme='http://www.blogger.com/atom/ns#' term='sort'/><title type='text'>Heap Sort</title><content type='html'>&lt;p&gt;Heap sort is similar to selection sort but instead of scanning the entire list for the minimal value it uses a heap to select the minimal value.  There is an added step of rebuilding the heap every time the minimal value is removed.  Heap sort's worst-case runtime is &amp;#952;(n log n).  In this implementation I use a max heap. &lt;a href="http://en.wikipedia.org/wiki/Heapsort"&gt;Wikipedia on Heap sort&lt;/a&gt;.&lt;/p&gt;&lt;div id="heapSort"&gt;&lt;img src="http://gradient.info/blog/img/heap.png"/&gt;&lt;/div&gt;&lt;br style="clear:both"/&gt;&lt;br /&gt;&lt;pre class="brush: jscript"&gt;algorithms.sort.heap = function(array, predicate) {&lt;br /&gt;    var siftDown = function(start, end) {&lt;br /&gt;        var root = start;&lt;br /&gt;        while (root * 2 + 1 &lt;= end) {&lt;br /&gt;            var child = root * 2 + 1;&lt;br /&gt;            if (child &lt; end &amp;&amp; predicate(array, child, child + 1)) {&lt;br /&gt;                child++;&lt;br /&gt;            }&lt;br /&gt;            if (predicate(array, root, child)) {&lt;br /&gt;                array.swap(root, child);&lt;br /&gt;                root = child;&lt;br /&gt;            } else {&lt;br /&gt;                return;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    };&lt;br /&gt;    &lt;br /&gt;    var length = array.length;&lt;br /&gt;    &lt;br /&gt;    // turn list into a heap&lt;br /&gt;    for (var start = Math.floor((length - 2) / 2); start &gt;= 0; start--) {&lt;br /&gt;        siftDown(start, length - 1);    &lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    // remove max value and restore heap property    &lt;br /&gt;    for (var end = length - 1; end &gt; 0; end--) {&lt;br /&gt;        array.swap(end, 0);  &lt;br /&gt;        siftDown(0, end - 1);    &lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;script type="text/javascript" src="http://gradient.info/blog/canvas.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;script type="text/javascript" src="http://gradient.info/blog/heap.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-589747486223861883?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/589747486223861883/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=589747486223861883' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/589747486223861883'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/589747486223861883'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2010/06/heap-sort.html' title='Heap Sort'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-6084253304247658172</id><published>2010-06-08T18:04:00.000-07:00</published><updated>2010-06-08T18:05:22.754-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='html5'/><category scheme='http://www.blogger.com/atom/ns#' term='canvas'/><category scheme='http://www.blogger.com/atom/ns#' term='sort'/><title type='text'>Selection Sort</title><content type='html'>&lt;p&gt;The next set of sorts are based on selection sort.  Selection sort works by finding the minimal value in a list and swapping it with the first position.  This is repeated with the remainder of the list swapping the next minimal value with the second position and so forth until the list is sorted. &lt;a href="http://en.wikipedia.org/wiki/Selection_sort"&gt;Wikipedia on Selection sort&lt;/a&gt;.&lt;/p&gt;&lt;div id="selectionSort"&gt;&lt;img src="http://gradient.info/blog/img/selection.png"/&gt;&lt;/div&gt;&lt;br style="clear:both"/&gt;&lt;br /&gt;&lt;pre class="brush: jscript"&gt;algorithms.sort.selection = function(array, predicate) {&lt;br /&gt;    var length = array.length;&lt;br /&gt;    for (var start = 0; start &lt; length; start++) {&lt;br /&gt;        var min = start;&lt;br /&gt;        for (var i = start; i &lt; length; i++) {&lt;br /&gt;            if (predicate(array, i, min)) {&lt;br /&gt;                min = i;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        array.swap(start, min);  &lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;script type="text/javascript" src="http://gradient.info/blog/canvas.js"&gt;&lt;/script&gt;&lt;script type="text/javascript" src="http://gradient.info/blog/selection.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-6084253304247658172?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/6084253304247658172/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=6084253304247658172' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/6084253304247658172'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/6084253304247658172'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2010/06/selection-sort.html' title='Selection Sort'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-4402101452862652423</id><published>2010-06-04T17:04:00.000-07:00</published><updated>2010-06-04T17:22:54.172-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='html5'/><category scheme='http://www.blogger.com/atom/ns#' term='canvas'/><category scheme='http://www.blogger.com/atom/ns#' term='sort'/><title type='text'>Quick Sort</title><content type='html'>&lt;p&gt;Quick sort is a classic divide and conquer algorithm.  It works by picking a pivot element and dividing the list into two sub list based on if the elements are less than or grater than the pivot element. This is repeated with new pivots in the smaller lists until the list size equals one.&lt;/p&gt;&lt;p&gt;Implementing this algorithm in place is interesting since you don't know how many elements are going to go on each side of the pivot.  To get around this you can swap the pivot element with the last element in the list.  Then you iterate over the list moving all the elements less than the pivot before all the elements greater than the pivot.   Once this is done you swap the last element again, which is the pivot, with the first element after all the elements less than the pivot.  This puts the pivot in the middle and the first element that is greater than the pivot in the last position.  The pivot is now in the correct position with all the elements less than it to the left and all the elements greater than it to the right.   &lt;a href="http://en.wikipedia.org/wiki/Quicksort"&gt;Wikipedia on Quick sort&lt;/a&gt;.&lt;/p&gt;&lt;div id="quickSort"&gt;&lt;img src="http://gradient.info/blog/img/quick.png"/&gt;&lt;/div&gt;&lt;br style="clear:both"/&gt;&lt;br /&gt;&lt;pre class="brush: jscript"&gt;algorithms.sort.quick = function(array, predicate) {&lt;br /&gt;    var quick = function(left, right) {&lt;br /&gt;        if (right &gt;= left) {&lt;br /&gt;            var pivot = Math.floor((right + left) / 2);&lt;br /&gt;            var store = left;&lt;br /&gt;            array.swap(right, pivot);&lt;br /&gt;            // right is now the pivot&lt;br /&gt;            for (var i = left; i &lt;= right; i++) {&lt;br /&gt;                if (predicate(array, i, right)) {&lt;br /&gt;                    array.swap(i, store);&lt;br /&gt;                    store++;&lt;br /&gt;                } &lt;br /&gt;            }&lt;br /&gt;            array.swap(right, store);&lt;br /&gt;            // right is no longer the pivot&lt;br /&gt;            quick(left, store - 1);&lt;br /&gt;            quick(store + 1, right);&lt;br /&gt;        }&lt;br /&gt;    };&lt;br /&gt;    quick(0, array.length - 1);&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;script type="text/javascript" src="http://gradient.info/blog/canvas.js"&gt;&lt;/script&gt;&lt;script type="text/javascript" src="http://gradient.info/blog/quick.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-4402101452862652423?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/4402101452862652423/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=4402101452862652423' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/4402101452862652423'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/4402101452862652423'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2010/06/quick-sort.html' title='Quick Sort'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-7465169084480977176</id><published>2010-06-03T19:44:00.000-07:00</published><updated>2010-06-03T19:45:28.322-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='html5'/><category scheme='http://www.blogger.com/atom/ns#' term='canvas'/><category scheme='http://www.blogger.com/atom/ns#' term='sort'/><title type='text'>Gnome Sort</title><content type='html'>&lt;p&gt;Gnome sort works by stepping forward in the list if two elements are in order.  If they are out of order it swaps them and steps back.  This behavior emulates insertion sort but with many swaps. &lt;a href="http://en.wikipedia.org/wiki/Gnome_sort"&gt;Wikipedia on Gnome sort&lt;/a&gt;.&lt;/p&gt;&lt;div id="gnomeSort"&gt;&lt;img src="http://gradient.info/blog/img/gnome.png"/&gt;&lt;/div&gt;&lt;br style="clear:both"/&gt;&lt;br /&gt;&lt;pre class="brush: jscript"&gt;algorithms.sort.gnome = function(array, predicate){&lt;br /&gt;    var i = 0;&lt;br /&gt;    var length = array.length;&lt;br /&gt;    while (i &lt; length - 1) {&lt;br /&gt;        if (!predicate(array, i, i + 1)) {&lt;br /&gt;            array.swap(i, i + 1);&lt;br /&gt;            if (i &gt; 0) {&lt;br /&gt;                i--;&lt;br /&gt;            }&lt;br /&gt;        } else {&lt;br /&gt;            i++;&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;script type="text/javascript" src="http://gradient.info/blog/canvas.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;script type="text/javascript" src="http://gradient.info/blog/gnome.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-7465169084480977176?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/7465169084480977176/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=7465169084480977176' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/7465169084480977176'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/7465169084480977176'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2010/06/gnome-sort.html' title='Gnome Sort'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-8581211253502058748</id><published>2010-06-02T19:35:00.000-07:00</published><updated>2010-06-02T19:40:26.501-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='html5'/><category scheme='http://www.blogger.com/atom/ns#' term='canvas'/><category scheme='http://www.blogger.com/atom/ns#' term='sort'/><title type='text'>Comb Sort</title><content type='html'>&lt;p&gt;Comb sort tries to overcome bubble sorts problems by comparing values far away from one another at first and then slowly reducing the gap until it's comparing adjacent values.&lt;br /&gt; &lt;a href="http://en.wikipedia.org/wiki/Comb_sort"&gt;Wikipedia on Comb sort&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;div id="combSort"&gt;&lt;br /&gt;&lt;img src="http://gradient.info/blog/img/comb.png"/&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br style="clear:both"/&gt;&lt;br /&gt;&lt;pre class="brush: jscript"&gt;&lt;br /&gt;algorithms.sort.comb = function(array, predicate){&lt;br /&gt;    var found = true;&lt;br /&gt;    var length = array.length;&lt;br /&gt;    var shrink_factor = 1.247330950103979;&lt;br /&gt;    var gap = length;&lt;br /&gt;    while (found || gap &gt; 1) {&lt;br /&gt;        found = false;&lt;br /&gt;        &lt;br /&gt;        gap = gap / shrink_factor;     &lt;br /&gt;        if (gap &lt; 1) {&lt;br /&gt;            gap = 1;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        var i_gap = Math.ceil(gap);     &lt;br /&gt;        for (var i = 0; i &lt; length - i_gap; i++) {&lt;br /&gt;            if (!predicate(array, i, i + i_gap)) {&lt;br /&gt;                array.swap(i, i + i_gap);&lt;br /&gt;                found = true;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;script type="text/javascript" src="http://gradient.info/blog/canvas.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;script type="text/javascript" src="http://gradient.info/blog/comb.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-8581211253502058748?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/8581211253502058748/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=8581211253502058748' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/8581211253502058748'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/8581211253502058748'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2010/06/comb-sort.html' title='Comb Sort'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-1815111227207389940</id><published>2010-06-01T20:23:00.000-07:00</published><updated>2010-06-01T20:32:55.046-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='html5'/><category scheme='http://www.blogger.com/atom/ns#' term='canvas'/><category scheme='http://www.blogger.com/atom/ns#' term='sort'/><title type='text'>Odd-even Sort</title><content type='html'>&lt;p&gt;Odd-even sort is another bubble sort variant and is similar to cocktail sort since it makes alternating passes. Instead of changing directions like cocktail, it tests all the even elements in one pass and then all the odd elements in the next. &lt;a href="http://en.wikipedia.org/wiki/Odd-even_sort"&gt;Wikipedia on Odd-even sort&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;div id="odd_evenSort"&gt;&lt;br /&gt;&lt;img src="http://gradient.info/blog/img/odd_even.png"/&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br style="clear:both"/&gt;&lt;br /&gt;&lt;pre class="brush: jscript"&gt;&lt;br /&gt;algorithms.sort.odd_even = function(array, predicate){&lt;br /&gt;    var found = true;&lt;br /&gt;    var length = array.length;&lt;br /&gt;    while (found) {&lt;br /&gt;        found = false;&lt;br /&gt;        for (var i = 0; i &lt; length - 1; i += 2) {&lt;br /&gt;            if (!predicate(array, i, i + 1)) {&lt;br /&gt;                array.swap(i, i + 1);&lt;br /&gt;                found = true;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        if (!found)&lt;br /&gt;            break;&lt;br /&gt;            &lt;br /&gt;        for (var i = 1; i &lt; length - 1; i += 2) {&lt;br /&gt;            if (!predicate(array, i, i + 1)) {&lt;br /&gt;                array.swap(i, i + 1);&lt;br /&gt;                found = true;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;script type="text/javascript" src="http://gradient.info/blog/canvas.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;script type="text/javascript" src="http://gradient.info/blog/odd_even.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-1815111227207389940?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/1815111227207389940/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=1815111227207389940' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/1815111227207389940'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/1815111227207389940'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2010/06/odd-even-sort.html' title='Odd-even Sort'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-2071895509476686903</id><published>2010-05-31T13:27:00.000-07:00</published><updated>2010-05-31T13:37:13.252-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='html5'/><category scheme='http://www.blogger.com/atom/ns#' term='canvas'/><category scheme='http://www.blogger.com/atom/ns#' term='sort'/><title type='text'>Cocktail Sort</title><content type='html'>&lt;p&gt;Cocktail sort is similar to bubble sort except it reverses directions when it reaches the end of the list instead of starting from the beginning. &lt;a href="http://en.wikipedia.org/wiki/Cocktail_sort"&gt;Wikipedia on cocktail sort&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;div id="cocktailSort"&gt;&lt;br /&gt;&lt;img src="http://gradient.info/blog/img/cocktail.png"/&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br style="clear:both"/&gt;&lt;br /&gt;&lt;pre class="brush: jscript"&gt;&lt;br /&gt;algorithms.sort.cocktail = function(array, predicate){&lt;br /&gt;    var found = true;&lt;br /&gt;    var length = array.length;&lt;br /&gt;    while (found) {&lt;br /&gt;        found = false;&lt;br /&gt;        for (var i = 0; i &lt; length - 1; i++) {&lt;br /&gt;            if (!predicate(array, i, i + 1)) {&lt;br /&gt;                array.swap(i, i + 1);&lt;br /&gt;                found = true;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        if (!found)&lt;br /&gt;            break;&lt;br /&gt;            &lt;br /&gt;        for (var i = length - 1; i &gt; 1; i--) {&lt;br /&gt;            if (predicate(array, i, i - 1)) {&lt;br /&gt;                array.swap(i, i - 1);&lt;br /&gt;                found = true;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;script type="text/javascript" src="http://gradient.info/blog/canvas.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;script type="text/javascript" src="http://gradient.info/blog/cocktail.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-2071895509476686903?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/2071895509476686903/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=2071895509476686903' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/2071895509476686903'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/2071895509476686903'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2010/05/cocktail-sort.html' title='Cocktail Sort'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-4026436444240259998</id><published>2010-05-31T10:53:00.000-07:00</published><updated>2010-05-31T14:03:18.169-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='html5'/><category scheme='http://www.blogger.com/atom/ns#' term='canvas'/><category scheme='http://www.blogger.com/atom/ns#' term='sort'/><title type='text'>Bubble Sort</title><content type='html'>&lt;p&gt;Inspired be Wikipedia's algorithm pages I decided to recreate their animations using JavaSrcipt and HTML5 canvas elements.  IE 8 does not support canvas however new versions of all other modern browsers do.  Mozilla Firefox, Google Chrome, Safari, and Opera.&lt;/p&gt;&lt;p&gt;Bubble sort works by looking at ever element in a list that is to be sorted and swapping adjacent pairs that are out of order.  If it makes it to the end of the list without swapping any elements then it stops and the list is in order.  If not then it starts at the beginning again. &lt;a href="http://en.wikipedia.org/wiki/Bubble_sort"&gt;Wikipedia on Bubble Sort&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;div id="bubbleSort"&gt;&lt;br /&gt;&lt;img src="http://gradient.info/blog/img/bubble.png"/&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br style="clear:both"/&gt;&lt;br /&gt;&lt;pre class="brush: jscript"&gt;&lt;br /&gt;algorithms.sort.bubble = function(array, predicate){&lt;br /&gt;    var found = true;&lt;br /&gt;    var length = array.length;&lt;br /&gt;    while (found) {&lt;br /&gt;        found = false;&lt;br /&gt;        for (var i = 0; i &lt; length - 1; i++) {&lt;br /&gt;            if (!predicate(array, i, i + 1)) {&lt;br /&gt;                array.swap(i, i + 1);&lt;br /&gt;                found = true;&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;script type="text/javascript" src="http://gradient.info/blog/canvas.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;script type="text/javascript" src="http://gradient.info/blog/bubble.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-4026436444240259998?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/4026436444240259998/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=4026436444240259998' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/4026436444240259998'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/4026436444240259998'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2010/05/bubble-sort.html' title='Bubble Sort'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-7317970734998527038</id><published>2010-03-14T12:11:00.000-07:00</published><updated>2010-03-14T12:23:12.705-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Pi'/><category scheme='http://www.blogger.com/atom/ns#' term='F#'/><category scheme='http://www.blogger.com/atom/ns#' term='Pi Day'/><title type='text'>Pi Day</title><content type='html'>&lt;p&gt;Having noticed it was Pi day before Google alerted me to the fact, I'm feeling pretty dorky.  Following some links I found the current &lt;a href="http://bellard.org/pi/pi2700e9/"&gt;record holder&lt;/a&gt; for the most digits of pi computed.  Seeing his algorithm is recursive I thought "Hey I could write that in F# with bigint."  So here I am on Pi day computing pi.&lt;/p&gt;&lt;p&gt;  There is no square root method built in so I had to make my own. It takes about 30s on my i7 to compute the first 100,000 digits.  I confirmed the results against the record holders data.&lt;/p&gt;&lt;pre&gt;105790 // digits computed&lt;br /&gt;"70150789337728658035712790913767420805655493624646" // digits 99951..100000&lt;/pre&gt;&lt;br /&gt;&lt;pre class="brush: fsharp"&gt;&lt;br /&gt;let A = 13591409I&lt;br /&gt;let B = 545140134I&lt;br /&gt;let C = 640320I&lt;br /&gt;&lt;br /&gt;let a n = if n % 2I = 0I then (A + B * n) else -(A + B * n)&lt;br /&gt;let p n = (2I*n - 1I) * (6I*n - 5I) * (6I*n - 1I)&lt;br /&gt;let q n = n*n*n * C*C*C / 24I&lt;br /&gt;&lt;br /&gt;let div2floor x =&lt;br /&gt;    if x % 2I = 0I then&lt;br /&gt;        x / 2I&lt;br /&gt;    else&lt;br /&gt;        (x - 1I) / 2I&lt;br /&gt;&lt;br /&gt;let rec pqt n1 n2 =&lt;br /&gt;    if n1 + 1I = n2 then&lt;br /&gt;        (p n2, q n2, (a n2) * (p n2))&lt;br /&gt;    else&lt;br /&gt;        let m = div2floor (n1 + n2)&lt;br /&gt;        let P1, Q1, T1 = pqt n1 m&lt;br /&gt;        let P2, Q2, T2 = pqt m n2&lt;br /&gt;        (P1*P2, Q1 * Q2, T1*Q2 + P1*T2)&lt;br /&gt;&lt;br /&gt;let sqrtC length =&lt;br /&gt;    let rec sqrt x y =&lt;br /&gt;        let e = y - x * x&lt;br /&gt;        let p = e / (2I * x)&lt;br /&gt;        if p = 0I then&lt;br /&gt;            x&lt;br /&gt;        else&lt;br /&gt;            sqrt (x + p) y&lt;br /&gt;    let guess = 800I * bigint.Pow(10I, length / 2)&lt;br /&gt;    let accuracy = bigint.Pow(10I, 2*(length / 2))&lt;br /&gt;    sqrt guess (C * accuracy)&lt;br /&gt;&lt;br /&gt;let pi n =&lt;br /&gt;    let p, q, t = pqt 0I n&lt;br /&gt;    let dividend = q&lt;br /&gt;    let divisor = 12I * (t + q * A)&lt;br /&gt;    &lt;br /&gt;    let sign =&lt;br /&gt;        if divisor &lt; 0I then&lt;br /&gt;            -divisor&lt;br /&gt;        else&lt;br /&gt;            divisor&lt;br /&gt;    let length = int (bigint.Log10(sign))&lt;br /&gt;&lt;br /&gt;    C * (sqrtC length) * dividend / divisor&lt;br /&gt;&lt;br /&gt;let test = string (pi 8000I)&lt;br /&gt;printfn "%A" test.Length&lt;br /&gt;printfn "%A" test.[99951..100000]&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-7317970734998527038?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/7317970734998527038/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=7317970734998527038' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/7317970734998527038'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/7317970734998527038'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2010/03/pi-day.html' title='Pi Day'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-3484037015574865636</id><published>2010-01-17T17:36:00.000-08:00</published><updated>2010-01-17T20:00:16.981-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MORGE'/><category scheme='http://www.blogger.com/atom/ns#' term='F#'/><title type='text'>Moving on with F# Development</title><content type='html'>&lt;p&gt;After a break from game development and finishing a work project in F#, I'm back and it's time for me to leave XNA behind and move on to a collection of specifically designed libraries. For my graphics engine I'm choosing ORGE by way of MORGE a .NET wrapper for it.&lt;/p&gt;&lt;p&gt;After digging into the C# SDK I figured a good start would be porting MorgeForm. To get this code to run install the SDK, create a project, set it to .NET 2.0, add a reference to Mogre_d (C:\MogreSDK\bin\Debug) and set the working directory to C:\MogreSDK\bin\Debug.  The sample pulls resources through relative paths so you need to run in the SDK Debug directory.&lt;/p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_9tQTRFC8wPE/S1O94__L18I/AAAAAAAAAX4/oNoHdysI5Pc/s1600-h/MogreForm.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 400px; height: 331px;" src="http://4.bp.blogspot.com/_9tQTRFC8wPE/S1O94__L18I/AAAAAAAAAX4/oNoHdysI5Pc/s400/MogreForm.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5427890762858354626" /&gt;&lt;/a&gt;&lt;p&gt;On a side note I need to make my own custom theme for better syntax highlighting.&lt;/p&gt;&lt;br /&gt;&lt;pre class="brush: fsharp"&gt;open System&lt;br /&gt;open System.Windows.Forms&lt;br /&gt;open System.Drawing&lt;br /&gt;&lt;br /&gt;open Mogre&lt;br /&gt;&lt;br /&gt;type OgreWindow(origin, hWnd) =&lt;br /&gt;    //----------------------------------------------------- &lt;br /&gt;    // 1 enter ogre &lt;br /&gt;    //----------------------------------------------------- &lt;br /&gt;    let root = new Root()&lt;br /&gt;&lt;br /&gt;    do  //----------------------------------------------------- &lt;br /&gt;        // 2 configure resource paths&lt;br /&gt;        //----------------------------------------------------- &lt;br /&gt;        let cf = new ConfigFile()&lt;br /&gt;        cf.Load("resources.cfg", "\t:=", true)&lt;br /&gt;&lt;br /&gt;        // Go through all sections &amp; settings in the file&lt;br /&gt;        let seci = cf.GetSectionIterator()&lt;br /&gt;&lt;br /&gt;        // Normally we would use the foreach syntax, which enumerates the values, but in this case we need CurrentKey too;&lt;br /&gt;        while seci.MoveNext() do&lt;br /&gt;            for pair in seci.Current do&lt;br /&gt;                ResourceGroupManager.Singleton.AddResourceLocation(pair.Value, pair.Key, seci.CurrentKey)&lt;br /&gt;&lt;br /&gt;        //----------------------------------------------------- &lt;br /&gt;        // 3 Configures the application and creates the window&lt;br /&gt;        //----------------------------------------------------- &lt;br /&gt;        root.RenderSystem &lt;- root.GetAvailableRenderers() |&gt; Seq.find (fun rs -&gt; rs.Name = "Direct3D9 Rendering Subsystem")&lt;br /&gt;        root.RenderSystem.SetConfigOption("Full Screen", "No")&lt;br /&gt;        root.RenderSystem.SetConfigOption("Video Mode", "640 x 480 @ 32-bit colour")&lt;br /&gt;&lt;br /&gt;        root.Initialise(false) |&gt; ignore&lt;br /&gt;        let misc = new NameValuePairList()&lt;br /&gt;        misc.["externalWindowHandle"] &lt;- hWnd.ToString()&lt;br /&gt;        let window = root.CreateRenderWindow("Simple Mogre Form Window", 0u, 0u, false, misc.ReadOnlyInstance)&lt;br /&gt;        ResourceGroupManager.Singleton.InitialiseAllResourceGroups()&lt;br /&gt;&lt;br /&gt;        //----------------------------------------------------- &lt;br /&gt;        // 4 Create the SceneManager&lt;br /&gt;        // &lt;br /&gt;        //  ST_GENERIC = octree&lt;br /&gt;        //  ST_EXTERIOR_CLOSE = simple terrain&lt;br /&gt;        //  ST_EXTERIOR_FAR = nature terrain (depreciated)&lt;br /&gt;        //  ST_EXTERIOR_REAL_FAR = paging landscape&lt;br /&gt;        //  ST_INTERIOR = Quake3 BSP&lt;br /&gt;        //----------------------------------------------------- &lt;br /&gt;        let sceneMgr = root.CreateSceneManager(SceneType.ST_GENERIC, "SceneMgr")&lt;br /&gt;        sceneMgr.AmbientLight &lt;- new ColourValue(0.5f, 0.5f, 0.5f)&lt;br /&gt;&lt;br /&gt;        //----------------------------------------------------- &lt;br /&gt;        // 5 Create the camera &lt;br /&gt;        //----------------------------------------------------- &lt;br /&gt;        let camera = sceneMgr.CreateCamera("SimpleCamera")&lt;br /&gt;        camera.Position &lt;- new Vector3(0.0f, 0.0f, 100.0f)&lt;br /&gt;        // Look back along -Z&lt;br /&gt;        camera.LookAt(new Vector3(0.0f, 0.0f, -300.0f))&lt;br /&gt;        camera.NearClipDistance &lt;- 5.0f&lt;br /&gt;&lt;br /&gt;        let viewport = window.AddViewport(camera)&lt;br /&gt;        viewport.BackgroundColour &lt;- new ColourValue(0.0f, 0.0f, 0.0f, 1.0f)&lt;br /&gt;&lt;br /&gt;        let ent = sceneMgr.CreateEntity("ogre", "ogrehead.mesh")&lt;br /&gt;        let node = sceneMgr.RootSceneNode.CreateChildSceneNode("ogreNode")&lt;br /&gt;        node.AttachObject(ent)&lt;br /&gt;&lt;br /&gt;    member this.Paint() =&lt;br /&gt;        root.RenderOneFrame() |&gt; ignore&lt;br /&gt;&lt;br /&gt;    member this.Dispose() =&lt;br /&gt;        if root &lt;&gt; null then&lt;br /&gt;            root.Dispose()&lt;br /&gt;&lt;br /&gt;type MogreForm() as this =&lt;br /&gt;    inherit Form()&lt;br /&gt;&lt;br /&gt;    let mogrePanel = new System.Windows.Forms.Panel()&lt;br /&gt;&lt;br /&gt;    // Between Suspend and Resume Layout is normal form Designer Code&lt;br /&gt;    do  base.SuspendLayout()&lt;br /&gt;&lt;br /&gt;        mogrePanel.Location &lt;- new System.Drawing.Point(0, 0)&lt;br /&gt;        mogrePanel.Name &lt;- "mogrePanel"&lt;br /&gt;        mogrePanel.Size &lt;- new System.Drawing.Size(483, 375)&lt;br /&gt;        mogrePanel.TabIndex &lt;- 0&lt;br /&gt;&lt;br /&gt;        base.AutoScaleDimensions &lt;- new System.Drawing.SizeF(6.0f, 13.0f)&lt;br /&gt;        base.AutoScaleMode &lt;- System.Windows.Forms.AutoScaleMode.Font&lt;br /&gt;        base.ClientSize &lt;- new System.Drawing.Size(483, 375)&lt;br /&gt;        base.Controls.Add(mogrePanel)&lt;br /&gt;        base.Name &lt;- "MogreForm"&lt;br /&gt;        base.Text &lt;- "Simple F# Mogre Form";&lt;br /&gt;&lt;br /&gt;        base.ResumeLayout(false)&lt;br /&gt;&lt;br /&gt;        let mogreWin = new OgreWindow(Point(100, 30), mogrePanel.Handle)&lt;br /&gt;        this.Disposed.Add(fun _ -&gt; mogreWin.Dispose())&lt;br /&gt;        this.Paint.Add(fun _ -&gt; mogreWin.Paint())&lt;br /&gt;&lt;br /&gt;let main() =&lt;br /&gt;    Application.EnableVisualStyles()&lt;br /&gt;    Application.SetCompatibleTextRenderingDefault(false)&lt;br /&gt;    Application.Run(new MogreForm())&lt;br /&gt;&lt;br /&gt;[&lt;STAThread&gt;]&lt;br /&gt;do main()&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-3484037015574865636?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/3484037015574865636/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=3484037015574865636' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/3484037015574865636'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/3484037015574865636'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2010/01/moving-on-with-f-development.html' title='Moving on with F# Development'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_9tQTRFC8wPE/S1O94__L18I/AAAAAAAAAX4/oNoHdysI5Pc/s72-c/MogreForm.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-1013429588647496391</id><published>2009-05-07T15:52:00.001-07:00</published><updated>2009-05-07T16:51:27.351-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='Autodesk'/><category scheme='http://www.blogger.com/atom/ns#' term='XNA 3.0'/><category scheme='http://www.blogger.com/atom/ns#' term='F#'/><category scheme='http://www.blogger.com/atom/ns#' term='Breakout'/><title type='text'>XNA F# Breakout Clone - Model Tutorials</title><content type='html'>&lt;p&gt;I'm impressed by how easy it is to use Models in XNA and because of this I'm demoting my render engine to line drawing only.    Here is how I went about getting Models into my game.&lt;br /&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;First you will need software to create models and Autodesk has a free version of just that. &lt;a href="http://www.softimage.com/products/modtool/"&gt;Autodesk Softimage Mod Tool 7.5&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Watch &lt;a href="http://video.msn.com/video.aspx?mkt=en-us&amp;amp;vid=008b55b0-56cc-4cfc-99a9-6ee47149b20c"&gt;this video&lt;/a&gt; so you can create and export your 3D models correctly. The video series and blog post can be found &lt;a href="http://blogs.msdn.com/dawate/archive/2008/02/05/building-a-3d-game-in-xna-from-scratch-free-video-tutorial-series-now-available.aspx"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Third you can follow the Microsoft tutorials to get your models in game &lt;a href="http://msdn.microsoft.com/en-us/library/bb197293.aspx"&gt;Microsoft Tutorial on displaying a 3D Model&lt;/a&gt; or you can &lt;a href="http://video.msn.com/video.aspx?vid=a0668c4b-db79-4b34-9de4-ed834a9cab6c"&gt;continue&lt;/a&gt; the &lt;a href="http://blogs.msdn.com/dawate/archive/2008/02/05/building-a-3d-game-in-xna-from-scratch-free-video-tutorial-series-now-available.aspx"&gt;blog&lt;/a&gt; from the previous step.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Finally you will need some video tutorials on how to use Autodesk to create more complex models.  &lt;a href="http://community.softimage.com/forumdisplay.php?f=57"&gt;XSI Video Tutorials&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;/p&gt;&lt;div&gt;&lt;a href="http://github.com/gradbot/xna-f-sharp-breakout"&gt;XNA F# Breakout Clone - Project Homepage&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_9tQTRFC8wPE/SgNmPvyeYlI/AAAAAAAAAQE/hhrBF6yoR4E/s1600-h/breakout5.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 294px; height: 400px;" src="http://2.bp.blogspot.com/_9tQTRFC8wPE/SgNmPvyeYlI/AAAAAAAAAQE/hhrBF6yoR4E/s400/breakout5.png" alt="" id="BLOGGER_PHOTO_ID_5333218804449043026" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-1013429588647496391?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/1013429588647496391/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=1013429588647496391' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/1013429588647496391'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/1013429588647496391'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2009/05/xna-f-breakout-clone-model-tutorials.html' title='XNA F# Breakout Clone - Model Tutorials'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_9tQTRFC8wPE/SgNmPvyeYlI/AAAAAAAAAQE/hhrBF6yoR4E/s72-c/breakout5.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-5294400589270353929</id><published>2009-05-03T15:14:00.000-07:00</published><updated>2010-05-31T10:41:49.215-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Physics Engine'/><category scheme='http://www.blogger.com/atom/ns#' term='XNA 3.0'/><category scheme='http://www.blogger.com/atom/ns#' term='F#'/><category scheme='http://www.blogger.com/atom/ns#' term='Breakout'/><title type='text'>Breakout Clone - Added Physics Engine and Sound - F# XNA</title><content type='html'>&lt;p&gt;I added the &lt;a href="http://www.codeplex.com/FarseerPhysics"&gt;Farseer Physics Engine&lt;/a&gt; to my game along with XNA sound effects.  I'm amazed by how easy it was to use this physics engine.  Collisions are handled by Delegates which you create in F# by passing a function to the delegate constructor.&lt;br /&gt;&lt;/p&gt;&lt;pre class="brush: fsharp"&gt;&lt;br /&gt;ball.Geometry.OnCollision &lt;- &lt;br /&gt;    Geom.CollisionEventHandler(&lt;br /&gt;        fun geom1 geom2 contactList -&gt; true)&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;My current plan is to add different shapes to the blocks, different masses, and maybe events such as an explosion.&lt;/p&gt;&lt;div&gt;&lt;a href="http://github.com/gradbot/xna-f-sharp-breakout"&gt;XNA F# Breakout Clone - Project Homepage&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_9tQTRFC8wPE/Sf4XjW8zNSI/AAAAAAAAAOw/3C3-lPPbYD0/s1600-h/breakout3.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 292px; height: 400px;" src="http://1.bp.blogspot.com/_9tQTRFC8wPE/Sf4XjW8zNSI/AAAAAAAAAOw/3C3-lPPbYD0/s400/breakout3.jpg" alt="" id="BLOGGER_PHOTO_ID_5331724905076700450" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-5294400589270353929?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/5294400589270353929/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=5294400589270353929' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/5294400589270353929'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/5294400589270353929'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2009/05/breakout-clone-added-physics-engine-and.html' title='Breakout Clone - Added Physics Engine and Sound - F# XNA'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_9tQTRFC8wPE/Sf4XjW8zNSI/AAAAAAAAAOw/3C3-lPPbYD0/s72-c/breakout3.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-4538731383985580629</id><published>2009-04-27T08:09:00.000-07:00</published><updated>2010-05-31T10:41:05.023-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA 3.0'/><category scheme='http://www.blogger.com/atom/ns#' term='F#'/><category scheme='http://www.blogger.com/atom/ns#' term='Breakout'/><category scheme='http://www.blogger.com/atom/ns#' term='Discriminated Union'/><title type='text'>Knockout Clone - Discriminated Unions with F#</title><content type='html'>&lt;div&gt;F# supports discriminated unions.  This along with pattern matching makes for some short and elegant code which quite frankly is awesome.  Here's a small example.&lt;br /&gt;&lt;pre class="brush: fsharp"&gt;&lt;br /&gt;type PieceType = Breakable | Solid&lt;br /&gt;&lt;br /&gt;member this.needsDisposing() =&lt;br /&gt;    match pieceType with&lt;br /&gt;        | Breakable -&gt; (life &lt;= 0)         &lt;br /&gt;        | Solid -&gt; false&lt;br /&gt;&lt;br /&gt;member this.points() =&lt;br /&gt;    match pieceType with&lt;br /&gt;        | Breakable -&gt; 1&lt;br /&gt;        | Solid -&gt; 0&lt;br /&gt;&lt;/pre&gt;Here I use a property of type PieceType to both define when a piece on the board needs to be removed and if the piece returns a point when it is hit.  The calling class has no knowledge of this state and filters out pieces based on the returned bool flag needsDisposing() along with adding whatever is returned by points() to the total point score.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;a href="http://github.com/gradbot/xna-f-sharp-breakout"&gt;XNA F# Breakout Clone - Project Homepage&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_9tQTRFC8wPE/SfXKu9_u07I/AAAAAAAAAOo/TBxMf3EKv9o/s1600-h/breakout2.gif"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 294px; height: 400px;" src="http://1.bp.blogspot.com/_9tQTRFC8wPE/SfXKu9_u07I/AAAAAAAAAOo/TBxMf3EKv9o/s400/breakout2.gif" alt="" id="BLOGGER_PHOTO_ID_5329388642327516082" border="0" /&gt;&lt;br /&gt;&lt;/a&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238); text-decoration: underline;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-4538731383985580629?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/4538731383985580629/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=4538731383985580629' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/4538731383985580629'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/4538731383985580629'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2009/04/knockout-clone-discriminated-unions.html' title='Knockout Clone - Discriminated Unions with F#'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_9tQTRFC8wPE/SfXKu9_u07I/AAAAAAAAAOo/TBxMf3EKv9o/s72-c/breakout2.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-6037248898540444905</id><published>2009-04-19T10:51:00.000-07:00</published><updated>2009-07-02T09:20:22.241-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Algorithm'/><category scheme='http://www.blogger.com/atom/ns#' term='XNA 3.0'/><category scheme='http://www.blogger.com/atom/ns#' term='F#'/><category scheme='http://www.blogger.com/atom/ns#' term='Breakout'/><title type='text'>Breakout Clone - Line Segment Intersection Algorithm</title><content type='html'>&lt;p&gt;For my next game Breakout, I need to detect collisions for a moving object.  I choose line segments to represent object borders and motion.  Calculating line segment intersections is a simple and fast algorithm and there are more advanced scan line algorithms to speed it up if needed.   In order to use it, I take the ball's position and old position as the line segment for the ball.&lt;/p&gt;&lt;p&gt;The hard part of any collision algorithm is of course dealing with the collision.  Detection is always easy because it's been done before.  I'm doing collision with a simple reflection of the velocity off of the line segment it's intersecting.  This works great until you collide close to another line segment and you happen to reflect to the other side of it.  To fix this, I made the intersection and reflection algorithm recursive.  This works great except for possible race conditions.  Also, you no longer have a constant speed for your ball. A quick fix for the race condition is to check to make sure you can't intersect with the same line segment twice in a row. Having the ball move a little faster is acceptable.&lt;br /&gt;&lt;/p&gt;&lt;a href="http://github.com/gradbot/xna-f-sharp-breakout"&gt;Project Homepage&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_9tQTRFC8wPE/SkzeGPRnqHI/AAAAAAAAAUE/K5TrrzHNZbs/s1600-h/breakout.png"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 292px; height: 400px;" src="http://2.bp.blogspot.com/_9tQTRFC8wPE/SkzeGPRnqHI/AAAAAAAAAUE/K5TrrzHNZbs/s400/breakout.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5353898255797692530" /&gt;&lt;/a&gt;&lt;p&gt;Here's a burn test where I had set the ball to a very high speed to see if it could escape it's enclosure or enter one of the other objects.  In order to make any errors apparent, I added a line trail of a random colors behind the ball.  This ends up filling in all of the movable area.&lt;/p&gt;&lt;p&gt;I must say it's pretty cool to see the ball travel to every little nook and cranny of the board.  This must be how particle chaos works.  Like a fragrance filling the room.&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-6037248898540444905?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/6037248898540444905/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=6037248898540444905' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/6037248898540444905'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/6037248898540444905'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2009/04/breakout-clone-line-segment.html' title='Breakout Clone - Line Segment Intersection Algorithm'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_9tQTRFC8wPE/SkzeGPRnqHI/AAAAAAAAAUE/K5TrrzHNZbs/s72-c/breakout.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-8409785536179178668</id><published>2009-04-11T17:08:00.000-07:00</published><updated>2009-05-03T15:33:24.557-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA 3.0'/><category scheme='http://www.blogger.com/atom/ns#' term='F#'/><category scheme='http://www.blogger.com/atom/ns#' term='Tetris'/><title type='text'>Tetris in XNA with F#</title><content type='html'>I learned a few things on this project.  One is that arrays are not the end all of data structures.  My first instinct from my C++ background was to make a 2D array for the tetris game board.  After wasting an hour or two I realized that it was over complicated and that a Set would work really well.&lt;br /&gt;&lt;br /&gt;Basically each piece in the game is a set of tuple points.  The game board boarder is a set of tuple points and the already fallen pieces is a set of pieces.  I had to keep the concept of a piece in order to keep the color associated with each tuple point. This setup made collision detection simple.  It was just a matter of Seq.union_all and Set.intersect&lt;br /&gt;&lt;br /&gt;I'm pretty amazed by the relatively few lines of code it took me to recreate the game.  The main game logic is incredibly small.  Most of the code is spent setting up the system and handling user input/graphics.&lt;br /&gt;&lt;br /&gt;Project Time: 13 hours&lt;br /&gt;&lt;a href="http://github.com/gradbot/xna-f-sharp-tetris"&gt;Project - Source Code&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The game is played with the DPad and A/B buttons.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_9tQTRFC8wPE/SeFDgX1jumI/AAAAAAAAAOI/_SA3DO1dcSg/s1600-h/tetris1.gif"&gt;&lt;img style="cursor: pointer; width: 258px; height: 320px;" src="http://4.bp.blogspot.com/_9tQTRFC8wPE/SeFDgX1jumI/AAAAAAAAAOI/_SA3DO1dcSg/s320/tetris1.gif" alt="" id="BLOGGER_PHOTO_ID_5323610457962166882" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-8409785536179178668?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/8409785536179178668/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=8409785536179178668' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/8409785536179178668'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/8409785536179178668'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2009/04/tetris-in-xna-with-f.html' title='Tetris in XNA with F#'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_9tQTRFC8wPE/SeFDgX1jumI/AAAAAAAAAOI/_SA3DO1dcSg/s72-c/tetris1.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-5467375336407855835</id><published>2009-03-10T14:37:00.000-07:00</published><updated>2009-05-03T15:35:32.422-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='2D Classics'/><title type='text'>Learning from the Classics</title><content type='html'>So I decided while working on my platformer that I need to reduce the number of jobs I'm undertaking while I program.  In order to do that I'm dropping creative director and am instead recreating classic titles.  I'm still project manager since I need to manage my time and my development goal has to be playability if I'm ever going to get anything playable.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The below list contains all the 2D video game genres I can think of.  I'm going to pick a game and spend a few weeks recreating it and then move on to another game in a different genre.  I hope to learn the different challenges associated with each genre and what game mechanics cross genres.  I have other long term goals but i'll worry more about those once I have a few games playable.&lt;br /&gt;&lt;br /&gt;2d paddle - knockout, pong&lt;br /&gt;2d shooter - galaga, zanak, space invaders&lt;br /&gt;2d platformer - metroid, mario, kurby, castlevania, sonic&lt;br /&gt;2d puzzle - tetris, dr. mario, generic match 3 game&lt;br /&gt;2d maze - pacman, frogger&lt;br /&gt;2d hack &amp;amp; slash - gauntlet, zelda, diablo, crono trigger&lt;br /&gt;2d fighter - street fighter&lt;br /&gt;2d rpg - final fantasy, dragon warrior&lt;br /&gt;2d simulation - simcity, trains&lt;br /&gt;2d strategy - civilization&lt;br /&gt;2d rts - starcraft, red alert, dune 2, lemmings&lt;br /&gt;2d racing - r.c. pro am, excite bike, mario cart&lt;br /&gt;2d board game - chess, checkers, go, othello&lt;br /&gt;2d projectile - gorrila, scorched earth, tank&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm going to contenue using F# and XNA as they have served me well so far.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-5467375336407855835?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/5467375336407855835/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=5467375336407855835' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/5467375336407855835'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/5467375336407855835'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2009/03/learning-from-classics.html' title='Learning from the Classics'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-7454613657929961812</id><published>2009-02-17T21:33:00.000-08:00</published><updated>2010-05-31T10:42:40.419-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='F#'/><category scheme='http://www.blogger.com/atom/ns#' term='Effect FX'/><category scheme='http://www.blogger.com/atom/ns#' term='Nvidia'/><title type='text'>Added runtime fx compilation and lighting</title><content type='html'>I spent some time fighting with matrices to get the lighting correct but I'm happy now that I have a rotating and moving object in XNA that is lit from a single stationary source.  I'm using the plastic shader that comes with &lt;a href="http://developer.nvidia.com/object/fx_composer_home.html"&gt;NVIDIA FX Composer 2.5&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_9tQTRFC8wPE/SZughoWyHwI/AAAAAAAAAM4/9wwRhXJaZPE/s1600-h/triangle3.png"&gt;&lt;img style="cursor: pointer; width: 320px; height: 239px;" src="http://2.bp.blogspot.com/_9tQTRFC8wPE/SZughoWyHwI/AAAAAAAAAM4/9wwRhXJaZPE/s320/triangle3.png" alt="" id="BLOGGER_PHOTO_ID_5304009485787995906" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here's my runtime code that compiles a fx file into an Effect.&lt;br /&gt;&lt;pre class="brush: fsharp"&gt;&lt;br /&gt;let compileEffect(fileName : string)=&lt;br /&gt;   let compiledEffect =&lt;br /&gt;       Effect.CompileEffectFromFile(&lt;br /&gt;           fileName,&lt;br /&gt;           null,&lt;br /&gt;           null,&lt;br /&gt;           CompilerOptions.Debug,&lt;br /&gt;           TargetPlatform.Windows)&lt;br /&gt;   let effectCode =&lt;br /&gt;       compiledEffect.GetEffectCode()&lt;br /&gt;   new Effect(&lt;br /&gt;       this.graphics.GraphicsDevice,&lt;br /&gt;       effectCode,&lt;br /&gt;       CompilerOptions.Debug,&lt;br /&gt;       null)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;a href="http://github.com/gradbot/xna-f-sharp/commit/6d2fc6b5add8df0180b2e4c150f8750d6d180c82"&gt;source code&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-7454613657929961812?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/7454613657929961812/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=7454613657929961812' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/7454613657929961812'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/7454613657929961812'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2009/02/added-runtime-fx-compilation-and.html' title='Added runtime fx compilation and lighting'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_9tQTRFC8wPE/SZughoWyHwI/AAAAAAAAAM4/9wwRhXJaZPE/s72-c/triangle3.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-138357435284637095</id><published>2009-02-14T11:03:00.000-08:00</published><updated>2009-05-03T15:38:19.269-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA 3.0'/><category scheme='http://www.blogger.com/atom/ns#' term='F#'/><category scheme='http://www.blogger.com/atom/ns#' term='Primitives'/><title type='text'>Moving along in XNA</title><content type='html'>&lt;p&gt;I added a shape class and some basic shapes made out of line segments.  Along with this i added collision for the line segments with a player and mapped the first controller pad to control it.  Jumping is very basic and gravity is simple.&lt;/p&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.gradient.info/blog/triangle2.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 400px; height: 313px;" src="http://www.gradient.info/blog/triangle2.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://picasaweb.google.com/gradbot/Programming?feat=directlink"&gt;Images from the project.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;source code: &lt;a href="http://github.com/gradbot/xna-f-sharp/commit/c6e6afae3317230447ea610b5f7a251e008328ee"&gt;github.com/gradbot/xna-f-sharp&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-138357435284637095?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/138357435284637095/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=138357435284637095' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/138357435284637095'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/138357435284637095'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2009/02/moving-along-in-xna.html' title='Moving along in XNA'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-6263628042924674039</id><published>2009-01-04T13:47:00.000-08:00</published><updated>2010-05-31T10:52:42.301-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XNA 3.0'/><category scheme='http://www.blogger.com/atom/ns#' term='F#'/><category scheme='http://www.blogger.com/atom/ns#' term='Primitives'/><title type='text'>Rotating Triangle in F#</title><content type='html'>For my first project in F# I ported a simple C# XNA project that draws an rotating triangle.  The original C# article can be found &lt;a href="http://www.nuclex.org/articles/using-xna-to-draw-a-rotating-triangle"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I'm using Microsoft F#, September 2008 CTP (Community Technology Preview) and Microsoft XNA 3.0 CTP&lt;br /&gt;&lt;br /&gt;You can download the complete solution &lt;a href="http://www.gradient.info/code/triangle.zip"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;img src="http://gradient.info/code/triangle.png" title="Rotating Triangle in F#" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: fsharp"&gt;&lt;br /&gt;#I @"C:\Program Files\Microsoft XNA\XNA Game Studio\v3.0\References\Windows\x86";;&lt;br /&gt;&lt;br /&gt;#r @"Microsoft.Xna.Framework.dll";;&lt;br /&gt;#r @"Microsoft.Xna.Framework.Game.dll";;&lt;br /&gt;&lt;br /&gt;open System&lt;br /&gt;open System.Collections.Generic&lt;br /&gt;&lt;br /&gt;open Microsoft.Xna.Framework&lt;br /&gt;open Microsoft.Xna.Framework.Audio&lt;br /&gt;open Microsoft.Xna.Framework.Content&lt;br /&gt;open Microsoft.Xna.Framework.Graphics&lt;br /&gt;open Microsoft.Xna.Framework.Input&lt;br /&gt;open Microsoft.Xna.Framework.Storage&lt;br /&gt;&lt;br /&gt;type MyGame = &lt;br /&gt;    inherit Game&lt;br /&gt;  &lt;br /&gt;    val mutable graphics : GraphicsDeviceManager&lt;br /&gt;    val mutable content : ContentManager&lt;br /&gt;    val mutable effect : Effect&lt;br /&gt;    val mutable world : Matrix&lt;br /&gt;    val mutable view : Matrix&lt;br /&gt;    val mutable projection : Matrix&lt;br /&gt;  &lt;br /&gt;    new() as this =&lt;br /&gt;        {&lt;br /&gt;            graphics = null&lt;br /&gt;            content = null&lt;br /&gt;            effect = null&lt;br /&gt;            world = Matrix.Identity&lt;br /&gt;            view = Matrix.Identity&lt;br /&gt;            projection = Matrix.Identity&lt;br /&gt;        }&lt;br /&gt;        then&lt;br /&gt;            this.graphics &lt;- new GraphicsDeviceManager(this)&lt;br /&gt;            this.content &lt;- new ContentManager(this.Services)&lt;br /&gt;            this.view &lt;- &lt;br /&gt;                Matrix.CreateLookAt(&lt;br /&gt;                    new Vector3(0.0f, 0.0f, 3.0f),&lt;br /&gt;                    Vector3.Zero,&lt;br /&gt;                    new Vector3(0.0f, 1.0f, 0.0f))&lt;br /&gt;            this.projection &lt;- &lt;br /&gt;                Matrix.CreatePerspectiveFieldOfView(&lt;br /&gt;                    MathHelper.Pi / 4.0f,&lt;br /&gt;                    (float32)this.Window.ClientBounds.Height / (float32)this.Window.ClientBounds.Width * 3.0f / 2.0f,&lt;br /&gt;                    0.01f,&lt;br /&gt;                    1000.0f)&lt;br /&gt;&lt;br /&gt;    override this.Initialize() =&lt;br /&gt;        base.Initialize()      &lt;br /&gt;       &lt;br /&gt;    override this.LoadContent() = &lt;br /&gt;        this.effect &lt;- this.content.Load("colorfill")&lt;br /&gt;       &lt;br /&gt;    override this.Draw(gameTime) = &lt;br /&gt;        let gd = this.graphics.GraphicsDevice&lt;br /&gt;        gd.Clear(Color.Green)&lt;br /&gt;       &lt;br /&gt;        let vertex = [|&lt;br /&gt;            new VertexPositionColor(new Vector3(-0.5f, -0.5f, 0.0f), Color.Red);&lt;br /&gt;            new VertexPositionColor(new Vector3(0.0f, 0.5f, 0.0f), Color.Blue);&lt;br /&gt;            new VertexPositionColor(new Vector3(0.5f, -0.5f, 0.0f), Color.Yellow);&lt;br /&gt;        |]&lt;br /&gt;&lt;br /&gt;        gd.RenderState.CullMode &lt;- CullMode.None&lt;br /&gt;        gd.VertexDeclaration &lt;- new VertexDeclaration(gd, VertexPositionColor.VertexElements)&lt;br /&gt;&lt;br /&gt;        this.effect.Begin()&lt;br /&gt;&lt;br /&gt;        for pass in this.effect.CurrentTechnique.Passes do&lt;br /&gt;            pass.Begin()&lt;br /&gt;            gd.DrawUserPrimitives(PrimitiveType.TriangleList, vertex, 0, 1)&lt;br /&gt;            pass.End()&lt;br /&gt;&lt;br /&gt;        this.effect.End()&lt;br /&gt;&lt;br /&gt;    override this.Update(gameTime) = &lt;br /&gt;        if (GamePad.GetState(PlayerIndex.One).Buttons.Back = ButtonState.Pressed) then&lt;br /&gt;            this.Exit()&lt;br /&gt;&lt;br /&gt;        this.world &lt;- this.world * Matrix.CreateRotationY(MathHelper.TwoPi / 360.0f)&lt;br /&gt;        this.effect.Parameters.Item("WorldViewProj").SetValue(this.world * this.view * this.projection)&lt;br /&gt;        base.Update(gameTime)&lt;br /&gt;      &lt;br /&gt;let game = new MyGame()&lt;br /&gt;game.Run()&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-6263628042924674039?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/6263628042924674039/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=6263628042924674039' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/6263628042924674039'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/6263628042924674039'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2009/01/rotating-triangle-in-f.html' title='Rotating Triangle in F#'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1789861069162129577.post-4895840340721247678</id><published>2008-12-26T12:55:00.001-08:00</published><updated>2009-05-03T15:40:18.100-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Review'/><category scheme='http://www.blogger.com/atom/ns#' term='F#'/><category scheme='http://www.blogger.com/atom/ns#' term='Book'/><title type='text'>Expert F#</title><content type='html'>I recently purchased Expert F# and I'm quite satisfied with it.  It goes well beyond syntax and into best practices.  It also includes some excellent glue work for various targets such as web development and managed Direct X.  The level of detail it goes through means a slow read and it skips over trying to teach you the basics of programming.  I read it in a few days verses an afternoon which is normal for me and a technical book.&lt;br /&gt;&lt;br /&gt;I'm interested to see if the section on decoding compiler error messages will be useful at some point.  The book covers Functional, Imperative, Object Oriented, and Language Oriented programming in F#.  The section on OOP was a bit short however the book mentions that this section was kept short on purpose to help you get away from pure OOP.  The few mastering chapters are really good at taking F#'s syntax and clarifying how it works.&lt;br /&gt;&lt;br /&gt;I highly recommend this book based on it being information rich and fluff free.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1789861069162129577-4895840340721247678?l=gradbot.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://gradbot.blogspot.com/feeds/4895840340721247678/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1789861069162129577&amp;postID=4895840340721247678' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/4895840340721247678'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1789861069162129577/posts/default/4895840340721247678'/><link rel='alternate' type='text/html' href='http://gradbot.blogspot.com/2008/12/expert-f.html' title='Expert F#'/><author><name>gradbot</name><uri>http://www.blogger.com/profile/03333817171572641019</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='25' height='32' src='http://3.bp.blogspot.com/_9tQTRFC8wPE/SSHgd1NE9oI/AAAAAAAAALM/XDcWzsRyxBM/S220/n1001720775_30054819_5021.jpg'/></author><thr:total>0</thr:total></entry></feed>
