images Hi. I’m Robert Gawdzik.

I’m a Computer Science student and aspiring Software Engineer from the University of Waterloo.


The Ruby, Coffeescript, and Rails way

I recently started work at Uken Games as a software developer intern, and I didn’t update my blog in a while.

I picked up coffeescript, ruby, and rails. I am here to speak specifically about ruby and coffeescript, both interesting languages that share a few interesting traits of style in common.

Expressive Syntax

Both ruby and coffee make it really easy to have meaningful, expressive code. The best part is that you can think with similar syntax on both the front and backend. This is similar to node.js, and is one of the advantages that people tend to argue for using node.js.

The following solves a simple task: Given a list of n elements, return a list containing only elements with an even index in the array.

even.rb
1
get_even = ->(arr) { arr.select.with_index { |a, i| i % 2 == 0 } }

With coffeescript:

even.coffee
1
get_even = (arr) -> (a for a, i when i % 2 == 0)

As you can see, this syntax is very minimal, beautiful, and meaningful. And you can see various overlap between both ruby and coffee syntax; the anonymous method declaration for example. Both languages also try hard to be “english-like” when performing logic (Not to the point of Visual Basic though). I will mention that creating ruby anonymous methods create a Proc, which requires calling the function using .call(args…), whereas coffeescript anonymous functions are more first class.

What about speed? Isn’t that important? Well, ruby isn’t fast. But it’s good enough for most applications like web development. You would use Ruby to create your next CMS, but I wouldn’t use it to create a AAA 3D game. I believe if you can use ruby/python or other minimal languages, use them. They are more expressive and compact, thus easier to debug since developers consider every character in the source code, since it has meaning instead of being boilerplate (Cough, cough, Java).

Kick-Ass Platform

Rails is a mature, stable, ecosystem of tools that strive toward creating a nice backend platform. I’ve come from node.js, which is a more younger platform that shows it youth. For example, there is no toolkit like what rails has for generating projects, controllers, routes, tests, etc.

When I want to generate a rails project, I simply:

cmd.bash
1
rails new project_name

Whereas in node.js, I need to find a template on github or use bower. When I want to generate a controller, I simply:

cmd.bash
1
rails g controller ctrl_name

Whereas in node.js, I need to manually create the files necessary. I think you get the point. By the way, I realize many other web platforms like Django offer this sort of command line toolkit, however I am simply comparing node to rails. And if you comment on this blog telling me there are things such as bower that offer a node toolkit, I will ask “Why isn’t it in node?”.


A new prototype: TankGL

I’ve decided to develop a prototype this week: TankGL. Why you might ask? I’ve seen a lack of WebGL games around tanks. I really like tank games, as I played BattleTankz as a child.

I wanted TankGL to be some sort of massive online/bot-based tank battlefield. This isn’t going to be an easy task because of the immediate challenges of scalability and efficiency. images

Technical

TankGL has a foundation on the following technologies:

The general idea is to offload all the computationally expensive game logic to the server, and have the client act as a rendering agent with a controller interface. Through web sockets, we can use effective communication in the form of events and callback functions.

the design of tankgl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
+-----------------+                   +-------------------+
|      Server     |+----------------->|       Client      |
|                 |<-----------------+|                   |
+-----------------+     WebSockets   ++-------------------+
         ^                                      +
         |                                      |
         |                                      |
         v                                      v
   Physics Engine                        Rendering Engine
         ^                                      +
         |                                      |
         |                                      |
         v                                      v
    Tank Manager                              Human

Updating the client

Currently the client is updated 60 times a second through an update event in web sockets. The update also contains a delta of the state of the map in JSON format. This delta allows the client to update what the user sees.

The biggest bandwidth consumer is the delta state. We can reduce bandwidth by using the map to our advantage. Since we assume the map is of fixed width (Think 5km by 5km), we can partition the whole map into fixed width cells and give the player a respective update to current and surrounding cells. I call this a “Difference Grid”, it might be called something else in the game industry. The best part is that retrieval from the difference grid is O(1). We will be retrieving a lot.

The following is a highly condensed DiffGrid ADT example with most comments removed for brevity.

ext.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
function DiffGrid(map_size, fixed_width) {
    ... //Set up DiffGrid
}

//retrieve: {Int, Int} -> Array
DiffGrid.prototype.retrieve = function(cell) {
    return this.grid[cell.y][cell.x];
}

//bounded: {Int, Int} -> Bool
DiffGrid.prototype.bounded = function(cell) {
    return 0 <= cell.x && cell.x < this.grid[0].length
    && 0 <= cell.y && cell.y < this.grid.length;
}

//search: {Int, Int} -> Array
DiffGrid.prototype.search = function(cell) {
    ...
    for(var x = -1; x <= 1; x++) {
        for(var y = -1; y <= 1; y++) {
            if(this.bounded({x: cell.x + x, y: cell.y + y})) {
                 ret.concat(this.retrieve(n_cell));
             }
        }
    }
    return ret;
}

//foreach(Function) -> Void
DiffGrid.prototype.foreach = function(fn) {
    ...//Traverse all cells, apply fn
}

//update: Int {Int, Int} Int -> Void
DiffGrid.prototype.update = function(tank_id, p_cell, n_cell) {
    remove(this.retrieve(p_cell), tank_id);
    this.retrieve(n_cell).push(tank_id);
}

//getCell: {Int, Int} -> {Int, Int}
DiffGrid.prototype.getCell = function(loc) {
    return {x: loc.x / this._fixed_width, y: loc.y / this._fixed_width };
}

This is really great when you have 200 tanks on the battlefield. You don’t want to pass 1MB of JSON every 60th of a second.

We can still improve bandwidth futher; the update event will be reduced to 30 times a second by using client-side lag compensation. However, this is not implemented yet.

The Map

For the map, I decided that randomly generated terrain would be adequate for gameplay. To generate this map, I used Simplex Noise.

main.js
1
2
3
4
5
6
7
8
9
10
11
var geometry = new THREE.PlaneGeometry(map_size, map_size, map_size - 1, map_size - 1 );
var SimplexNoise = require('simplex-noise'),
simplex = new SimplexNoise();

for(var y = 0; y < map_size; y++) {
    for(var x = 0; x < map_size; x++) {
        geometry.vertices[(y * map_size) + x].z = geometry.vertices[(y * map_size) + x].y + map_size / 2;
        geometry.vertices[(y * map_size) + x].y = simplex.noise2D(x, y) / 3;
        geometry.vertices[(y * map_size) + x].x += map_size / 2;
    }
}

At server startup, the terrain is generated and stored. When a client connects, they emit a ‘need_map’ event, and the server sends the 2MB map.

I chose to compute the map each time rather than having a cold map stored in the client for extensibility: I might want to have more maps one day, or custom user ones.

Conclusion

I am really enjoying the work I am doing and already did on tankgl. I feel that writing 3D games tend to get you thrown at harder problems quicker compared to writing regular apps. The networking, performance, and mathematical problems you face are useful in becoming a better Computer Scientist.


My participation at a Facebook Hackathon

Yesterday (January 24-25 2014), I participated in a 24h Facebook hackathon that held host to 400 people. We first started working on Video Tapestries a project that tries to navigate video in a different way than usual, by melding the scenes of an image to form a medievial tapestry. At 6am, 13 hours after the start of the hackathon, we decided that it was way too ambitious for a 24h hackathon, thus our team went to bed, leaving only me and Tasti.

We started to brainstorm ideas and thought of a really funny idea: Facemash but with Code instead of faces. It was really silly and started working at 7am. Remember that we didn’t sleep yet.

The project itself was very simple since we only had 3 hours, but we had a working prototype by 3pm. It features what not to do at a real job, such as inlining css and javascript. (Also, another team member(Neil) came from his sleep at 11am and polished it up, which was awesome as we were barely functioning.)

When we presented, the whole audience of 400 laughed, which got us a honourable mention out of 50 projects. It’s really awesome to be part of a school that manages to round in 400 student developers at a local event.

This shows you that you shouldn’t give up at a hackathon, and should continue working until the very end. It’s better to show off something rather than nothing.


An OpenGL Adventure: 3D Conway’s Game of Life

YouTube Link

Introduction

To experiment with OpenGL, I decided to make Conway’s Game of Life in 3-Dimensions. It is available on github, titled “Europa”.

If you are not familar with this 1970’s experiment, it has three rules (mine are modified for three dimensions).

  • A cell who is alive and has 2 or 3 neighbours lives to the next stage.
  • A cell who is dead and has exactly 3 neighbours becomes alive, as by reproduction.
  • A cell who is alive and has less than 2 or more than 3 neighbours dies, as if by under or over population.

Technical

The application at it’s current state is not polished. It is the result of 6 hours of coding.

The following are some of the highlights of Europa.

Dynamic Structures

Many game of life implementations just store all the cells in an fixed 2-dimensional boolean array. Instead, I wanted to focus on making the stage as dynamic as possible. This is done by simply using vectors and structures. Here are the structures:

/framework/foundation/foundation.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//Represents a position in 3D space:
struct Pos {
  int X;
  int Y;
  int Z;
  bool operator==(const Pos other);
};

//Represents a Color:
struct Color {
  int R;
  int G;
  int B;
  bool operator==(const Color other);
};

//Represents a Cell on the screen:
struct Cell {
  Pos position;
  Color color;
  bool alive;
  bool operator==(const Cell other);
};

Observe I am overloading the equality comparision operator. This is because I will need to compare these data types many times. Also, currently color isn’t implemented, but it isn’t hard to do so.

The Update Loop

In the update loop, I cared about the cells individually until the end. This improved efficiency as I didn’t have to do menial checking of the environment. purge_dead() takes care of the rest, removing any duplicates and dead cells from the world (which is a vector of type Cell).

/framework/game.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//update: &vector<Life> -> NULL
//Takes in a vector containing all the life forms on the screen and updates them.
void Framework::update(std::vector<Cell> &world) {
        std::queue<Cell> to_add = std::queue<Cell>();

        for(unsigned int i = 0; i < world.size(); i++) {
                std::vector<Cell> neighbours = Framework::pos_neighbours(world[i], world);
                int count_alive = Framework::neighbour_scan(world[i], world);
              ...
                for(std::vector<Cell>::iterator q = neighbours.begin(); q != neighbours.end(); ++q) {
                        //This cell should be alive:
                        if(Framework::neighbour_scan(*q, world) == 5) {
                                q->alive = true;
                                q->color = blend_color(q->color, world[i].color);
                                to_add.push(*q);
                        }
                }
        }

        //Add all the new elements to the world:
        while(!to_add.empty()) {
                world.push_back(to_add.front());
                to_add.pop();
        }

        purge_dead(world);
}

Neighbour Positions

I did a basic traversal in 3D space of 1 cell in radius. If you know a better way of doing this, let me know!

/framework/game.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//pos_neighbours: Cell vector<Cell> -> vector<Cell>
//Returns the location of all cells around a pivot, whether alive or dead.
std::vector<Cell> Framework::pos_neighbours(Cell pivot, std::vector<Cell> &world) {
        std::vector<Cell> neighbours;

        for(int x_ = -1; x_ < 2; x_++) {
                for(int y_ = -1; y_ < 2; y_++) {
                        for(int z_ = -1; z_ < 2; z_++) {

                                if(x_ != 0 || y_ != 0 || z_ != 0) {
                                        Pos dummy = pivot.position;
                                        dummy.X += x_;
                                        dummy.Y += y_;
                                        dummy.Z += z_;

                                        Cell temp;
                                        temp.alive = false;
                                        temp.position = dummy;
                                        neighbours.push_back(temp);
                                }
                        }
                }
        }
        return neighbours;
}

Conclusion

This was a fun small project. There wasn’t any real blackmagic wizardry as compared to my other 3D works such as Soar 3D. I learnt a lot about OpenGL, and I will continue studying it.


Using XMonad on UNIX

images

As any avid GNU/Linux user does, I too have a Window Manager. This one is called XMonad, and I was introduced to it through the Computer Science Club at the University of Waterloo.

It’s pretty awesome, and it has workspaces, responsive tiling, and really quick bootup time. It’s written and configured in Haskell, a functional programming language. XMonad is one of those examples you show when you confront a person who believes everything fast must have been written in C.

The following is my configuration file:

xmonad.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import XMonad
import XMonad.Hooks.DynamicLog
import XMonad.Hooks.ManageDocks
import XMonad.Util.Run(spawnPipe)
import XMonad.Util.EZConfig(additionalKeys)
import System.IO
import XMonad.Actions.UpdatePointer
import XMonad.ManageHook
import XMonad.Hooks.EwmhDesktops

startup = do
        spawn "xloadimage -onroot -fullscreen -center /home/rgawdzik/Pictures/background2.jpg"

main = do
xmproc <- spawnPipe "xmobar"
xmonad $ defaultConfig
    { manageHook = manageDocks <+> manageHook defaultConfig
    , layoutHook = avoidStruts  $  layoutHook defaultConfig
    , startupHook = startup
    , handleEventHook = fullscreenEventHook
    , logHook = updatePointer (Relative 0.99 0.99)
    } `additionalKeys`
    [ ((mod4Mask .|. shiftMask, xK_z), spawn "gnome-screensaver-command --lock") --mod4mask is the windows key
    , ((0, xK_Print), spawn "gnome-screenshot")
    ]

As well as XMonad, I use something called XMobar that serves as a status bar. It tells me the date, weather, cpu/memory/eth0 status, and is highly configurable to suit your own needs.

Here is it’s configuration file:

.xmobarrc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Config { font = "-misc-fixed-*-*-*-*-10-*-*-*-*-*-*-*"
       , bgColor = "#002b36"
       , fgColor = "#657b83"
       , position = Top
       , lowerOnStart = True
       , commands = [ Run Weather "CYKF" ["-t","<station>: <tempC>C","-L","18","-H","25","--normal","green","--high","red","--low","lightblue"] 36000
                    , Run Network "eth0" ["-L","0","-H","32","--normal","green","--high","red"] 10
                    , Run Network "eth1" ["-L","0","-H","32","--normal","green","--high","red"] 10
                    , Run Cpu ["-L","3","-H","50","--normal","green","--high","red"] 10
                    , Run Memory ["-t","Mem: <usedratio>%"] 10
                    , Run Swap [] 10
                    , Run Com "uname" ["-s","-r"] "" 36000
            , Run Date "%a %b %_d %Y %H:%M:%S" "date" 10
                    ]
       , sepChar = "%"
       , alignSep = "}{"
       , template = "%cpu% | %memory% * %swap% | %eth0% - %eth1% }{ <fc=#ee9a00>%date%</fc>| %CYKF% | %uname%"
       }

It suites my needs for computing, and I hope you consider it as your tiling window manager of choice.


Here is my newer blog

I have changed my blog again. I decided against WordPress because:

  • This is a sweet static blogging platform.
  • I get free hosting on github pages.

This static blog is running OctoPress, and the theme is OctoPress Flat.

The only reason I used WordPress initially was because of time constraints, but with this awesome Christmas Break, I had time to set up a real blogging platform. Over the chistmas break I will be posting a lot, and I plan to focus on:

  • Learning OpenGL
  • Contributing to Mozilla
  • Continue learning C++

Thank you!


My 1A Term as a UWaterloo CS Student

As my first term approaches a closure, I can now speak upon my core courses which are MATH135, MATH137, and CS135. You are required to take these courses as a Computer Science Student at the University of Waterloo. The cool part about the core courses is that they are interconnected with each other. Once you learn something such as gcd’s or induction, you start using it in CS or Calculus.

MATH135: Algebra

A mathematics course that is very unusual for a first year University course. One obvious way to tell is when you want to google a problem you are facing, you get links to 3rd year assignments from other Universities. The first portion of the course deals with introducing the concept of the proof, and how to perform rigorous ones. You are met with Proof by Contradiction, Induction, Strong Induction, Contrapositive, etc. This is where many students struggle initially, as it is not math they have encountered before. Rather than performing an algorithmic methodology they memorized, they are rather forced to think abstractly and dynamically solve problems.

A sample problem:

A sequence xi is defined by x_1=11 , x_2=23 , and x_n=x_n−1+12x_n−2 for all n>3 . Prove that for all x∈N , x_n=2(4)n−(−3)n

After the first midterm, the content dived into RSA, GCD, Congruency, Complex Numbers, and other interesting applied mathematics.

MATH137: Calculus I for the Mathematics

Ah yes, you took Calculus in High School right? Get ready for real calculus. This is the course that all first years underestimate initially, and start panicking after the midterm they did poorly on. Even though it reintroduces the concepts taught in High School, it does so at a highly theoretical approach. The course assignments/exams are ~60% applied, and 40% theoretical.

A sample problem:

Prove that if f(x)>0 for all x , if limx→∞f(x)=0 and limx→∞g(x)=∞ , then limx→∞(f(x))g(x)=0

Topics included: Integrals, Limits, Derivatives, Mean Value Theorem, Delta-Episilon Proofs, and much more.

CS135: Designing Functional Programs

You probably heard that 1st year CS students at the University of Waterloo learn functional programming. This is true, they use Scheme, a dialect of Lisp. While people scold Lisp, they fail to realize that it dramatically accelerates the education of Computer Science. With Scheme, we learn Trees, Binary Search Trees, Heaps, Directed Acyclic Graphs, Priority Queues, Unit Testing, File Structures, Peer2Peer Networks, Encryption and Decryption, sorting algorithms, algorithmic efficiency, and much more. Just think about the fact that you learn this in the first 1-3 months of coming to the UW for CS.

Another cool thing about Functional Programming is that it is actually used in the real world. Scala, Clojure, and functional paradigms are being/already introduced to the mainstream.

A cool sample: A Y Combinator

Two Electives of Your Choice

I hope this sums up my three core courses, and comes to an aid for anyone considering Computer Science at the University of Waterloo.


Why choose CS at UWaterloo?

Since some people are now applying to University (or are going to), I might as well tell you all why I choose the University of Waterloo for Computer Science.

Environment

The University of Waterloo is known to be very entrepreneurial in nature, such as it’s policies towards student ownership. Anything you make at the University of Waterloo is your own property, contrary to many standard University policies. This means startup incubators such as Velocity exist to aid University of Waterloo students into pursuing their dreams.

Faculty

The Computer Science program is under the largest Faculty of Mathematics in the world. The University of Waterloo realized that Mathematics should have their own devoted faculty, and also that the Computer Science roots exist in the branch of Mathematics rather than the natural sciences or arts or any other faculty that other University’s place their CS program in. This means you can graduate with a Bachelor of Mathematics with your major in Computer Science, or with a Bachelor of Computer Science. Computer Science is so popular at the University of Waterloo, that a building called DC (David Cheriton School of Computer Science) is devoted to it. It even it features 2 Tim Hortons.

Flexibility

The Bachelor of Computer Science is a very flexible degree, allowing you to specialize in Software Engineering, Bioinformatics, Business, Digital Hardware, or any minor/double joint major of your own. For example, I pursue an option in Software Engineering while having the ability to take interesting courses of my choosing such as Astronomy or (in the future) Real Time Programming.

Prestige

The University of Waterloo’s Math Faculty is very prestigious and known globally around the world, winning many awards such as in ACM competitions. Did you know that the University of Waterloo is the only Canadian University to ever win a global ACM? Not only once, but twice? These facts are what appeal to me when I apply to Universities. Not only this, but how companies such as Microsoft state “Many years, we hire more students out of the University of Waterloo than any other University in the world.”

Co-op

The University of Waterloo has the largest co-op program in the world. You also get the chance to experience 6 co-op jobs, or 5 if you want to take a 8-month co-op. This means when you graduate, you get to list 5-6 jobs on your resume. While some may say you get no summers off, I say that you would work during those summers anyways. The job hire rate for Computer Science Co-op is always really high, even during recessions. Once you graduate, you become very popular. Also note that it is very usual for 3rd/4th year UW CS students to work in Silicon Valley.

I hope this sums up why I choose the University of Waterloo for Computer Science Co-op.