<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
	<title>Kyle W. Banks</title>
	<link>http://kylewbanks.com</link>
	<image>
		<url>http://kylewbanks.com/favicon.ico</url>
		<title>Kyle W. Banks</title>
		<link>http://kylewbanks.com</link>
	</image>
	<description>
	A collection of tips, tricks, and tutorials covering a wide range of programming topics.
	</description>
		
		    <item>
                <title>Accessing the Goodreads API with Go</title>
                <link>https://kylewbanks.com/blog/accessing-goodreads-api-with-golang</link>
                <guid isPermaLink="true">https://kylewbanks.com/blog/accessing-goodreads-api-with-golang</guid>
                <pubDate>Sun, 27 Jan 2019 00:00:00 +0000</pubDate>
                <description>&lt;p&gt;&lt;a href=&quot;https://www.goodreads.com&quot;&gt;Goodreads&lt;/a&gt; is one of my favorite services, as I love reading (and spend quite a bit of time doing it, to be honest). My goal for 2019 is to read 75 books, and an additional 3 books in German as I’ve been learning the language over the last couple of years. Here’s where I’m at so far, and we’re only in January:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;[4 stars] &lt;a href=&quot;https://www.goodreads.com/book/show/20351202-the-man-in-the-high-castle&quot;&gt;The Man in the High Castle&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;[4 stars] &lt;a href=&quot;https://www.goodreads.com/book/show/29434402-the-start-up-j-curve&quot;&gt;The Start-Up J Curve: The Six Steps to Entrepreneurial Success&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;[1 stars] &lt;a href=&quot;https://www.goodreads.com/book/show/43203923-the-general-theory-of-employment-interest-and-money&quot;&gt;The General Theory of Employment, Interest, and Money&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;[4 stars] &lt;a href=&quot;https://www.goodreads.com/book/show/24811910-red-notice&quot;&gt;Red Notice: A True Story of High Finance, Murder, and One Man’s Fight for Justice&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;[3 stars] &lt;a href=&quot;https://www.goodreads.com/book/show/37761872-natural-language-processing-in-action&quot;&gt;Natural Language Processing in Action&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;[4 stars] &lt;a href=&quot;https://www.goodreads.com/book/show/18868371-an-astronaut-s-guide-to-life-on-earth&quot;&gt;An Astronaut’s Guide to Life on Earth&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;[4 stars] &lt;a href=&quot;https://www.goodreads.com/book/show/1230913.Excelsior_&quot;&gt;Excelsior!: The Amazing Life of Stan Lee&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;[4 stars] &lt;a href=&quot;https://www.goodreads.com/book/show/16255272-the-end-of-the-fucking-world&quot;&gt;The End of the Fucking World&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;[4 stars] &lt;a href=&quot;https://www.goodreads.com/book/show/8387565-30-second-economics&quot;&gt;30-Second Economics&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;[3 stars] &lt;a href=&quot;https://www.goodreads.com/book/show/9249686-the-grand-design&quot;&gt;The Grand Design&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;[5 stars] &lt;a href=&quot;https://www.goodreads.com/book/show/36327112-travelers-in-the-third-reich&quot;&gt;Travelers in the Third Reich: The Rise of Fascism: 1919–1945&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I tend to read a lot of books on finance, physics, history and software development, with some fiction and comics mixed in from time to time. Of the books above, I’d most recommend &lt;a href=&quot;https://www.goodreads.com/book/show/36327112-travelers-in-the-third-reich&quot;&gt;Travelers in the Third Reich: The Rise of Fascism: 1919–1945&lt;/a&gt; and &lt;a href=&quot;https://www.goodreads.com/book/show/18868371-an-astronaut-s-guide-to-life-on-earth&quot;&gt;An Astronaut’s Guide to Life on Earth&lt;/a&gt;. The former is an eye-opening look at what it was like to live and travel in Germany between the two world wars, and really gives you perspective on how the second world war came to be. The latter is an inspiring autobiography of Chris Hadfield, a Canadian astronaut who dreamed of becoming an astronaut long before it was even possible for Canadians.&lt;/p&gt;

&lt;p&gt;Anyways, I thought it would be cool to add a sort-of “bookshelf” to my website, and noticed that there weren’t any solid clients for the &lt;a href=&quot;https://www.goodreads.com/api&quot;&gt;Goodreads API&lt;/a&gt; written in Go, so I decided to put one together at &lt;a href=&quot;https://github.com/KyleBanks/goodreads&quot;&gt;github.com/KyleBanks/goodreads&lt;/a&gt;. It’s pretty straightforward, but first you’ll need to sign up for a &lt;a href=&quot;https://www.goodreads.com/api/keys&quot;&gt;developer key at goodreads.com/api/keys&lt;/a&gt;. Once you’ve got that, you’re ready to go.&lt;/p&gt;

&lt;p&gt;First, you’ll want to initialize a &lt;strong&gt;goodreads.Client&lt;/strong&gt; using your developer key. Here’s how you might do that, using an &lt;strong&gt;API_KEY&lt;/strong&gt; environment variable:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
package main

import (
    &quot;os&quot;

    &quot;github.com/KyleBanks/goodreads&quot;
)

func main() {
    key := os.GetEnv(&quot;API_KEY&quot;)	
    c := goodreads.NewClient(key)
}
&lt;/pre&gt;

&lt;p&gt;After that, you can make calls to the API using the corresponding function. For instance, to call the &lt;a href=&quot;https://www.goodreads.com/api/index#user.show&quot;&gt;user.show&lt;/a&gt; API endpoint, you’d use the &lt;strong&gt;UserShow&lt;/strong&gt; function:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
u, err := c.UserShow(&quot;user-id&quot;)
&lt;/pre&gt;

&lt;p&gt;To quickly put together the markdown for the list of books above, here’s what I did:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
reviews, _ := c.ReviewList(&quot;38763538&quot;, &quot;read&quot;, &quot;date_read&quot;, &quot;&quot;, &quot;d&quot;, 1, 11)
for i, rev := range reviews {
	fmt.Printf(&quot; %d. [%d stars] [%s](%s)\n&quot;, i+1, rev.Rating, rev.Book.Title, rev.Book.Link)
}
&lt;/pre&gt;

&lt;p&gt;This loads the &lt;em&gt;read&lt;/em&gt; bookshelf for my Goodreads user ID, sorted by &lt;em&gt;date_read&lt;/em&gt; in descending order, limiting to the &lt;em&gt;11&lt;/em&gt; books I’ve read this year. It’s pretty straightforward, but there’s a lot of work to do in order to &lt;a href=&quot;https://www.goodreads.com/api/index&quot;&gt;fill in all the API endpoints that Goodreads provides&lt;/a&gt;. If you’re interested, I’d be very grateful to receive pull requests at &lt;a href=&quot;https://github.com/KyleBanks/goodreads&quot;&gt;github.com/KyleBanks/goodreads&lt;/a&gt; and to hear what you’re using the client for!&lt;/p&gt;
</description>
            </item>
        
		    <item>
                <title>Loading Unlabeled Images with ImageDataGenerator flow_from_directory in Keras</title>
                <link>https://kylewbanks.com/blog/loading-unlabeled-images-with-imagedatagenerator-flowfromdirectory-keras</link>
                <guid isPermaLink="true">https://kylewbanks.com/blog/loading-unlabeled-images-with-imagedatagenerator-flowfromdirectory-keras</guid>
                <pubDate>Fri, 25 Jan 2019 00:00:00 +0000</pubDate>
                <description>&lt;p&gt;The &lt;a href=&quot;https://keras.io/preprocessing/image/&quot;&gt;ImageDataGenerator class in Keras&lt;/a&gt; is a really valuable tool. I’ve recently written about using it for &lt;a href=&quot;https://kylewbanks.com/blog/train-validation-split-with-imagedatagenerator-keras&quot;&gt;training/validation splitting of images&lt;/a&gt;, and it’s also helpful for data augmentation by applying random permutations to your image dataset in an effort to reduce overfitting and improve the generalized performance of your models.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://keras.io/preprocessing/image/#flow_from_directory&quot;&gt;flow_from_directory&lt;/a&gt; function is particularly helpful as it allows you to load batches of images from a labeled directory structure, where the name of each subdirectory is the class name for a classification task. For instance, you might use a directory structure like so for the &lt;a href=&quot;http://yann.lecun.com/exdb/mnist/&quot;&gt;MNIST&lt;/a&gt; dataset:&lt;/p&gt;

&lt;pre&gt;
train/
	0/
	1/
	2/
	3/
	4/
	5/
	6/
	7/
	8/
	9/
&lt;/pre&gt;

&lt;p&gt;In this case, each subdirectory of the &lt;strong&gt;train&lt;/strong&gt; directory contains images corresponding to that particular class (ie. classes &lt;strong&gt;0&lt;/strong&gt; through &lt;strong&gt;9&lt;/strong&gt;). Loading this dataset with &lt;strong&gt;ImageDataGenerator&lt;/strong&gt; could be accomplished like so:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
datagen = ImageDataGenerator()
train_data = datagen.flow_from_directory('./train')
&lt;/pre&gt;

&lt;p&gt;You’ll then see output like so, indicating the number of images and classes discovered:&lt;/p&gt;

&lt;pre&gt;
Found 1000 images belonging to 10 classes.
&lt;/pre&gt;

&lt;p&gt;Frequently however, you’ll also have a &lt;strong&gt;test&lt;/strong&gt; directory which doesn’t have subdirectories as you don’t know the classes of those images. Inside of &lt;strong&gt;test&lt;/strong&gt; is simply a variety of images of unknown class, and you can’t use the &lt;strong&gt;flow_from_directory&lt;/strong&gt; function like we did above as you’ll end up with the following issue:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
datagen = ImageDataGenerator()
train_data = datagen.flow_from_directory('./test')
&lt;/pre&gt;
&lt;pre&gt;
Found 0 images belonging to 0 classes.
&lt;/pre&gt;

&lt;p&gt;It can’t find any classes because &lt;strong&gt;test&lt;/strong&gt; has no subdirectories. Without classes it can’t load your images, as you see in the log output above. There is a workaround to this however, as you can specify the parent directory of the &lt;strong&gt;test&lt;/strong&gt; directory and specify that you only want to load the &lt;strong&gt;test&lt;/strong&gt; “class”:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
datagen = ImageDataGenerator()
test_data = datagen.flow_from_directory('.', classes=['test'])
&lt;/pre&gt;
&lt;pre&gt;
Found 1000 images belonging to 1 class.
&lt;/pre&gt;

&lt;p&gt;The &lt;strong&gt;classes&lt;/strong&gt; argument tells &lt;strong&gt;flow_from_directory&lt;/strong&gt; that you only want to load images of the specified class(es), in this case the &lt;strong&gt;test&lt;/strong&gt; “class”. Now &lt;strong&gt;test_data&lt;/strong&gt; will contain only the one &lt;strong&gt;test&lt;/strong&gt; “class”, allowing you to work with your test dataset just as you would the labeled training data from above.&lt;/p&gt;

&lt;p&gt;In fact, you can also use this trick to exclude subdirectories of your dataset for whatever reason. Going back to the MNIST problem above, if you only cared about recognizing digits &lt;strong&gt;0&lt;/strong&gt; through &lt;strong&gt;3&lt;/strong&gt;, you could do something like this:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
datagen = ImageDataGenerator()
train_data = datagen.flow_from_directory('./train', classes=['0', '1', '2', '3'])
&lt;/pre&gt;
&lt;pre&gt;
Found 400 images belonging to 4 classes.
&lt;/pre&gt;
</description>
            </item>
        
		    <item>
                <title>Training/Validation Split with ImageDataGenerator in Keras</title>
                <link>https://kylewbanks.com/blog/train-validation-split-with-imagedatagenerator-keras</link>
                <guid isPermaLink="true">https://kylewbanks.com/blog/train-validation-split-with-imagedatagenerator-keras</guid>
                <pubDate>Tue, 22 Jan 2019 00:00:00 +0000</pubDate>
                <description>&lt;p&gt;&lt;a href=&quot;https://keras.io/&quot;&gt;Keras&lt;/a&gt; comes bundled with many helpful utility functions and classes to accomplish all kinds of common tasks in your machine learning pipelines. One commonly used class is the &lt;a href=&quot;https://keras.io/preprocessing/image/&quot;&gt;ImageDataGenerator&lt;/a&gt;. As the documentation explains:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Generate batches of tensor image data with real-time data augmentation. The data will be looped over (in batches).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Until recently though, you were on your own to put together your training and validation datasets, for instance by creating two separate folder structures for your images to be used in conjunction with the &lt;a href=&quot;https://keras.io/preprocessing/image/#flow_from_directory&quot;&gt;flow_from_directory&lt;/a&gt; function.&lt;/p&gt;

&lt;p&gt;For example, the old way would be to do something like so:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
TRAIN_DIR = './datasets/training'
VALIDATION_DIR = './datasets/validation'

datagen = ImageDataGenerator(rescale=1./255)

train_generator = datagen.flow_from_directory(TRAIN_DIR)
val_generator = datagen.flow_from_directory(VALIDATION_DIR)
&lt;/pre&gt;

&lt;p&gt;Recently however (&lt;a href=&quot;https://github.com/keras-team/keras/pull/9745&quot;&gt;here’s the pull request, if you’re curious&lt;/a&gt;), a new &lt;strong&gt;validation_split&lt;/strong&gt; parameter was added to the &lt;strong&gt;ImageDataGenerator&lt;/strong&gt; that allows you to randomly split a subset of your training data into a validation set, by specifying the percentage you want to allocate to the validation set:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
datagen = ImageDataGenerator(validation_split=0.2, rescale=1./255)
&lt;/pre&gt;

&lt;p&gt;Then when you invoke &lt;strong&gt;flow_from_directory&lt;/strong&gt;, you pass the &lt;strong&gt;subset&lt;/strong&gt; parameter specifying which set you want:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
train_generator = datagen.flow_from_directory(
    TRAIN_DIR, 
    subset='training'
)

val_generator = datagen.flow_from_directory(
    TRAIN_DIR,
    subset='validation'
)
&lt;/pre&gt;

&lt;p&gt;You’ll note that both generators are being loaded from the &lt;strong&gt;TRAIN_DIR&lt;/strong&gt;, the only difference is one uses the &lt;strong&gt;training&lt;/strong&gt; subset and the other uses the &lt;strong&gt;validation&lt;/strong&gt; subset.&lt;/p&gt;

&lt;p&gt;And that’s all, it’s as easy as specifying the two parameters as needed. Now that you have your training and validation sets, did you know you can also use the &lt;a href=&quot;/blog/loading-unlabeled-images-with-imagedatagenerator-flowfromdirectory-keras&quot;&gt;ImageDataGenerator to load unlabeled images, such as an unlabeled test dataset?&lt;/a&gt;&lt;/p&gt;
</description>
            </item>
        
		    <item>
                <title>Running Multiple make Targets Concurrently</title>
                <link>https://kylewbanks.com/blog/running-multiple-make-targets-concurrently</link>
                <guid isPermaLink="true">https://kylewbanks.com/blog/running-multiple-make-targets-concurrently</guid>
                <pubDate>Sat, 19 Jan 2019 00:00:00 +0000</pubDate>
                <description>&lt;p&gt;&lt;a href=&quot;https://www.gnu.org/software/make/manual/html_node/index.html#Top&quot;&gt;make&lt;/a&gt; is a widely used and powerful took for coordinating common tasks within a project, and you’ll often file a &lt;strong&gt;Makefile&lt;/strong&gt; sitting in the root of open source repositories, allowing you to quickly see how to perform common tasks such as running tests, compiling and running, etc. There is also a wealth of tooling around &lt;strong&gt;make&lt;/strong&gt;, one of my favorites being &lt;a href=&quot;https://github.com/tj/mmake&quot;&gt;Modern Make, or mmake&lt;/a&gt; by &lt;a href=&quot;https://github.com/tj&quot;&gt;TJ Holowaychuk&lt;/a&gt; which adds some niceties around &lt;strong&gt;make&lt;/strong&gt; without changing anything about the original command.&lt;/p&gt;

&lt;p&gt;If you’re unfamiliar with &lt;strong&gt;make&lt;/strong&gt;, or it’s just been a while, here’s a quick refresher. Create a &lt;strong&gt;Makefile&lt;/strong&gt; containing task definitions for your project. Here’s a relevant section of the &lt;a href=&quot;https://github.com/KyleBanks/whatsthecodeforthat.com/blob/master/Makefile&quot;&gt;Makefile&lt;/a&gt; for the website &lt;a href=&quot;https://whatsthecodeforthat.com&quot;&gt;https://whatsthecodeforthat.com&lt;/a&gt; that we’ll be working with later on:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
local-server:
	hugo server -D
.PHONY: local-server

local-browser:
	open http://localhost:1313
.PHONY: local-browser
&lt;/pre&gt;

&lt;p&gt;This &lt;strong&gt;Makefile&lt;/strong&gt; contains two targets, &lt;strong&gt;local-server&lt;/strong&gt; and &lt;strong&gt;local-browser&lt;/strong&gt;. The first, &lt;strong&gt;local-server&lt;/strong&gt; compiles the &lt;a href=&quot;https://gohugo.io/&quot;&gt;hugo&lt;/a&gt; project and runs a local server to host the compiled website. The second, &lt;strong&gt;local-browser&lt;/strong&gt;, simply opens the default browser to the hugo development server address on localhost.&lt;/p&gt;

&lt;p&gt;Executing either of these targets is then simply:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
$ make local-server
$ make local-browser
&lt;/pre&gt;

&lt;p&gt;But herein lays the problem and the purpose of this post, as &lt;strong&gt;local-server&lt;/strong&gt; is a blocking command which means I’m unable to run &lt;strong&gt;local-browser&lt;/strong&gt; right afterwards. To fix this, I could open a second terminal tab and use one for the server and one for opening the browser, but that’s pretty clunky and I generally have enough tabs as it is.&lt;/p&gt;

&lt;h2 id=&quot;make-concurrently&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make&lt;/code&gt; Concurrently&lt;/h2&gt;

&lt;p&gt;The solution is to run the two commands concurrently, using the &lt;strong&gt;-j&lt;/strong&gt; argument of &lt;strong&gt;make&lt;/strong&gt;:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
$ make -help
Usage: make [options] [target] ...
Options:
  ...
  -j [N], --jobs[=N]          Allow N jobs at once; infinite jobs with no arg.
&lt;/pre&gt;

&lt;p&gt;As the &lt;strong&gt;-help&lt;/strong&gt; description explains, &lt;strong&gt;-j&lt;/strong&gt; allows you to run a variable number of jobs (or targets) at once.&lt;/p&gt;

&lt;p&gt;This is how it looks in practice:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
$ make -j 2 local-server local-browser
&lt;/pre&gt;

&lt;p&gt;This command will run the two commands simultaneously, in this case starting the local server while concurrently opening the browser. Pretty handy, but we can even do one better by creating a new &lt;strong&gt;make&lt;/strong&gt; target that handles this. Back in the &lt;strong&gt;Makefile&lt;/strong&gt;:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
local:
	make -j 2 local-server local-browser
.PHONY: local

local-server:
	hugo server -D
.PHONY: local-server

local-browser:
	open http://localhost:1313
.PHONY: local-browser
&lt;/pre&gt;

&lt;p&gt;Nothing changed with &lt;strong&gt;local-server&lt;/strong&gt; or &lt;strong&gt;local-browser&lt;/strong&gt;, the only difference is a new &lt;strong&gt;local&lt;/strong&gt; target that recursively calls &lt;strong&gt;make&lt;/strong&gt; with the &lt;strong&gt;-j 2&lt;/strong&gt; argument and the two other targets. Now running the two commands concurrently is as simple as:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
$ make local
&lt;/pre&gt;

&lt;p&gt;There are a number of use cases for this kind of parallel functionality, but one of my favorites is to parallelize slow build processes (especially in legacy projects) to reduce wait time during clean, compilation, startup, etc.&lt;/p&gt;
</description>
            </item>
        
		    <item>
                <title>Using a Convolutional Neural Network to Play Conway's Game of Life with Keras</title>
                <link>https://kylewbanks.com/blog/conways-game-of-life-convolutional-neural-network-keras</link>
                <guid isPermaLink="true">https://kylewbanks.com/blog/conways-game-of-life-convolutional-neural-network-keras</guid>
                <pubDate>Wed, 02 Jan 2019 00:00:00 +0000</pubDate>
                <description>&lt;p&gt;The goal of this post is to train a neural network to play &lt;a href=&quot;https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life&quot;&gt;Conway’s Game of Life&lt;/a&gt; without explicitly teaching it the rules of the game.&lt;/p&gt;

&lt;p&gt;Speaking of which, if you’re not familiar with Conway’s Game of Life, the rules are as follows:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;blockquote&gt;
    &lt;blockquote&gt;
      &lt;p&gt;The universe of the Game of Life is an infinite, two-dimensional orthogonal grid of square cells, each of which is in one of two possible states, alive or dead, (or populated and unpopulated, respectively). Every cell interacts with its eight neighbours, which are the cells that are horizontally, vertically, or diagonally adjacent. At each step in time, the following transitions occur:&lt;/p&gt;

      &lt;ul&gt;
        &lt;li&gt;Any live cell with fewer than two live neighbors dies, as if by underpopulation.&lt;/li&gt;
        &lt;li&gt;Any live cell with two or three live neighbors lives on to the next generation.&lt;/li&gt;
        &lt;li&gt;Any live cell with more than three live neighbors dies, as if by overpopulation.&lt;/li&gt;
        &lt;li&gt;Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction.&lt;/li&gt;
      &lt;/ul&gt;

      &lt;p&gt;The initial pattern constitutes the seed of the system. The first generation is created by applying the above rules simultaneously to every cell in the seed; births and deaths occur simultaneously, and the discrete moment at which this happens is sometimes called a tick. Each generation is a pure function of the preceding one. The rules continue to be applied repeatedly to create further generations.&lt;/p&gt;

      &lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life#Rules&quot;&gt;Wikipedia, Conway’s Game of Life&lt;/a&gt;&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/blockquote&gt;
&lt;/blockquote&gt;

&lt;p&gt;Why do this? Mostly for fun, and to learn a little bit about convolutional neural networks. It’s probably overkill for Conway’s Game, but it’s still pretty interesting to see how it performs.&lt;/p&gt;

&lt;p&gt;Without further ado, let’s jump into it.&lt;/p&gt;

&lt;h2 id=&quot;game-logic&quot;&gt;Game Logic&lt;/h2&gt;

&lt;p&gt;The first thing to do is define a function that takes a game board as input and returns the next state. Luckily there are plenty of implementations available online, such as the following from &lt;a href=&quot;https://jakevdp.github.io/blog/2013/08/07/conways-game-of-life/&quot;&gt;https://jakevdp.github.io/blog/2013/08/07/conways-game-of-life/&lt;/a&gt;. Basically, it takes a game board matrix as input where &lt;strong&gt;0&lt;/strong&gt; represents a dead cell and &lt;strong&gt;1&lt;/strong&gt; represents a living cell, and returns a matrix of the same size but containing the state of each cell on the next iteration of the game.&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
import numpy as np

def life_step(X):
    live_neighbors = sum(np.roll(np.roll(X, i, 0), j, 1)
                     for i in (-1, 0, 1) for j in (-1, 0, 1)
                     if (i != 0 or j != 0))
    return (live_neighbors == 3) | (X &amp;amp; (live_neighbors == 2)).astype(int)
&lt;/pre&gt;

&lt;h2 id=&quot;generate-game-boards&quot;&gt;Generate Game Boards&lt;/h2&gt;

&lt;p&gt;With the game logic in place, the next thing we’ll want is some way to randomly generate game boards (frames) and a way to visualize them. &lt;strong&gt;generate_frames&lt;/strong&gt; creates &lt;strong&gt;num_frames&lt;/strong&gt; random game boards with a particular shape and a predefined probability of each cell being ‘alive’, and &lt;strong&gt;render_frames&lt;/strong&gt; draws image representations of two game boards side-by-side for comparison, where living cells are white and dead cells are black:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
import matplotlib.pyplot as plt

def generate_frames(num_frames, board_shape=(100,100), prob_alive=0.15):
    return np.array([
        np.random.choice([False, True], size=board_shape, p=[1-prob_alive, prob_alive])
        for _ in range(num_frames)
    ]).astype(int)

def render_frames(frame1, frame2):
    plt.subplot(1, 2, 1)
    plt.imshow(frame1.flatten().reshape(board_shape), cmap='gray')

    plt.subplot(1, 2, 2)
    plt.imshow(frame2.flatten().reshape(board_shape), cmap='gray')
&lt;/pre&gt;

&lt;p&gt;Let’s see what these frames look like:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
board_shape = (20, 20)
board_size = board_shape[0] * board_shape[1]
probability_alive = 0.15

frames = generate_frames(10, board_shape=board_shape, prob_alive=probability_alive)
print(frames.shape) # (num_frames, board_w, board_h)
&lt;/pre&gt;

&lt;pre&gt;
(10, 20, 20)
&lt;/pre&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
print(frames[0])
&lt;/pre&gt;

&lt;pre&gt;
[[0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0],
 [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
 [0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1],
 [1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
 [1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0],
 [0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0],
 [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
 [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0]])
&lt;/pre&gt;

&lt;p&gt;The following takes the integer representation of a game board from above, and renders it as an image. To the right it also renders the next state of the game board using the &lt;strong&gt;life_step&lt;/strong&gt; function:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
render_frames(frames[1], life_step(frames[1]))
&lt;/pre&gt;

&lt;p&gt;&lt;img src=&quot;/images/post/cnn_cgol_sample_frames.png&quot; alt=&quot;Sample frames of Conway's Game of Life&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;construct-a-training-and-validation-set&quot;&gt;Construct a Training and Validation Set&lt;/h2&gt;

&lt;p&gt;Now that we can generate data, we’ll generate training, validation and test sets.&lt;/p&gt;

&lt;p&gt;Each element in the &lt;strong&gt;y_train&lt;/strong&gt;/&lt;strong&gt;y_val&lt;/strong&gt;/&lt;strong&gt;y_test&lt;/strong&gt; arrays will represent the &lt;strong&gt;next&lt;/strong&gt; &lt;em&gt;Game of Life&lt;/em&gt; board for each board frame in &lt;strong&gt;X_train&lt;/strong&gt;/&lt;strong&gt;X_val&lt;/strong&gt;/&lt;strong&gt;X_test&lt;/strong&gt;.&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
def reshape_input(X):
    return X.reshape(X.shape[0], X.shape[1], X.shape[2], 1)

def generate_dataset(num_frames, board_shape, prob_alive):
    X = generate_frames(num_frames, board_shape=board_shape, prob_alive=prob_alive)
    X = reshape_input(X)
    y = np.array([
        life_step(frame) 
        for frame in X
    ])
    return X, y

train_size = 70000
val_size   = 10000
test_size  = 20000
&lt;/pre&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
print(&quot;Training Set:&quot;)
X_train, y_train = generate_dataset(train_size, board_shape, probability_alive)
print(X_train.shape)
print(y_train.shape)
&lt;/pre&gt;

&lt;pre&gt;
Training Set:
(70000, 20, 20, 1)
(70000, 20, 20, 1)
&lt;/pre&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
print(&quot;Validation Set:&quot;)
X_val, y_val = generate_dataset(val_size, board_shape, probability_alive)
print(X_val.shape)
print(y_val.shape)
&lt;/pre&gt;

&lt;pre&gt;
Validation Set:
(10000, 20, 20, 1)
(10000, 20, 20, 1)
&lt;/pre&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
print(&quot;Test Set:&quot;)
X_test, y_test = generate_dataset(test_size, board_shape, probability_alive)
print(X_test.shape)
print(y_test.shape)
&lt;/pre&gt;

&lt;pre&gt;
Test Set:
(20000, 20, 20, 1)
(20000, 20, 20, 1)
&lt;/pre&gt;

&lt;h2 id=&quot;build-a-convolutional-neural-network&quot;&gt;Build a Convolutional Neural Network&lt;/h2&gt;

&lt;p&gt;Now we can take a first crack at building a &lt;em&gt;Convolutional Neural Network&lt;/em&gt; using &lt;a href=&quot;https://keras.io/layers/convolutional/&quot;&gt;Keras&lt;/a&gt;. The key here is the &lt;strong&gt;kernel_size&lt;/strong&gt; of &lt;strong&gt;(3, 3)&lt;/strong&gt; and &lt;strong&gt;strides&lt;/strong&gt; of &lt;strong&gt;1&lt;/strong&gt;. This instructs the &lt;em&gt;CNN&lt;/em&gt; to look at a &lt;strong&gt;3x3&lt;/strong&gt; matrix of surrounding cells for each &lt;strong&gt;1&lt;/strong&gt; cell of the board it looks at, including the current cell itself.&lt;/p&gt;

&lt;p&gt;For example, if the following were a game board and we were at the middle cell &lt;strong&gt;x&lt;/strong&gt;, it would look at all the cells marked with an exclamation mark &lt;strong&gt;!&lt;/strong&gt; and the &lt;strong&gt;x&lt;/strong&gt; cell. It would then move along &lt;strong&gt;1&lt;/strong&gt; cell to the right, and do the same, repeating over and over until it’s looked at every cell, and its neighbors, of the entire board.&lt;/p&gt;

&lt;pre&gt;
0 0 0 0 0
0 ! ! ! 0 
0 ! x ! 0
0 ! ! ! 0 
0 0 0 0 0
&lt;/pre&gt;

&lt;p&gt;The rest of the network is pretty basic, so I won’t go into much detail about it. If you’re curious about anything, I’d recommend checking out the documentation for the class in question.&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Conv2D, MaxPool2D

# CNN Properties
filters = 50
kernel_size = (3, 3) # look at all 8 neighboring cells, plus itself
strides = 1
hidden_dims = 100

model = Sequential()
model.add(Conv2D(
    filters, 
    kernel_size,
    padding='same',
    activation='relu',
    strides=strides,
    input_shape=(board_shape[0], board_shape[1], 1)
))
model.add(Dense(hidden_dims))
model.add(Dense(1))
model.add(Activation('sigmoid'))

model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
&lt;/pre&gt;

&lt;p&gt;Let’s look at the model using the &lt;strong&gt;summary&lt;/strong&gt; function:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
model.summary()
&lt;/pre&gt;

&lt;pre&gt;
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_9 (Conv2D)            (None, 20, 20, 50)        500       
_________________________________________________________________
dense_17 (Dense)             (None, 20, 20, 100)       5100      
_________________________________________________________________
dense_18 (Dense)             (None, 20, 20, 1)         101       
_________________________________________________________________
activation_9 (Activation)    (None, 20, 20, 1)         0         
=================================================================
Total params: 5,701
Trainable params: 5,701
Non-trainable params: 0
_________________________________________________________________
&lt;/pre&gt;

&lt;h2 id=&quot;train-and-save-the-model&quot;&gt;Train and Save the Model&lt;/h2&gt;

&lt;p&gt;With the CNN defined, let’s train the model and save it to disk:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
def train(model, X_train, y_train, X_val, y_val, batch_size=50, epochs=2, filename_suffix=''):
    model.fit(
        X_train, y_train, 
        batch_size=batch_size, 
        epochs=epochs,
        validation_data=(X_val, y_val)
    )
    
    with open('cgol_cnn{}.json'.format(filename_suffix), 'w') as file:
        file.write(model.to_json())
    model.save_weights('cgol_cnn{}.h5'.format(filename_suffix))


train(model, X_train, y_train, X_val, y_val, filename_suffix='_basic')
&lt;/pre&gt;

&lt;pre&gt;
Train on 70000 samples, validate on 10000 samples
Epoch 1/2
70000/70000 [==============================] - 27s 388us/step 
    - loss: 0.1324 - acc: 0.9651 - val_loss: 0.0833 - val_acc: 0.9815
Epoch 2/2
70000/70000 [==============================] - 27s 383us/step 
    - loss: 0.0819 - acc: 0.9817 - val_loss: 0.0823 - val_acc: 0.9816
&lt;/pre&gt;

&lt;p&gt;This model achieves a little over 98% accuracy on both the training and validation sets, which is pretty good for a first pass. Let’s try to figure out where we’re making mistakes.&lt;/p&gt;

&lt;h2 id=&quot;try-it-out&quot;&gt;Try it Out&lt;/h2&gt;

&lt;p&gt;Let’s take a look at a prediction for a random game board and see how it does. First, generate a single game board and take a look at the correct subsequent frame:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
X, y = generate_dataset(1, board_shape=board_shape, prob_alive=probability_alive)

render_frames(X[0].flatten().reshape(board_shape), y)
&lt;/pre&gt;

&lt;p&gt;&lt;img src=&quot;/images/post/cnn_cgol_sample_frames_2.png&quot; alt=&quot;Sample Test Frame for Conway's Game of Life&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Next, let’s perform the prediction and see how many were cells were incorrectly predicted:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
pred = model.predict_classes(X)
print(np.count_nonzero(pred.flatten() - y.flatten()), &quot;incorrect cells.&quot;)
&lt;/pre&gt;

&lt;pre&gt;
4 incorrect cells.
&lt;/pre&gt;

&lt;p&gt;Next, let’s compare the correct next frame versus the predicted frame:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
render_frames(y, pred.flatten().reshape(board_shape))
&lt;/pre&gt;

&lt;p&gt;&lt;img src=&quot;/images/post/cnn_cgol_bad_prediction.png&quot; alt=&quot;First prediction of a Game of Life board using a Convolutional Neural Network&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It’s not terrible, but can you see where it failed? It appears to be failing to predict the cells around the edges of the game board. Take a look at the following where non-zero values indicate incorrect predictions:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
print(pred.flatten().reshape(board_shape) - y.flatten().reshape(board_shape))
&lt;/pre&gt;

&lt;pre&gt;
[[ 0  0  0  0  0  0  0 -1  0  0  0  0  0  0  0  0  0 -1 -1  0]
 [ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0]
 [ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0]
 [ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0]
 [ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0]
 [ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0]
 [ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0]
 [ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0]
 [ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0]
 [ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0]
 [ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0]
 [ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0]
 [ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0]
 [ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0]
 [ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0]
 [ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0]
 [ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0]
 [ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0]
 [ 0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0]
 [ 0  0  0  0  0  0 -1  0  0  0  0  0  0  0  0  0  0  0  0  0]]
&lt;/pre&gt;

&lt;p&gt;As you can see, all of the non-zero values are located on the edges of the game board. Let’s take a look at the full testing set and see if that observation holds true.&lt;/p&gt;

&lt;h2 id=&quot;view-frequent-errors-using-test-set&quot;&gt;View Frequent Errors using Test Set&lt;/h2&gt;

&lt;p&gt;We’ll write a function that renders a heat map depicting where the model is making errors, and invoke it using the entire testing set:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
def view_prediction_errors(model, X, y):
    y_pred = model.predict_classes(X)
    sum_y_pred = np.sum(y_pred, axis=0).flatten().reshape(board_shape)
    sum_y = np.sum(y, axis=0).flatten().reshape(board_shape)

    plt.imshow(sum_y_pred - sum_y, cmap='hot', interpolation='nearest')
    plt.show()

view_prediction_errors(model, X_test, y_test)
&lt;/pre&gt;

&lt;p&gt;&lt;img src=&quot;/images/post/cnn_cgol_bad_prediction_heatmap.png&quot; alt=&quot;Heat map depicting all errors on the test set&quot; /&gt;&lt;/p&gt;

&lt;p&gt;All of the errors are around the edges, and the model performs the worst in the corners. This makes sense since the &lt;em&gt;CNN&lt;/em&gt; cannot look around the edges, but the &lt;em&gt;Game of Life&lt;/em&gt; logic in &lt;strong&gt;life_step&lt;/strong&gt; does. For example, consider the following. Currently, when looking at the edge cell &lt;strong&gt;x&lt;/strong&gt; below, the CNN only sees the &lt;strong&gt;x&lt;/strong&gt; and the &lt;strong&gt;!&lt;/strong&gt; cells:&lt;/p&gt;

&lt;pre&gt;
0 0 0 0 0
! ! 0 0 0 
x ! 0 0 0
! ! 0 0 0 
0 0 0 0 0
&lt;/pre&gt;

&lt;p&gt;But what we really want, and what &lt;strong&gt;life_step&lt;/strong&gt; is doing, is to look at the cells on the opposite side as well:&lt;/p&gt;

&lt;pre&gt;
0 0 0 0 0
! ! 0 0 ! 
x ! 0 0 !
! ! 0 0 ! 
0 0 0 0 0
&lt;/pre&gt;

&lt;p&gt;The same logic applies to corner cells, like so:&lt;/p&gt;

&lt;pre&gt;
x ! 0 0 !
! ! 0 0 ! 
0 0 0 0 0
0 0 0 0 0
! 0 0 0 !
&lt;/pre&gt;

&lt;p&gt;To fix this, the &lt;strong&gt;padding&lt;/strong&gt; property of the &lt;strong&gt;Conv2D&lt;/strong&gt; needs to somehow look at the opposite side of the game board. Alternatively, each input board could be pre-processed to pad the edges with the opposite side, and then &lt;strong&gt;Conv2D&lt;/strong&gt; can simply drop the first/last column and row. Since we’re at the mercy of &lt;em&gt;Keras&lt;/em&gt; and the &lt;strong&gt;padding&lt;/strong&gt; functionality it provides, which don’t support what we’re looking for, we’ll have to resort to adding our own padding.&lt;/p&gt;

&lt;h2 id=&quot;fixing-the-edge-issue-with-custom-padding&quot;&gt;Fixing the Edge Issue with Custom Padding&lt;/h2&gt;

&lt;p&gt;We need to pad each game board with the opposite value to simulate how &lt;strong&gt;life_step&lt;/strong&gt; looks across the game board for edge values. We can use &lt;strong&gt;np.pad&lt;/strong&gt; with &lt;strong&gt;mode=’wrap’&lt;/strong&gt; to accomplish this. For instance, consider the following array and the padded output below:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
x = np.array([
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
])

print(np.pad(x, (1, 1), mode='wrap'))
&lt;/pre&gt;

&lt;pre&gt;
[[9, 7, 8, 9, 7],
 [3, 1, 2, 3, 1],
 [6, 4, 5, 6, 4],
 [9, 7, 8, 9, 7],
 [3, 1, 2, 3, 1]]
&lt;/pre&gt;

&lt;p&gt;Notice now how the first column/row and the last column/row are mirrors of the opposite side of the original matrix, and the middle &lt;em&gt;3x3&lt;/em&gt; matrix is the original value &lt;strong&gt;x&lt;/strong&gt;. For example, cell &lt;strong&gt;[1][1]&lt;/strong&gt; has been replicated on the far side in cell &lt;strong&gt;[4][1]&lt;/strong&gt;, and likewise &lt;strong&gt;[0][1]&lt;/strong&gt; contains &lt;strong&gt;[3][1]&lt;/strong&gt;. In every direction, and even in the corners, the array has been wrapped to contain its opposite side, just how we want. This will allow the &lt;em&gt;CNN&lt;/em&gt; to consider the wrapped game board and properly handle the edge cases (pun intended).&lt;/p&gt;

&lt;p&gt;Now we can write a function to pad all our input matrices:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
def pad_input(X):
    return reshape_input(np.array([
        np.pad(x.reshape(board_shape), (1,1), mode='wrap')
        for x in X
    ]))

X_train_padded = pad_input(X_train)
X_val_padded = pad_input(X_val)
X_test_padded = pad_input(X_test)

print(X_train_padded.shape)
print(X_val_padded.shape)
print(X_test_padded.shape)
&lt;/pre&gt;

&lt;pre&gt;
(70000, 22, 22, 1)
(10000, 22, 22, 1)
(20000, 22, 22, 1)
&lt;/pre&gt;

&lt;p&gt;All the datasets are now padded with their wrapped columns/rows, allowing the CNN to look around the opposite side of the game board just like &lt;strong&gt;life_step&lt;/strong&gt; does. Because of this, each game board is now &lt;strong&gt;22x22&lt;/strong&gt; instead of the original &lt;strong&gt;20x20&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Next, the &lt;em&gt;CNN&lt;/em&gt; must be reconstructed to drop the padding values using &lt;strong&gt;padding=’valid’&lt;/strong&gt; (which tells &lt;strong&gt;Conv2D&lt;/strong&gt; to drop the edges, although thats not immediately obvious), and updated to handle the new &lt;strong&gt;input_shape&lt;/strong&gt;. This way when we pass in the padded &lt;strong&gt;22x22&lt;/strong&gt; game boards we still get &lt;strong&gt;20x20&lt;/strong&gt; game boards as output, since we’ll drop the first and last columns/rows. The rest remains identical:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
model_padded = Sequential()
model_padded.add(Conv2D(
    filters, 
    kernel_size,
    padding='valid',
    activation='relu',
    strides=strides,
    input_shape=(board_shape[0] + 2, board_shape[1] + 2, 1)
))
model_padded.add(Dense(hidden_dims))
model_padded.add(Dense(1))
model_padded.add(Activation('sigmoid'))

model_padded.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
model_padded.summary()
&lt;/pre&gt;

&lt;pre&gt;
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_10 (Conv2D)           (None, 20, 20, 50)        500       
_________________________________________________________________
dense_19 (Dense)             (None, 20, 20, 100)       5100      
_________________________________________________________________
dense_20 (Dense)             (None, 20, 20, 1)         101       
_________________________________________________________________
activation_10 (Activation)   (None, 20, 20, 1)         0         
=================================================================
Total params: 5,701
Trainable params: 5,701
Non-trainable params: 0
_________________________________________________________________
&lt;/pre&gt;

&lt;p&gt;Now we can train using the padded inputs:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
train(
    model_padded, 
    X_train_padded, y_train, X_val_padded, y_val, 
    filename_suffix='_padded'
)
&lt;/pre&gt;

&lt;pre&gt;
Train on 70000 samples, validate on 10000 samples
Epoch 1/2
70000/70000 [==============================] - 27s 389us/step - loss: 0.0604 - acc: 0.9807 - val_loss: 4.5475e-04 - val_acc: 1.0000
Epoch 2/2
70000/70000 [==============================] - 27s 382us/step - loss: 1.7058e-04 - acc: 1.0000 - val_loss: 5.9932e-05 - val_acc: 1.0000
&lt;/pre&gt;

&lt;p&gt;Validation and training accuracy are up to 100% from the roughly 98% we got before adding the padding. Let’s see the test error:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
view_prediction_errors(model_padded, X_test_padded, y_test)
&lt;/pre&gt;

&lt;p&gt;&lt;img src=&quot;/images/post/cnn_cgol_good_prediction_heatmap.png&quot; alt=&quot;Final prediction heat map using padded inputs&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Perfect! The black heat map indicates that there is no variance in the values, meaning we successfully predicted every cell, for every game.&lt;/p&gt;

&lt;p&gt;And that’s all there is to it. This was a fun little exercise to play with convolutional neural networks, without requiring a big data set. Feel free to check it out at &lt;a href=&quot;https://github.com/KyleBanks/conways-gol-cnn&quot;&gt;github.com/KyleBanks/conways-gol-cnn&lt;/a&gt;.&lt;/p&gt;
</description>
            </item>
        
		    <item>
                <title>Introducing modoc, a Lightweight Framework for Large Markdown Documents</title>
                <link>https://kylewbanks.com/blog/introducing-modoc-lightweight-framework-for-large-markdown-documents</link>
                <guid isPermaLink="true">https://kylewbanks.com/blog/introducing-modoc-lightweight-framework-for-large-markdown-documents</guid>
                <pubDate>Sat, 26 May 2018 00:00:00 +0100</pubDate>
                <description>&lt;p&gt;I thoroughly enjoy writing and generally when I write, I do so using Markdown for formatting. Markdown is great because it can be easily exported to HTML, a PDF, Word Documents, etc. There’s great tooling around Markdown, abd it’s a well supported markup language.&lt;/p&gt;

&lt;p&gt;My only problem is when I’m writing larger documents, such as if you were to write book, you quickly end up with a massive, unwieldly document. A few problems that come to mind:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;If you want to go back and reorganize sections or chapters of your document it’s usually pretty difficult as you have to recreate your headings as the heading levels won’t match up.&lt;/li&gt;
  &lt;li&gt;How do you go about managing a table of contents? You could manually manage it, but updating the links and text, and maintaining order and depth of each heading is a pain.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What I wanted was a small, lightweight framework that can be used to organize a larger document into smaller, more manageable chunks, but still output to a single Markdown file complete with table of contents. That’s where &lt;a href=&quot;https://github.com/KyleBanks/modoc&quot;&gt;modoc&lt;/a&gt; comes in.&lt;/p&gt;

&lt;p&gt;With &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;modoc&lt;/code&gt; you simply create a directory structure where each directory has a &lt;strong&gt;TITLE&lt;/strong&gt; and &lt;strong&gt;README.md&lt;/strong&gt; file, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;modoc&lt;/code&gt; does all the rest. Here’s what the directory structure for the &lt;a href=&quot;https://github.com/KyleBanks/modoc/tree/master/examples/readme&quot;&gt;README document of the opensource modoc repository&lt;/a&gt; looks like:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ tree examples/readme/
examples/readme/
├── 1-features
│   ├── README.md
│   └── TITLE
├── 2-usage
│   ├── 1-install
│   │   ├── README.md
│   │   └── TITLE
│   ├── 2-command-line
│   │   ├── 1-init
│   │   │   ├── README.md
│   │   │   └── TITLE
│   │   ├── 2-compile
│   │   │   ├── README.md
│   │   │   └── TITLE
│   │   ├── README.md
│   │   └── TITLE
│   ├── 3-project-structure
│   │   ├── README.md
│   │   └── TITLE
│   ├── 4-examples
│   │   ├── README.md
│   │   └── TITLE
│   └── TITLE
├── 3-authors
│   ├── 1-contributing
│   │   ├── README.md
│   │   └── TITLE
│   ├── README.md
│   └── TITLE
├── 4-license
│   ├── README.md
│   └── TITLE
├── README.md
└── TITLE

11 directories, 23 files
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Directories are loaded into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;modoc&lt;/code&gt; recursively and in alphabetical order, and the titles, sections, and table of contents are created from there. In the example above, you end up with a document that looks like so:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# Features
...
# Usage
...
## Install
...
## Command-Line
...
### init
...
### compile
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;(Take a look at the full document at &lt;a href=&quot;https://github.com/KyleBanks/modoc&quot;&gt;github.com/KyleBanks/modoc&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;modoc&lt;/code&gt; also generates the table of contents at the top of the document, complete with links to each section, so you don’t have to worry about it:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;## Table of Contents

- [Features](#features)
- [Usage](#usage)
   - [Install](#install)
   - [Command Line](#command-line)
      - [init](#init)
      - [compile](#compile)
   - [Project Structure](#project-structure)
   - [Examples](#examples)
- [Authors](#authors)
   - [Contributing](#contributing)
- [License](#license)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This makes it really easy to structure and organize larger writing projects without having a full-blown framework to get in your way. Check it out on GitHub at &lt;a href=&quot;https://github.com/KyleBanks/modoc&quot;&gt;github.com/KyleBanks/modoc&lt;/a&gt; and try it for yourself. If you have any ideas or run into trouble, don’t hesitate to &lt;a href=&quot;https://github.com/KyleBanks/modoc/issues/new&quot;&gt;create an issue&lt;/a&gt;!&lt;/p&gt;
</description>
            </item>
        
		    <item>
                <title>Transfer Learning and Retraining Inception/MobileNet with TensorFlow and Docker</title>
                <link>https://kylewbanks.com/blog/tutorial-transfer-learning-retraining-inception-mobilenet-with-tensorflow-and-docker</link>
                <guid isPermaLink="true">https://kylewbanks.com/blog/tutorial-transfer-learning-retraining-inception-mobilenet-with-tensorflow-and-docker</guid>
                <pubDate>Sat, 09 Dec 2017 00:00:00 +0000</pubDate>
                <description>&lt;p&gt;&lt;a href=&quot;https://www.tensorflow.org&quot;&gt;TensorFlow&lt;/a&gt; is a modern machine learning framework that provides tremendous power and opportunity to developers and data scientists. One of those opportunities is to use the concept of &lt;em&gt;Transfer Learning&lt;/em&gt; to reduce training time and complexity by repurposing a pre-trained model.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.tensorflow.org/tutorials/image_retraining&quot;&gt;From the official docs&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Modern object recognition models have millions of parameters and can take weeks to fully train. Transfer learning is a technique that shortcuts a lot of this work by taking a fully-trained model for a set of categories like ImageNet, and retrains from the existing weights for new classes. In this example we’ll be retraining the final layer from scratch, while leaving all the others untouched. For more information on the approach you can see &lt;a href=&quot;https://arxiv.org/pdf/1310.1531v1.pdf&quot;&gt;this paper on Decaf&lt;/a&gt;.&lt;/p&gt;

  &lt;p&gt;Though it’s not as good as a full training run, this is surprisingly effective for many applications, and can be run in as little as thirty minutes on a laptop, without requiring a GPU.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this tutorial we’ll learn how to utilize &lt;em&gt;Transfer Learning&lt;/em&gt; to repurpose a pre-trained &lt;a href=&quot;https://github.com/tensorflow/models/tree/master/research/inception&quot;&gt;Inception&lt;/a&gt; or &lt;a href=&quot;https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet_v1.md&quot;&gt;MobileNet&lt;/a&gt; model provided by TensorFlow to serve a new purpose.&lt;/p&gt;

&lt;p&gt;What’s unique about this tutorial however, is that we’ll do it all without installing TensorFlow, instead performing training and predictions entirely through &lt;a href=&quot;https://www.docker.com/&quot;&gt;Docker&lt;/a&gt;. Why? Because it simplifies the process of getting this working on multiple machines, whether that is multiple developers and data scientists, your continuous integration process, or your production pipelines. Performing training in Docker ensures that no matter what machine is used to train your models, it will work without additional setup.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you want to skip ahead and just get to work with the pre-built Docker images, head over to &lt;a href=&quot;https://github.com/KyleBanks/tensorflow-docker-retrain&quot;&gt;KyleBanks/tensorflow-docker-retrain&lt;/a&gt; on GitHub and follow the quick instructions there.&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;gathering-images&quot;&gt;Gathering Images&lt;/h3&gt;

&lt;p&gt;The first (and honestly, most challenging) step of any image classification problem is to gather the image dataset. For this tutorial we’ll reuse the &lt;a href=&quot;http://yann.lecun.com/exdb/mnist/&quot;&gt;MNIST database&lt;/a&gt; of handwritten digits (0-9), which contains 60,000 training examples and 10,000 testing examples. This saves considerable time in gathering and preparing a custom dataset, and lets us get right into the real work of training and predicting.&lt;/p&gt;

&lt;p&gt;In order to further reduce the amount of work we need to do to get started, I’ve converted the dataset into JPG format, which you can download and unzip from here: &lt;a href=&quot;https://s3.amazonaws.com/kylewbanks/mnist-jpegs.zip&quot;&gt;mnist-jpegs.zip&lt;/a&gt;. After downloading and unzipping you should have a directory structure like so:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;test-images/
    0/
    1/
    2/
    3/
    4/
    5/
    6/
    7/
    8/  
    9/ 
train-images/
    0/
    1/
    2/
    3/
    4/
    5/
    6/
    7/
    8/  
    9/ 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Within these directories you’ll find thousands of &lt;strong&gt;28x28&lt;/strong&gt; images that look like so:&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;MNIST sample 0&quot; src=&quot;/images/post/tensorflow-mnist-0.jpg&quot; width=&quot;28&quot; height=&quot;28&quot; /&gt;
&lt;img alt=&quot;MNIST sample 6&quot; src=&quot;/images/post/tensorflow-mnist-6.jpg&quot; width=&quot;28&quot; height=&quot;28&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The way TensorFlow expects images to be laid out is exactly as seen in the directory structure above: one folder per label, each containing the appropriate images. In this case our labels are the digits 0 through 9, so we have a folder for each. The &lt;strong&gt;test-images&lt;/strong&gt; and &lt;strong&gt;train-images&lt;/strong&gt; folders are going to be used by us to separate our training images from the images we’ll test on, and are not important to TensorFlow necessarily.&lt;/p&gt;

&lt;p&gt;If you have your own image dataset that you want to work with, please feel free to do so! You’ll simply need to structure it like you see above, one folder per label where the folder name is the label name. For instance, if we were classifying images of comic book characters we might have a directory structure of:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;iron-man/
captain-america/
green-lantern/
batman/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;training&quot;&gt;Training&lt;/h3&gt;

&lt;p&gt;Now that we have our dataset, it’s time to get to work. We’ll start by creating a Docker image to handle training: &lt;strong&gt;train-classifier/Dockerfile&lt;/strong&gt;. &lt;em&gt;It’s important to put this in the &lt;strong&gt;train-classifier&lt;/strong&gt; directory as we’ll be creating multiple Docker images for different purposes by the end of the tutorial.&lt;/em&gt;&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
FROM gcr.io/tensorflow/tensorflow:1.4.0

ENV IMAGE_SIZE 128
ENV OUTPUT_GRAPH tf_files/retrained_graph.pb
ENV OUTPUT_LABELS tf_files/retrained_labels.txt
ENV ARCHITECTURE mobilenet_0.50_${IMAGE_SIZE}
ENV TRAINING_STEPS 1000

VOLUME /output
VOLUME /input

RUN curl -O https://raw.githubusercontent.com/tensorflow/tensorflow/master/tensorflow/examples/image_retraining/retrain.py

ENTRYPOINT python -m retrain \
  --how_many_training_steps=&quot;${TRAINING_STEPS}&quot; \
  --model_dir=/output/tf_files/models/ \
  --output_graph=/output/&quot;${OUTPUT_GRAPH}&quot; \
  --output_labels=/output/&quot;${OUTPUT_LABELS}&quot; \
  --architecture=&quot;${ARCHITECTURE}&quot; \
  --image_dir=/input
&lt;/pre&gt;

&lt;p&gt;Let’s walk through this from top-to-bottom.&lt;/p&gt;

&lt;p&gt;First, we use the official &lt;strong&gt;TensorFlow v1.4.0&lt;/strong&gt; image (the latest at time of writing) as our base, which comes with TensorFlow preinstalled and configured for us, one of the many benefits of Docker.&lt;/p&gt;

&lt;p&gt;Next we define the default training parameters as environment variables which will allow us to eventually override them at runtime as necessary. We set our image size to &lt;strong&gt;128&lt;/strong&gt; pixels even though our images are &lt;strong&gt;28x28&lt;/strong&gt;, because that’s the minimum size allowed, meaning our images will be upscaled, which is fine because they are all being upscaled the same way. Next we define the output location of the trained graph and the labels text file that will be generated by the training script. For the &lt;strong&gt;ARCHITECTURE&lt;/strong&gt; you can see we’re using &lt;strong&gt;MobileNet&lt;/strong&gt; with a size of &lt;strong&gt;0.50&lt;/strong&gt; and the image size as the suffix. I’m using &lt;strong&gt;MobileNet&lt;/strong&gt; here in order to reduce training time and size of the trained model, but it does sacrifice some performance. If you wish to use &lt;strong&gt;Inception&lt;/strong&gt; you can set the value of &lt;strong&gt;ARCHITECTURE&lt;/strong&gt; to &lt;strong&gt;inception_v3&lt;/strong&gt;. For more on the architecture and what these values all mean, I recommend you read &lt;a href=&quot;https://www.tensorflow.org/tutorials/image_retraining#other_model_architectures&quot;&gt;Other Model Architectures&lt;/a&gt; from the official documentation. Finally we indicate 1000 training steps, which allows us to train quickly without doing a huge training cycle (the default is 4000), at the potential cost of performance. Generally once you have a good idea that your model will perform well you’ll want to play with increasing the training steps and training for longer to see if the improved performance is worth the increased training time.&lt;/p&gt;

&lt;p&gt;Next we mount two volumes, &lt;strong&gt;/output&lt;/strong&gt; and &lt;strong&gt;/input&lt;/strong&gt;. Volumes allow us to share data between the host machine and the Docker container. &lt;strong&gt;/output&lt;/strong&gt; will be used to retrieve the trained model and labels from the Docker container once training is complete, and &lt;strong&gt;/input&lt;/strong&gt; will be used to provide the Docker container with our training images. We’ll come back to these shortly.&lt;/p&gt;

&lt;p&gt;Now it’s time to retrieve the retraining script, which we do by downloading it from the &lt;a href=&quot;https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/image_retraining/retrain.py&quot;&gt;official TensorFlow repository&lt;/a&gt; on GitHub. We could write our own, but it’s definitely easier to start out with the existing training script until you need to do something custom.&lt;/p&gt;

&lt;p&gt;Finally, we define the entrypoint of the Docker container to be the retraining script invoked with our parameters. As you can see we are instructing the retraining script on how many training steps to perform, the output locations, the architecture to retrain, and the location of our training image set.&lt;/p&gt;

&lt;p&gt;With the Dockerfile created, we can go ahead and build the image:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
$ docker build -t train-classifier train-classifier/
&lt;/pre&gt;

&lt;p&gt;With the image built, it’s time to invoke it. Since the environment variables are all setup to match what we intend, all that we need to do is specify the location of the two volumes: &lt;strong&gt;/output&lt;/strong&gt; and &lt;strong&gt;/input&lt;/strong&gt;:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
$ docker run -it \  
    -v $(pwd)/output:/output \
    -v $(pwd)/train-images:/input
    train-classifier
&lt;/pre&gt;

&lt;p&gt;Here we’ve set &lt;strong&gt;/output&lt;/strong&gt; equal to a new &lt;strong&gt;output&lt;/strong&gt; directory in the present working directory, and &lt;strong&gt;/input&lt;/strong&gt; as the path to the &lt;strong&gt;train-images/&lt;/strong&gt; directory containing the MNIST training image dataset.&lt;/p&gt;

&lt;p&gt;If all goes well, you should eventually see output similar to:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;...
INFO:tensorflow: Step 980: Train accuracy = 96.0%
INFO:tensorflow: Step 980: Cross entropy = 0.122227
INFO:tensorflow: Step 980: Validation accuracy = 92.0% (N=100)
INFO:tensorflow: Step 990: Train accuracy = 97.0%
INFO:tensorflow: Step 990: Cross entropy = 0.164350
INFO:tensorflow: Validation accuracy = 93.0% (N=100)
INFO:tensorflow: Step 999: Train accuracy = 95.0%
INFO:tensorflow: Step 999: Cross entropy = 0.159146
INFO:tensorflow: Step 999: Validation accuracy = 95.0% (N=100)
INFO:tensorflow:Final test accuracy = 94.1% (N=6060)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; It may take 10-20 minutes to perform training, hence why we chose to use time-friendly variables in the Dockerfile environment configuration above.&lt;/p&gt;

&lt;h3 id=&quot;using-the-retrained-model-for-predictions&quot;&gt;Using the Retrained Model for Predictions&lt;/h3&gt;

&lt;p&gt;Now that the model is trained it’s ready to perform some predictions! Again we’ll create a Docker image to bundle the prediction logic which will be invoked against a folder containing images to predict - our &lt;strong&gt;test-images/&lt;/strong&gt; folder from the MNIST dataset in this case. Since these images were not used for training they will serve as a valid image set to test with.&lt;/p&gt;

&lt;p&gt;To start with let’s create a &lt;strong&gt;predictor/&lt;/strong&gt; folder beside the &lt;strong&gt;train-classifier/&lt;/strong&gt; folder, as these will be our two Docker images. Inside &lt;strong&gt;predictor/&lt;/strong&gt; let’s add a new Dockerfile:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
FROM gcr.io/tensorflow/tensorflow:1.4.0

ENV IMAGE_SIZE 128
ENV IMAGE_MEAN 0
ENV IMAGE_STD 255
ENV GRAPH_FILE retrained_graph.pb
ENV LABELS_FILE retrained_labels.txt
ENV INPUT_LAYER input
ENV OUTPUT_LAYER final_result

VOLUME /model
VOLUME /input

RUN curl -O https://raw.githubusercontent.com/tensorflow/tensorflow/master/tensorflow/examples/label_image/label_image.py
ADD predict.sh .

ENTRYPOINT [&quot;/bin/bash&quot;, &quot;predict.sh&quot;]
&lt;/pre&gt;

&lt;p&gt;Again, let’s walk through this line by line. We start off the same as before by using the standard TensorFlow Docker image as our base, specifying version &lt;strong&gt;1.4.0&lt;/strong&gt;, the latest at the time of writing.&lt;/p&gt;

&lt;p&gt;Next up we’re going to define the customizable runtime properties as environment variables, using defaults appropriate for this task. You’ll see we use the same image size as in training, and the same graph and label file names that our &lt;strong&gt;train-classifier&lt;/strong&gt; container created for us. What’s changed though is we now have a few new variables, namely &lt;strong&gt;IMAGE_MEAN&lt;/strong&gt;, &lt;strong&gt;IMAGE_STD&lt;/strong&gt;, &lt;strong&gt;INPUT_LAYER&lt;/strong&gt;, and &lt;strong&gt;OUTPUT_LAYER&lt;/strong&gt;. The image mean and std values specified simply match the defaults in the TensorFlow prediction script but allow you to tune them as needed, and the input and output layer names match the layer names in our trained model.&lt;/p&gt;

&lt;p&gt;Next we’ll mount two volumes just like we did in training, but this time we have &lt;strong&gt;/model&lt;/strong&gt; which maps to the folder containing the trained model and label files, and &lt;strong&gt;/input&lt;/strong&gt; which maps to the folder containing images to predict.&lt;/p&gt;

&lt;p&gt;Next up we download the &lt;a href=&quot;https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/label_image/label_image.py&quot;&gt;label_image.py&lt;/a&gt; script from the &lt;a href=&quot;https://github.com/tensorflow/tensorflow&quot;&gt;official TensorFlow repository&lt;/a&gt; and add our own &lt;strong&gt;predict.sh&lt;/strong&gt; script that we’ll see in a moment.&lt;/p&gt;

&lt;p&gt;Finally we define the entrypoint of the container to be the &lt;strong&gt;predict.sh&lt;/strong&gt; script below:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
#!/bin/bash
echo &quot;-------------------------------------------------&quot;
echo -e &quot;\n\n&quot;
env
echo -e &quot;\n\n&quot;
echo &quot;-------------------------------------------------&quot;
echo -e &quot;\n\nPredicting $@\n\n&quot;
echo &quot;-------------------------------------------------&quot;

python -m label_image \
    --input_width=&quot;$IMAGE_SIZE&quot; \
    --input_height=&quot;$IMAGE_SIZE&quot; \
    --input_mean=&quot;$IMAGE_MEAN&quot; \
    --input_std=&quot;$IMAGE_STD&quot; \
    --input_layer=&quot;$INPUT_LAYER&quot; \
    --output_layer=&quot;$OUTPUT_LAYER&quot; \
    --graph=/model/&quot;$GRAPH_FILE&quot; \
    --labels=/model/&quot;$LABELS_FILE&quot; \
    --image=/input/$@
&lt;/pre&gt;

&lt;p&gt;This bash script simply prints the environment variables and the name of the image we’re predicting, and then calls the &lt;strong&gt;label_image&lt;/strong&gt; script with the set configurations. This script is mostly just helpful to see what parameters you’re using and the image being predicted, and you can modify it as you see fit. Alternatively you could place the python script execution in the Dockerfile just like we did in the &lt;strong&gt;train-classifier&lt;/strong&gt; version - it’s all up to you.&lt;/p&gt;

&lt;p&gt;Alright, let’s build the predictor image:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
$ docker build -t predictor predictor/
&lt;/pre&gt;

&lt;p&gt;In a moment you should have a built predictor image that we can use to perform predictions. In order to predict, we’ll invoke the predictor by mounting the two required volumes, where &lt;strong&gt;/model&lt;/strong&gt; is the path to our &lt;strong&gt;output/tf_files&lt;/strong&gt; directory and &lt;strong&gt;/input&lt;/strong&gt; is the path to the test images folder containing the image to predict, and finally the name of the image to predict.&lt;/p&gt;

&lt;p&gt;For example, let’s predict &lt;strong&gt;test-images/5/1376.jpg&lt;/strong&gt;:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
$ docker run -it \
    -v $(pwd)/output/tf_files:/model \
    -v $(pwd)/test-images/5:/input \
    predictor 1376.jpg
&lt;/pre&gt;

&lt;p&gt;If all goes well you should get a response like so:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;-------------------------------------------------


Predicting 1376.jpg


-------------------------------------------------
5 0.953844
3 0.0283552
8 0.0168694
0 0.000464269
6 0.000233758
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What this tells us is that the label &lt;em&gt;5&lt;/em&gt; was predicted with 95% confidence, and in fact the predictor was correct. Go ahead and try it out on several images to see the results!&lt;/p&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Transfer Learning in Docker turns out to be rather straightforward (assuming you have some Docker experience), and greatly simplifies the setup process. Installing TensorFlow can be a painful process at times, so having to do so on you and your teams’ machines, as well as your production and staging environments is less than ideal. Docker simplifies the process and allows you to reuse the same Docker image on as many machines as you like, with no additional setup.&lt;/p&gt;

&lt;p&gt;Check out the &lt;a href=&quot;https://github.com/KyleBanks/tensorflow-docker-retrain&quot;&gt;project on GitHub at KyleBanks/tensorflow-docker-retrain&lt;/a&gt; and let me know what you think!&lt;/p&gt;

</description>
            </item>
        
		    <item>
                <title>OpenGL &amp; Go Tutorial Part 3: Implementing the Game</title>
                <link>https://kylewbanks.com/blog/tutorial-opengl-with-golang-part-3-implementing-the-game</link>
                <guid isPermaLink="true">https://kylewbanks.com/blog/tutorial-opengl-with-golang-part-3-implementing-the-game</guid>
                <pubDate>Sun, 12 Mar 2017 00:00:00 +0000</pubDate>
                <description>&lt;p&gt;&lt;em&gt;&lt;a href=&quot;/blog/tutorial-opengl-with-golang-part-1-hello-opengl&quot;&gt;Part 1: Hello, OpenGL&lt;/a&gt;&lt;/em&gt; | &lt;em&gt;&lt;a href=&quot;/blog/tutorial-opengl-with-golang-part-2-drawing-the-game-board&quot;&gt;Part 2: Drawing the Game Board&lt;/a&gt;&lt;/em&gt; | &lt;em&gt;&lt;a href=&quot;/blog/tutorial-opengl-with-golang-part-3-implementing-the-game&quot;&gt;Part 3: Implementing the Game&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The full source code of the tutorial is available on &lt;a href=&quot;https://github.com/KyleBanks/conways-gol&quot;&gt;GitHub&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Welcome back to the &lt;em&gt;OpenGL &amp;amp; Go Tutorial!&lt;/em&gt; If you haven’t gone through &lt;a href=&quot;/blog/tutorial-opengl-with-golang-part-1-hello-opengl&quot;&gt;Part 1&lt;/a&gt; and &lt;a href=&quot;[Part 2: Drawing the Game Board](/blog/tutorial-opengl-with-golang-part-2-drawing-the-game-board)&quot;&gt;Part 2&lt;/a&gt; you’ll definitely want to take a step back and check them out.&lt;/p&gt;

&lt;p&gt;At this point you should have a grid system created and a matrix of &lt;em&gt;cells&lt;/em&gt; to represent each unit of the grid. Now it’s time to implement &lt;em&gt;Conway’s Game of Life&lt;/em&gt; using the grid as the game board.&lt;/p&gt;

&lt;p&gt;Let’s get started!&lt;/p&gt;

&lt;h2 id=&quot;implement-conways-game&quot;&gt;Implement Conway’s Game&lt;/h2&gt;

&lt;p&gt;One of the keys to Conway’s game is that each cell must determine its next state based on the current state of the board, at the same time. This means that if Cell &lt;strong&gt;(X=3, Y=4)&lt;/strong&gt; changes state during its calculation, its neighbor at &lt;strong&gt;(X=4, Y=4)&lt;/strong&gt; must determine its own state based on what &lt;strong&gt;(X=3, Y=4)&lt;/strong&gt; &lt;em&gt;was&lt;/em&gt;, not what is has become. Basically, this means we must loop through the cells and determine their next state without modifying their current state before we draw, and then on the next loop of the game we apply the new state and repeat.&lt;/p&gt;

&lt;p&gt;In order to accomplish this, we’ll add two booleans to the &lt;strong&gt;cell&lt;/strong&gt; struct:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
type cell struct {
    drawable uint32

    alive     bool
    aliveNext bool

    x int
    y int
}
&lt;/pre&gt;

&lt;p&gt;Here we’ve added &lt;strong&gt;alive&lt;/strong&gt; and &lt;strong&gt;aliveNext&lt;/strong&gt;, the former being the cell’s current state and the later being the state it has calculated for the next turn.&lt;/p&gt;

&lt;p&gt;Now let’s add two functions that we’ll use to determine the cell’s state:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
// checkState determines the state of the cell for the next tick of the game.
func (c *cell) checkState(cells [][]*cell) {
    c.alive = c.aliveNext
    c.aliveNext = c.alive
    
    liveCount := c.liveNeighbors(cells)
    if c.alive {
        // 1. Any live cell with fewer than two live neighbours dies, as if caused by underpopulation.
        if liveCount &amp;lt; 2 {
            c.aliveNext = false
        }
        
        // 2. Any live cell with two or three live neighbours lives on to the next generation.
        if liveCount == 2 || liveCount == 3 {
            c.aliveNext = true
        }
        
        // 3. Any live cell with more than three live neighbours dies, as if by overpopulation.
        if liveCount &amp;gt; 3 {
            c.aliveNext = false
        }
    } else {
        // 4. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
        if liveCount == 3 {
            c.aliveNext = true
        }
    }
}

// liveNeighbors returns the number of live neighbors for a cell.
func (c *cell) liveNeighbors(cells [][]*cell) int {
    var liveCount int
    add := func(x, y int) {
        // If we're at an edge, check the other side of the board.
        if x == len(cells) {
            x = 0
        } else if x == -1 {
            x = len(cells) - 1
        }
        if y == len(cells[x]) {
            y = 0
        } else if y == -1 {
            y = len(cells[x]) - 1
        }
        
        if cells[x][y].alive {
            liveCount++
        }
    }
    
    add(c.x-1, c.y)   // To the left
    add(c.x+1, c.y)   // To the right
    add(c.x, c.y+1)   // up
    add(c.x, c.y-1)   // down
    add(c.x-1, c.y+1) // top-left
    add(c.x+1, c.y+1) // top-right
    add(c.x-1, c.y-1) // bottom-left
    add(c.x+1, c.y-1) // bottom-right
    
    return liveCount
}
&lt;/pre&gt;

&lt;p&gt;In &lt;strong&gt;checkState&lt;/strong&gt; we set the current state (&lt;strong&gt;alive&lt;/strong&gt;) equal to what we calculated on the last iteration (&lt;strong&gt;aliveNext&lt;/strong&gt;). Next we count the number of neighbors, and determine the &lt;strong&gt;aliveNext&lt;/strong&gt; state according to the rules of the game. The rules should be relatively clear and they’re documented in the code above, so I won’t go over them again here.&lt;/p&gt;

&lt;p&gt;What’s more interesting is the &lt;strong&gt;liveNeighbors&lt;/strong&gt; function where we return the number of neighbors to the current cell that are in an &lt;strong&gt;alive&lt;/strong&gt; state. We define an inner function called &lt;strong&gt;add&lt;/strong&gt; that will do some repetitive validation on X and Y coordinates. What it does is check if we’ve passed a number that exceeds the bounds of the board - for example, if cell &lt;strong&gt;(X=0, Y=5)&lt;/strong&gt; wants to check on its neighbor to the left, it has to wrap around to the other side of the board to cell &lt;strong&gt;(X=9, Y=5)&lt;/strong&gt;, and likewise for the Y-axis.&lt;/p&gt;

&lt;p&gt;Below the inner &lt;strong&gt;add&lt;/strong&gt; function we call &lt;strong&gt;add&lt;/strong&gt; with each of the cell’s eight neighbors, depicted below:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[
    [-, -, -],
    [N, N, N],
    [N, C, N],
    [N, N, N],
    [-, -, -]
]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this depiction, each cell labeled &lt;strong&gt;N&lt;/strong&gt; is a neighbor to &lt;strong&gt;C&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now in our &lt;strong&gt;main&lt;/strong&gt; function, where we have our core game loop, let’s call &lt;strong&gt;checkState&lt;/strong&gt; on each cell prior to drawing:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
func main() {
    ...
    
    for !window.ShouldClose() {
        for x := range cells {
            for _, c := range cells[x] {
                c.checkState(cells)
            }
        }

        draw(cells, window, program)
    }
}
&lt;/pre&gt;

&lt;p&gt;Now our core game logic is all set, we just need to modify the cell &lt;strong&gt;draw&lt;/strong&gt; function to skip drawing if the cell isn’t alive:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
func (c *cell) draw() {
    if !c.alive {
            return
    }

    gl.BindVertexArray(c.drawable)
    gl.DrawArrays(gl.TRIANGLES, 0, int32(len(square)/3))
}
&lt;/pre&gt;

&lt;p&gt;If you run the game now you’ll see a plain black screen, not the glorious simulation we’ve been working so hard to achieve. So why’s that? Well its because the simulation is working! None of our cells are alive, so none of them are drawing themselves.&lt;/p&gt;

&lt;p&gt;Let’s fix that. Back in &lt;strong&gt;makeCells&lt;/strong&gt; we’ll use a random number between &lt;strong&gt;0.0&lt;/strong&gt; and &lt;strong&gt;1.0&lt;/strong&gt; to set the initial state of the game. We’ll define a constant threshold of &lt;strong&gt;0.15&lt;/strong&gt; meaning that each cell has a 15% chance of starting in an alive state:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
import (
    &quot;math/rand&quot;
    &quot;time&quot;
    ...
)

const (
    ...
    
    threshold = 0.15
)


func makeCells() [][]*cell {
    rand.Seed(time.Now().UnixNano())

    cells := make([][]*cell, rows, rows)
    for x := 0; x &amp;lt; rows; x++ {
        for y := 0; y &amp;lt; columns; y++ {
            c := newCell(x, y)
            
            c.alive = rand.Float64() &amp;lt; threshold
            c.aliveNext = c.alive
            
            cells[x] = append(cells[x], c)
        }
    }

	return cells
}
&lt;/pre&gt;

&lt;p&gt;We start by adding two imports for the &lt;strong&gt;rand&lt;/strong&gt; (random) and &lt;strong&gt;time&lt;/strong&gt; packages, and defining our &lt;strong&gt;threshold&lt;/strong&gt; constant. Then in &lt;strong&gt;makeCells&lt;/strong&gt; we use the current time as the randomization seed, giving each game a unique starting state. You can also specify a particular seed value to always get an identical game, useful if you want to replay interesting simulations.&lt;/p&gt;

&lt;p&gt;Next in the loop, after creating a cell with the &lt;strong&gt;newCell&lt;/strong&gt; function we set its &lt;strong&gt;alive&lt;/strong&gt; state equal to the result of a random float, between &lt;strong&gt;0.0&lt;/strong&gt; and &lt;strong&gt;1.0&lt;/strong&gt;, being less than &lt;strong&gt;threshold&lt;/strong&gt; (&lt;strong&gt;0.15&lt;/strong&gt;). Again, this means each cell has a 15% chance of starting out alive. You can play with this number to increase or decrease the number of living cells at the outset of the game. We also set &lt;strong&gt;aliveNext&lt;/strong&gt; equal to &lt;strong&gt;alive&lt;/strong&gt;, otherwise we’ll get a massive die-off on the first iteration because &lt;strong&gt;aliveNext&lt;/strong&gt; will always be &lt;strong&gt;false&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;Now go ahead and give it a run, and you’ll likely see a quick flash of cells that you can’t make heads or tails of. The reason is that your computer is probably way too fast and is running through (or even finishing) the simulation before you have a chance to really see it.&lt;/p&gt;

&lt;p&gt;Let’s reduce the game speed by introducing a frames-per-second limitation in the main loop:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
const (
    ...
    
    fps = 2
)

func main() {
    ...
    
    for !window.ShouldClose() {
        t := time.Now()

        for x := range cells {
            for _, c := range cells[x] {
                c.checkState(cells)
            }
        }
        
        if err := draw(prog, window, cells); err != nil {
            panic(err)
        }
        
        time.Sleep(time.Second/time.Duration(fps) - time.Since(t))
    }
}
&lt;/pre&gt;

&lt;p&gt;At the top we define our &lt;strong&gt;fps&lt;/strong&gt; equal to 2, meaning we will perform 2 game iterations per second. We get a reference to the current time at the beginning of the loop, and at the end we sleep for one second divided by our FPS, minus the time that elapsed during the frame. For instance, at an FPS of 2 this means we want each loop to take 500 milliseconds. So, we divide one second by our FPS 2, giving us 500 milliseconds, but we also subtract the time that was spent processing the frame using &lt;strong&gt;time.Since(t)&lt;/strong&gt; where &lt;strong&gt;t&lt;/strong&gt; is the time we recorded at the beginning.&lt;/p&gt;

&lt;p&gt;Now you should be able to see some patterns, albeit very slowly. Increase the FPS to 10 and the size of the grid to 100x100 and you should see some really cool simulations:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
const (
    ...
    
    rows = 100
    columns = 100
    
    fps = 10
    
    ...
)
&lt;/pre&gt;

&lt;p&gt;Running now you should be able to see something along the lines of this:&lt;/p&gt;

&lt;div class=&quot;highlight center-text&quot;&gt;
    &lt;img src=&quot;/images/post/golang-opengl-conway-1.gif&quot; width=&quot;516&quot; height=&quot;536&quot; alt=&quot;Conway's Game of Life in OpenGL and Golang Tutorial - Demo Game&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Try playing with the constants to see how they impact the simulation - cool right? Your very first OpenGL application with Go!&lt;/p&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s Next?&lt;/h2&gt;

&lt;p&gt;This concludes the &lt;em&gt;OpenGL with Go Tutorial&lt;/em&gt;, but that doesn’t mean you should stop now. Here’s a few challenges to further improve your OpenGL (and Go) knowledge:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Give each cell a unique color.&lt;/li&gt;
  &lt;li&gt;Allow the user to specify, via command-line arguments, the grid size, frame rate, seed and threshold. You can see this one implemented on GitHub at &lt;a href=&quot;https://github.com/KyleBanks/conways-gol&quot;&gt;github.com/KyleBanks/conways-gol&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Change the shape of the cells into something more interesting, like a hexagon.&lt;/li&gt;
  &lt;li&gt;Use color to indicate the cell’s state - for example, make cells green on the first frame that they’re alive, and make them yellow if they’ve been alive more than three frames.&lt;/li&gt;
  &lt;li&gt;Automatically close the window if the simulation completes, meaning all cells are dead or no cells have changed state in the last two frames.&lt;/li&gt;
  &lt;li&gt;Move the shader source code out into their own files, rather than having them as string constants in the Go source code.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;Hopefully this tutorial has been helpful in gaining a foundation on OpenGL (and maybe even Go)! It was a lot of fun to make so I can only hope it was fun to go through and learn.&lt;/p&gt;

&lt;p&gt;As I’ve mentioned, OpenGL can be very intimidating, but it’s really not so bad once you get started. You just want to break down your goals into small, achievable steps, and enjoy each victory because while OpenGL isn’t always as tough as it looks, it can certainly be very unforgiving. One thing that I have found helpful when stuck on OpenGL issues was to understand that the way &lt;strong&gt;go-gl&lt;/strong&gt; is generated means you can always use C code as a reference, which is much more popular in tutorials around the internet. The only difference usually between the C and Go code is that functions in Go are prefixed with &lt;strong&gt;gl.&lt;/strong&gt; instead of &lt;strong&gt;gl&lt;/strong&gt;, and constants are prefixed with &lt;strong&gt;gl&lt;/strong&gt; instead of &lt;strong&gt;GL_&lt;/strong&gt;. This vastly increases the pool of knowledge you have to draw from!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href=&quot;/blog/tutorial-opengl-with-golang-part-1-hello-opengl&quot;&gt;Part 1: Hello, OpenGL&lt;/a&gt;&lt;/em&gt; | &lt;em&gt;&lt;a href=&quot;/blog/tutorial-opengl-with-golang-part-2-drawing-the-game-board&quot;&gt;Part 2: Drawing the Game Board&lt;/a&gt;&lt;/em&gt; | &lt;em&gt;&lt;a href=&quot;/blog/tutorial-opengl-with-golang-part-3-implementing-the-game&quot;&gt;Part 3: Implementing the Game&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The full source code of the tutorial is available on &lt;a href=&quot;https://github.com/KyleBanks/conways-gol&quot;&gt;GitHub&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;checkpoint&quot;&gt;Checkpoint&lt;/h2&gt;

&lt;p&gt;Here’s the final contents of &lt;strong&gt;main.go&lt;/strong&gt;:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
package main

import (
	&quot;fmt&quot;
	&quot;log&quot;
	&quot;math/rand&quot;
	&quot;runtime&quot;
	&quot;strings&quot;
	&quot;time&quot;

	&quot;github.com/go-gl/gl/v4.1-core/gl&quot; // OR: github.com/go-gl/gl/v2.1/gl
	&quot;github.com/go-gl/glfw/v3.2/glfw&quot;
)

const (
	width  = 500
	height = 500

	vertexShaderSource = `
		#version 410
		in vec3 vp;
		void main() {
			gl_Position = vec4(vp, 1.0);
		}
	` + &quot;\x00&quot;

	fragmentShaderSource = `
		#version 410
		out vec4 frag_colour;
		void main() {
			frag_colour = vec4(1, 1, 1, 1.0);
		}
	` + &quot;\x00&quot;

	rows    = 100
	columns = 100

	threshold = 0.15
	fps       = 10
)

var (
	square = []float32{
		-0.5, 0.5, 0,
		-0.5, -0.5, 0,
		0.5, -0.5, 0,

		-0.5, 0.5, 0,
		0.5, 0.5, 0,
		0.5, -0.5, 0,
	}
)

type cell struct {
	drawable uint32

	alive     bool
	aliveNext bool

	x int
	y int
}

func main() {
	runtime.LockOSThread()

	window := initGlfw()
	defer glfw.Terminate()
	program := initOpenGL()

	cells := makeCells()
	for !window.ShouldClose() {
		t := time.Now()

		for x := range cells {
			for _, c := range cells[x] {
				c.checkState(cells)
			}
		}

		draw(cells, window, program)

		time.Sleep(time.Second/time.Duration(fps) - time.Since(t))
	}
}

func draw(cells [][]*cell, window *glfw.Window, program uint32) {
	gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
	gl.UseProgram(program)

	for x := range cells {
		for _, c := range cells[x] {
			c.draw()
		}
	}

	glfw.PollEvents()
	window.SwapBuffers()
}

func makeCells() [][]*cell {
	rand.Seed(time.Now().UnixNano())

	cells := make([][]*cell, rows, rows)
	for x := 0; x &amp;lt; rows; x++ {
		for y := 0; y &amp;lt; columns; y++ {
			c := newCell(x, y)

			c.alive = rand.Float64() &amp;lt; threshold
			c.aliveNext = c.alive

			cells[x] = append(cells[x], c)
		}
	}

	return cells
}
func newCell(x, y int) *cell {
	points := make([]float32, len(square), len(square))
	copy(points, square)

	for i := 0; i &amp;lt; len(points); i++ {
		var position float32
		var size float32
		switch i % 3 {
		case 0:
			size = 1.0 / float32(columns)
			position = float32(x) * size
		case 1:
			size = 1.0 / float32(rows)
			position = float32(y) * size
		default:
			continue
		}

		if points[i] &amp;lt; 0 {
			points[i] = (position * 2) - 1
		} else {
			points[i] = ((position + size) * 2) - 1
		}
	}

	return &amp;amp;cell{
		drawable: makeVao(points),

		x: x,
		y: y,
	}
}

func (c *cell) draw() {
	if !c.alive {
		return
	}

	gl.BindVertexArray(c.drawable)
	gl.DrawArrays(gl.TRIANGLES, 0, int32(len(square)/3))
}

// checkState determines the state of the cell for the next tick of the game.
func (c *cell) checkState(cells [][]*cell) {
	c.alive = c.aliveNext
	c.aliveNext = c.alive

	liveCount := c.liveNeighbors(cells)
	if c.alive {
		// 1. Any live cell with fewer than two live neighbours dies, as if caused by underpopulation.
		if liveCount &amp;lt; 2 {
			c.aliveNext = false
		}

		// 2. Any live cell with two or three live neighbours lives on to the next generation.
		if liveCount == 2 || liveCount == 3 {
			c.aliveNext = true
		}

		// 3. Any live cell with more than three live neighbours dies, as if by overpopulation.
		if liveCount &amp;gt; 3 {
			c.aliveNext = false
		}
	} else {
		// 4. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
		if liveCount == 3 {
			c.aliveNext = true
		}
	}
}

// liveNeighbors returns the number of live neighbors for a cell.
func (c *cell) liveNeighbors(cells [][]*cell) int {
	var liveCount int
	add := func(x, y int) {
		// If we're at an edge, check the other side of the board.
		if x == len(cells) {
			x = 0
		} else if x == -1 {
			x = len(cells) - 1
		}
		if y == len(cells[x]) {
			y = 0
		} else if y == -1 {
			y = len(cells[x]) - 1
		}

		if cells[x][y].alive {
			liveCount++
		}
	}

	add(c.x-1, c.y)   // To the left
	add(c.x+1, c.y)   // To the right
	add(c.x, c.y+1)   // up
	add(c.x, c.y-1)   // down
	add(c.x-1, c.y+1) // top-left
	add(c.x+1, c.y+1) // top-right
	add(c.x-1, c.y-1) // bottom-left
	add(c.x+1, c.y-1) // bottom-right

	return liveCount
}

// initGlfw initializes glfw and returns a Window to use.
func initGlfw() *glfw.Window {
	if err := glfw.Init(); err != nil {
		panic(err)
	}
	glfw.WindowHint(glfw.Resizable, glfw.False)
	glfw.WindowHint(glfw.ContextVersionMajor, 4)
	glfw.WindowHint(glfw.ContextVersionMinor, 1)
	glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
	glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)

	window, err := glfw.CreateWindow(width, height, &quot;Conway's Game of Life&quot;, nil, nil)
	if err != nil {
		panic(err)
	}
	window.MakeContextCurrent()

	return window
}

// initOpenGL initializes OpenGL and returns an intiialized program.
func initOpenGL() uint32 {
	if err := gl.Init(); err != nil {
		panic(err)
	}
	version := gl.GoStr(gl.GetString(gl.VERSION))
	log.Println(&quot;OpenGL version&quot;, version)

	vertexShader, err := compileShader(vertexShaderSource, gl.VERTEX_SHADER)
	if err != nil {
		panic(err)
	}

	fragmentShader, err := compileShader(fragmentShaderSource, gl.FRAGMENT_SHADER)
	if err != nil {
		panic(err)
	}

	prog := gl.CreateProgram()
	gl.AttachShader(prog, vertexShader)
	gl.AttachShader(prog, fragmentShader)
	gl.LinkProgram(prog)
	return prog
}

// makeVao initializes and returns a vertex array from the points provided.
func makeVao(points []float32) uint32 {
	var vbo uint32
	gl.GenBuffers(1, &amp;amp;vbo)
	gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
	gl.BufferData(gl.ARRAY_BUFFER, 4*len(points), gl.Ptr(points), gl.STATIC_DRAW)

	var vao uint32
	gl.GenVertexArrays(1, &amp;amp;vao)
	gl.BindVertexArray(vao)
	gl.EnableVertexAttribArray(0)
	gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
	gl.VertexAttribPointer(0, 3, gl.FLOAT, false, 0, nil)

	return vao
}

func compileShader(source string, shaderType uint32) (uint32, error) {
	shader := gl.CreateShader(shaderType)

	csources, free := gl.Strs(source)
	gl.ShaderSource(shader, 1, csources, nil)
	free()
	gl.CompileShader(shader)

	var status int32
	gl.GetShaderiv(shader, gl.COMPILE_STATUS, &amp;amp;status)
	if status == gl.FALSE {
		var logLength int32
		gl.GetShaderiv(shader, gl.INFO_LOG_LENGTH, &amp;amp;logLength)

		log := strings.Repeat(&quot;\x00&quot;, int(logLength+1))
		gl.GetShaderInfoLog(shader, logLength, nil, gl.Str(log))

		return 0, fmt.Errorf(&quot;failed to compile %v: %v&quot;, source, log)
	}

	return shader, nil
}
&lt;/pre&gt;
</description>
            </item>
        
		    <item>
                <title>OpenGL &amp; Go Tutorial Part 2: Drawing the Game Board</title>
                <link>https://kylewbanks.com/blog/tutorial-opengl-with-golang-part-2-drawing-the-game-board</link>
                <guid isPermaLink="true">https://kylewbanks.com/blog/tutorial-opengl-with-golang-part-2-drawing-the-game-board</guid>
                <pubDate>Sun, 12 Mar 2017 00:00:00 +0000</pubDate>
                <description>&lt;p&gt;&lt;em&gt;&lt;a href=&quot;/blog/tutorial-opengl-with-golang-part-1-hello-opengl&quot;&gt;Part 1: Hello, OpenGL&lt;/a&gt;&lt;/em&gt; | &lt;em&gt;&lt;a href=&quot;/blog/tutorial-opengl-with-golang-part-2-drawing-the-game-board&quot;&gt;Part 2: Drawing the Game Board&lt;/a&gt;&lt;/em&gt; | &lt;em&gt;&lt;a href=&quot;/blog/tutorial-opengl-with-golang-part-3-implementing-the-game&quot;&gt;Part 3: Implementing the Game&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The full source code of the tutorial is available on &lt;a href=&quot;https://github.com/KyleBanks/conways-gol&quot;&gt;GitHub&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Welcome back to the &lt;em&gt;OpenGL &amp;amp; Go Tutorial!&lt;/em&gt; If you haven’t gone through &lt;a href=&quot;/blog/tutorial-opengl-with-golang-part-1-hello-opengl&quot;&gt;Part 1&lt;/a&gt; you’ll definitely want to take a step back and check it out.&lt;/p&gt;

&lt;p&gt;At this point you should be the proud creator of a magnificent white triangle, but we’re not in the business of using triangles as our game unit so it’s time to turn the triangle into a square, and then we’ll make an entire grid of them.&lt;/p&gt;

&lt;p&gt;Let’s get started!&lt;/p&gt;

&lt;h2 id=&quot;make-a-square-out-of-triangles&quot;&gt;Make a Square out of Triangles&lt;/h2&gt;

&lt;p&gt;Before we can make a square, let’s turn our triangle into a right-angle. Open up &lt;strong&gt;main.go&lt;/strong&gt; and change the &lt;strong&gt;triangle&lt;/strong&gt; definition to look like so:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
triangle = []float32{
    -0.5, 0.5, 0,
    -0.5, -0.5, 0,
    0.5, -0.5, 0,
}
&lt;/pre&gt;

&lt;p&gt;What we’ve done is move the X-coordinate of the top vertex to the left (&lt;strong&gt;-0.5&lt;/strong&gt;), giving us a triangle like so:&lt;/p&gt;

&lt;div class=&quot;highlight center-text&quot;&gt;
    &lt;img src=&quot;/images/post/golang-opengl-conway-4.png&quot; width=&quot;500&quot; height=&quot;518&quot; alt=&quot;Conway's Game of Life in OpenGL and Golang Tutorial - Right-Angle Triangle&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Easy enough, right? Now let’s make a square out of two of these. Let’s rename &lt;strong&gt;triangle&lt;/strong&gt; to &lt;strong&gt;square&lt;/strong&gt; and add a second, inverted right-angle triangle to the slice:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
square = []float32{
    -0.5, 0.5, 0,
    -0.5, -0.5, 0,
    0.5, -0.5, 0,

    -0.5, 0.5, 0,
    0.5, 0.5, 0,
    0.5, -0.5, 0,
}
&lt;/pre&gt;

&lt;p&gt;Note: You’ll also need to rename the two references to &lt;strong&gt;triangle&lt;/strong&gt; to be &lt;strong&gt;square&lt;/strong&gt;, namely in &lt;strong&gt;main&lt;/strong&gt; and &lt;strong&gt;draw&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Here we’ve doubled the number of points by adding a second set of three vertices to be our upper top-right triangle to complete the square. Run it for glory:&lt;/p&gt;

&lt;div class=&quot;highlight center-text&quot;&gt;
    &lt;img src=&quot;/images/post/golang-opengl-conway-5.png&quot; width=&quot;500&quot; height=&quot;530&quot; alt=&quot;Conway's Game of Life in OpenGL and Golang Tutorial - Two Triangles Make a Square&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Great, now we have the ability to draw a square! OpenGL isn’t so tough after all, is it?&lt;/p&gt;

&lt;h2 id=&quot;draw-a-grid-of-squares-covering-the-window&quot;&gt;Draw a Grid of Squares covering the Window&lt;/h2&gt;

&lt;p&gt;Now that we can draw one square, how about 100 of them? Let’s create a &lt;strong&gt;cell&lt;/strong&gt; struct to represent each unit of our grid so that we can be flexible in the number of squares we draw:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
type cell struct {
    drawable uint32
    
    x int
    y int
}
&lt;/pre&gt;

&lt;p&gt;The &lt;strong&gt;cell&lt;/strong&gt; contains a &lt;strong&gt;drawable&lt;/strong&gt; which is a square &lt;strong&gt;Vertex Array Object&lt;/strong&gt; just like the one we created above, and an X and Y coordinate to dictate where on the grid this cell resides.&lt;/p&gt;

&lt;p&gt;We’re also going to want two more constants that define the size and shape of our grid:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
const (
    ...
    
    rows = 10
    columns = 10
)
&lt;/pre&gt;

&lt;p&gt;Now let’s add a function to create the grid:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
func makeCells() [][]*cell {
    cells := make([][]*cell, rows, rows)
    for x := 0; x &amp;lt; rows; x++ {
        for y := 0; y &amp;lt; columns; y++ {
            c := newCell(x, y)
            cells[x] = append(cells[x], c)
        }
    }
    
    return cells
}
&lt;/pre&gt;

&lt;p&gt;Here we create a multi-dimensional slice to represent our game’s board, and populate each element of the matrix with a &lt;strong&gt;cell&lt;/strong&gt; using a new function called &lt;strong&gt;newCell&lt;/strong&gt; which we’ll write in just a moment.&lt;/p&gt;

&lt;p&gt;Before moving on, let’s take a moment to visualize what &lt;strong&gt;makeCells&lt;/strong&gt; is creating. We’re creating a slice that is equal in length to the number of rows on the grid, and each of these slices contains a slice of cells, equal in length to the number of columns. If we were to define &lt;strong&gt;rows&lt;/strong&gt; and &lt;strong&gt;columns&lt;/strong&gt; each equal to two, we’d create the following matrix:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[
    [cell, cell],
    [cell, cell]
]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We’re creating a much larger matrix that’s &lt;strong&gt;10x10&lt;/strong&gt; cells:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;[
    [cell, cell, cell, cell, cell, cell, cell, cell, cell, cell],
    [cell, cell, cell, cell, cell, cell, cell, cell, cell, cell],
    [cell, cell, cell, cell, cell, cell, cell, cell, cell, cell],
    [cell, cell, cell, cell, cell, cell, cell, cell, cell, cell],
    [cell, cell, cell, cell, cell, cell, cell, cell, cell, cell],
    [cell, cell, cell, cell, cell, cell, cell, cell, cell, cell],
    [cell, cell, cell, cell, cell, cell, cell, cell, cell, cell],
    [cell, cell, cell, cell, cell, cell, cell, cell, cell, cell],
    [cell, cell, cell, cell, cell, cell, cell, cell, cell, cell],
    [cell, cell, cell, cell, cell, cell, cell, cell, cell, cell]
]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now that the we understand the shape and representation of the matrix we’re creating, let’s have a look at &lt;strong&gt;newCell&lt;/strong&gt; which we use to actually populate the matrix:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
func newCell(x, y int) *cell {
    points := make([]float32, len(square), len(square))
    copy(points, square)

    for i := 0; i &amp;lt; len(points); i++ {
        var position float32
        var size float32
        switch i % 3 {
        case 0:
                size = 1.0 / float32(columns)
                position = float32(x) * size
        case 1:
                size = 1.0 / float32(rows)
                position = float32(y) * size
        default:
                continue
        }

        if points[i] &amp;lt; 0 {
                points[i] = (position * 2) - 1
        } else {
                points[i] = ((position + size) * 2) - 1
        }
    }

    return &amp;amp;cell{
        drawable: makeVao(points),

        x: x,
        y: y,
    }
}
&lt;/pre&gt;

&lt;p&gt;There’s quite a lot going on in this function so let’s break it down. The first thing we do is create a copy of our &lt;strong&gt;square&lt;/strong&gt; definition. This allows us to change its contents to customize the current cell’s position, without impacting any other cells that are also using the &lt;strong&gt;square&lt;/strong&gt; slice. Next we iterate over the &lt;strong&gt;points&lt;/strong&gt; copy and act based on the current index. We use a modulo operation to determine if we’re at an X (&lt;strong&gt;i % 3 == 0&lt;/strong&gt;) or Y (&lt;strong&gt;i % 3 == 1&lt;/strong&gt;) coordinate &lt;strong&gt;of the shape&lt;/strong&gt; (skipping Z since we’re operating in two dimensions) and determine the size (as a percentage of the entire game board) of the cell accordingly, as well as it’s position based on the X and Y coordinate of the cell &lt;strong&gt;on the game board&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Next, we modify the points which currently contain a combination of &lt;strong&gt;0.5&lt;/strong&gt;, &lt;strong&gt;0&lt;/strong&gt; and &lt;strong&gt;-0.5&lt;/strong&gt; as we defined them in the &lt;strong&gt;square&lt;/strong&gt; slice. If the point is less than zero, we set it equal to the position times 2 (because OpenGL coordinates have a range of 2, between &lt;strong&gt;-1&lt;/strong&gt; and &lt;strong&gt;1&lt;/strong&gt;), minus 1 to normalize to OpenGL coordinates. If the position is greater than or equal to zero, we do the same thing but add the size we calculated.&lt;/p&gt;

&lt;p&gt;The purpose of this is to set the scale of each cell so that it fills only its percentage of the game board. Since we have 10 rows and 10 columns, each cell will be given 10% of the width and 10% of the height of the game board.&lt;/p&gt;

&lt;p&gt;Finally, after all the points have been scaled and positioned, we create a &lt;strong&gt;cell&lt;/strong&gt; with the X and Y coordinate provided, and set the &lt;strong&gt;drawable&lt;/strong&gt; field equal to a &lt;strong&gt;Vertex Array Object&lt;/strong&gt; created from the &lt;strong&gt;points&lt;/strong&gt; slice we just manipulated.&lt;/p&gt;

&lt;p&gt;Alright, now in &lt;strong&gt;main&lt;/strong&gt; we can remove our call to &lt;strong&gt;makeVao&lt;/strong&gt; and replace it with a call to &lt;strong&gt;makeCells&lt;/strong&gt;. We’ll also change &lt;strong&gt;draw&lt;/strong&gt; to take the matrix of cells instead of a single &lt;strong&gt;vao&lt;/strong&gt;:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
func main() {
    ...
    
    // vao := makeVao(square)
    cells := makeCells()
    
    for !window.ShouldClose() {
        draw(cells, window, program)
    }
}

func draw(cells [][]*cell, window *glfw.Window, program uint32) {
    gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
    gl.UseProgram(program)

    // TODO

    glfw.PollEvents()
    window.SwapBuffers()
}
&lt;/pre&gt;

&lt;p&gt;Now we’ll need each cell to know how to draw itself. Let’s add a &lt;strong&gt;draw&lt;/strong&gt; function to the &lt;strong&gt;cell&lt;/strong&gt;:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
func (c *cell) draw() {
    gl.BindVertexArray(c.drawable)
    gl.DrawArrays(gl.TRIANGLES, 0, int32(len(square) / 3))
}
&lt;/pre&gt;

&lt;p&gt;This should look familiar, its nearly identical to how we were drawing the square &lt;strong&gt;vao&lt;/strong&gt; in &lt;strong&gt;draw&lt;/strong&gt; previously, the only difference being we &lt;strong&gt;BindVertexArray&lt;/strong&gt; using &lt;strong&gt;c.drawable&lt;/strong&gt;, which is the cell’s &lt;strong&gt;vao&lt;/strong&gt; we created in &lt;strong&gt;newCell&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Back in the main &lt;strong&gt;draw&lt;/strong&gt; function, we can loop over each cell and have it draw itself:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
func draw(cells [][]*cell, window *glfw.Window, program uint32) {
    gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
    gl.UseProgram(program)

    for x := range cells {
        for _, c := range cells[x] {
            c.draw()
        }
    }

    glfw.PollEvents()
    window.SwapBuffers()
}
&lt;/pre&gt;

&lt;p&gt;As you can see we loop over each of the cells and call its &lt;strong&gt;draw&lt;/strong&gt; function. If you run the application you should see the following:&lt;/p&gt;

&lt;div class=&quot;highlight center-text&quot;&gt;
    &lt;img src=&quot;/images/post/golang-opengl-conway-6.png&quot; width=&quot;500&quot; height=&quot;527&quot; alt=&quot;Conway's Game of Life in OpenGL and Golang Tutorial - Full Grid&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Is this what you expected? What we’ve done is create a square for each row and column on the grid, and colored it in, effectively filling the entire game board!&lt;/p&gt;

&lt;p&gt;We can see an visualize individual cells by commenting out the for-loop for a moment and doing the following:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
// for x := range cells {
//     for _, c := range cells[x] {
//         c.draw()
//     }
// }

cells[2][3].draw()
&lt;/pre&gt;

&lt;div class=&quot;highlight center-text&quot;&gt;
    &lt;img src=&quot;/images/post/golang-opengl-conway-7.png&quot; width=&quot;500&quot; height=&quot;532&quot; alt=&quot;Conway's Game of Life in OpenGL and Golang Tutorial - A Single Cell&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;This draws only the cell located at coordinate &lt;strong&gt;(X=2, Y=3)&lt;/strong&gt;. As you can see, each individual cell takes up a small portion of the game board, and is responsible for drawing its own space. We can also see that our game board has its origin, that is the &lt;strong&gt;(X=0, Y=0)&lt;/strong&gt; coordinate, in the bottom-left corner of the window. This is simply a result of the way our &lt;strong&gt;newCell&lt;/strong&gt; function calculates the position, and could be made to use the top-right, bottom-right, top-left, center, or any other position as its origin.&lt;/p&gt;

&lt;p&gt;Let’s go ahead and remove the &lt;strong&gt;cells[2][3].draw()&lt;/strong&gt; line and uncomment the for-loop, leaving us with the fully drawn grid we had above.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;Alright - we can now use two triangles to draw a square, and we have ourselves a game board! We should be proud, we’ve covered a lot of ground up to this point and to be completely honest, the hardest part is behind us now!&lt;/p&gt;

&lt;p&gt;Next up in &lt;a href=&quot;/blog/tutorial-opengl-with-golang-part-3-implementing-the-game&quot;&gt;Part 3&lt;/a&gt; we’ll implement the core game logic and see some cool simulations!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href=&quot;/blog/tutorial-opengl-with-golang-part-1-hello-opengl&quot;&gt;Part 1: Hello, OpenGL&lt;/a&gt;&lt;/em&gt; | &lt;em&gt;&lt;a href=&quot;/blog/tutorial-opengl-with-golang-part-2-drawing-the-game-board&quot;&gt;Part 2: Drawing the Game Board&lt;/a&gt;&lt;/em&gt; | &lt;em&gt;&lt;a href=&quot;/blog/tutorial-opengl-with-golang-part-3-implementing-the-game&quot;&gt;Part 3: Implementing the Game&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The full source code of the tutorial is available on &lt;a href=&quot;https://github.com/KyleBanks/conways-gol&quot;&gt;GitHub&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;checkpoint&quot;&gt;Checkpoint&lt;/h2&gt;

&lt;p&gt;Here’s the contents of &lt;strong&gt;main.go&lt;/strong&gt; at this point of the tutorial:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
package main

import (
	&quot;fmt&quot;
	&quot;log&quot;
	&quot;runtime&quot;
	&quot;strings&quot;

	&quot;github.com/go-gl/gl/v4.1-core/gl&quot; // OR: github.com/go-gl/gl/v2.1/gl
	&quot;github.com/go-gl/glfw/v3.2/glfw&quot;
)

const (
	width  = 500
	height = 500

	vertexShaderSource = `
		#version 410
		in vec3 vp;
		void main() {
			gl_Position = vec4(vp, 1.0);
		}
	` + &quot;\x00&quot;

	fragmentShaderSource = `
		#version 410
		out vec4 frag_colour;
		void main() {
			frag_colour = vec4(1, 1, 1, 1.0);
		}
	` + &quot;\x00&quot;

	rows    = 10
	columns = 10
)

var (
	square = []float32{
		-0.5, 0.5, 0,
		-0.5, -0.5, 0,
		0.5, -0.5, 0,

		-0.5, 0.5, 0,
		0.5, 0.5, 0,
		0.5, -0.5, 0,
	}
)

type cell struct {
	drawable uint32

	x int
	y int
}

func main() {
	runtime.LockOSThread()

	window := initGlfw()
	defer glfw.Terminate()
	program := initOpenGL()

	cells := makeCells()
	for !window.ShouldClose() {
		draw(cells, window, program)
	}
}

func draw(cells [][]*cell, window *glfw.Window, program uint32) {
	gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
	gl.UseProgram(program)

	for x := range cells {
		for _, c := range cells[x] {
			c.draw()
		}
	}

	glfw.PollEvents()
	window.SwapBuffers()
}

func makeCells() [][]*cell {
	cells := make([][]*cell, rows, rows)
	for x := 0; x &amp;lt; rows; x++ {
		for y := 0; y &amp;lt; columns; y++ {
			c := newCell(x, y)
			cells[x] = append(cells[x], c)
		}
	}

	return cells
}

func newCell(x, y int) *cell {
	points := make([]float32, len(square), len(square))
	copy(points, square)

	for i := 0; i &amp;lt; len(points); i++ {
		var position float32
		var size float32
		switch i % 3 {
		case 0:
			size = 1.0 / float32(columns)
			position = float32(x) * size
		case 1:
			size = 1.0 / float32(rows)
			position = float32(y) * size
		default:
			continue
		}

		if points[i] &amp;lt; 0 {
			points[i] = (position * 2) - 1
		} else {
			points[i] = ((position + size) * 2) - 1
		}
	}

	return &amp;amp;cell{
		drawable: makeVao(points),

		x: x,
		y: y,
	}
}

func (c *cell) draw() {
	gl.BindVertexArray(c.drawable)
	gl.DrawArrays(gl.TRIANGLES, 0, int32(len(square)/3))
}

// initGlfw initializes glfw and returns a Window to use.
func initGlfw() *glfw.Window {
	if err := glfw.Init(); err != nil {
		panic(err)
	}
	glfw.WindowHint(glfw.Resizable, glfw.False)
	glfw.WindowHint(glfw.ContextVersionMajor, 4)
	glfw.WindowHint(glfw.ContextVersionMinor, 1)
	glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
	glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)

	window, err := glfw.CreateWindow(width, height, &quot;Conway's Game of Life&quot;, nil, nil)
	if err != nil {
		panic(err)
	}
	window.MakeContextCurrent()

	return window
}

// initOpenGL initializes OpenGL and returns an intiialized program.
func initOpenGL() uint32 {
	if err := gl.Init(); err != nil {
		panic(err)
	}
	version := gl.GoStr(gl.GetString(gl.VERSION))
	log.Println(&quot;OpenGL version&quot;, version)

	vertexShader, err := compileShader(vertexShaderSource, gl.VERTEX_SHADER)
	if err != nil {
		panic(err)
	}

	fragmentShader, err := compileShader(fragmentShaderSource, gl.FRAGMENT_SHADER)
	if err != nil {
		panic(err)
	}

	prog := gl.CreateProgram()
	gl.AttachShader(prog, vertexShader)
	gl.AttachShader(prog, fragmentShader)
	gl.LinkProgram(prog)
	return prog
}

// makeVao initializes and returns a vertex array from the points provided.
func makeVao(points []float32) uint32 {
	var vbo uint32
	gl.GenBuffers(1, &amp;amp;vbo)
	gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
	gl.BufferData(gl.ARRAY_BUFFER, 4*len(points), gl.Ptr(points), gl.STATIC_DRAW)

	var vao uint32
	gl.GenVertexArrays(1, &amp;amp;vao)
	gl.BindVertexArray(vao)
	gl.EnableVertexAttribArray(0)
	gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
	gl.VertexAttribPointer(0, 3, gl.FLOAT, false, 0, nil)

	return vao
}

func compileShader(source string, shaderType uint32) (uint32, error) {
	shader := gl.CreateShader(shaderType)

	csources, free := gl.Strs(source)
	gl.ShaderSource(shader, 1, csources, nil)
	free()
	gl.CompileShader(shader)

	var status int32
	gl.GetShaderiv(shader, gl.COMPILE_STATUS, &amp;amp;status)
	if status == gl.FALSE {
		var logLength int32
		gl.GetShaderiv(shader, gl.INFO_LOG_LENGTH, &amp;amp;logLength)

		log := strings.Repeat(&quot;\x00&quot;, int(logLength+1))
		gl.GetShaderInfoLog(shader, logLength, nil, gl.Str(log))

		return 0, fmt.Errorf(&quot;failed to compile %v: %v&quot;, source, log)
	}

	return shader, nil
}
&lt;/pre&gt;
</description>
            </item>
        
		    <item>
                <title>OpenGL &amp; Go Tutorial Part 1: Hello, OpenGL</title>
                <link>https://kylewbanks.com/blog/tutorial-opengl-with-golang-part-1-hello-opengl</link>
                <guid isPermaLink="true">https://kylewbanks.com/blog/tutorial-opengl-with-golang-part-1-hello-opengl</guid>
                <pubDate>Sun, 12 Mar 2017 00:00:00 +0000</pubDate>
                <description>&lt;p&gt;&lt;em&gt;&lt;a href=&quot;/blog/tutorial-opengl-with-golang-part-1-hello-opengl&quot;&gt;Part 1: Hello, OpenGL&lt;/a&gt;&lt;/em&gt; | &lt;em&gt;&lt;a href=&quot;/blog/tutorial-opengl-with-golang-part-2-drawing-the-game-board&quot;&gt;Part 2: Drawing the Game Board&lt;/a&gt;&lt;/em&gt; | &lt;em&gt;&lt;a href=&quot;/blog/tutorial-opengl-with-golang-part-3-implementing-the-game&quot;&gt;Part 3: Implementing the Game&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The full source code of the tutorial is available on &lt;a href=&quot;https://github.com/KyleBanks/conways-gol&quot;&gt;GitHub&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://www.opengl.org/&quot;&gt;OpenGL&lt;/a&gt; is pretty much the gold standard for any kind of graphics work, from desktop GUIs to games to mobile applications and even the web, I can almost guarantee you’ve viewed something rendered by OpenGL today. However, regardless of how popular and useful OpenGL is, it can be quite intimidating to get started compared to more high-level graphics libraries.&lt;/p&gt;

&lt;p&gt;The purpose of this tutorial is to give you a starting point and basic understanding of OpenGL, and how to utilize it with &lt;a href=&quot;https://golang.org/&quot;&gt;Go&lt;/a&gt;. There are bindings for OpenGL in just about every language and Go is no exception with the &lt;a href=&quot;https://github.com/go-gl/gl&quot;&gt;go-gl&lt;/a&gt; packages, a full suite of generated OpenGL bindings for various OpenGL versions.&lt;/p&gt;

&lt;p&gt;The tutorial will walk through a few phases outlined below, with our end goal being to implement &lt;a href=&quot;https://en.wikipedia.org/wiki/Conway's_Game_of_Life&quot;&gt;Conway’s Game of Life&lt;/a&gt; using OpenGL to draw the game board in a desktop window. The full source code is available on GitHub at &lt;a href=&quot;https://github.com/KyleBanks/conways-gol&quot;&gt;github.com/KyleBanks/conways-gol&lt;/a&gt; so feel free to check it out if you get stuck or use it as a reference if you decide to go your own way.&lt;/p&gt;

&lt;p&gt;Before we get started, we need to get an understanding of what &lt;em&gt;Conway’s Game of Life&lt;/em&gt; actually is. Here’s the summary from &lt;a href=&quot;https://en.wikipedia.org/wiki/Conway's_Game_of_Life&quot;&gt;Wikipedia&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The Game of Life, also known simply as Life, is a cellular automaton devised by the British mathematician John Horton Conway in 1970.&lt;/p&gt;

  &lt;p&gt;The “game” is a zero-player game, meaning that its evolution is determined by its initial state, requiring no further input. One interacts with the Game of Life by creating an initial configuration and observing how it evolves, or, for advanced “players”, by creating patterns with particular properties.&lt;/p&gt;

  &lt;p&gt;Rules&lt;/p&gt;

  &lt;p&gt;The universe of the Game of Life is an infinite two-dimensional orthogonal grid of square cells, each of which is in one of two possible states, alive or dead, or “populated” or “unpopulated” (the difference may seem minor, except when viewing it as an early model of human/urban behaviour simulation or how one views a blank space on a grid). Every cell interacts with its eight neighbours, which are the cells that are horizontally, vertically, or diagonally adjacent. At each step in time, the following transitions occur:&lt;/p&gt;

  &lt;ol&gt;
    &lt;li&gt;Any live cell with fewer than two live neighbours dies, as if caused by underpopulation.&lt;/li&gt;
    &lt;li&gt;Any live cell with two or three live neighbours lives on to the next generation.&lt;/li&gt;
    &lt;li&gt;Any live cell with more than three live neighbours dies, as if by overpopulation.&lt;/li&gt;
    &lt;li&gt;Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.&lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;And without further ado, here’s a demo of what we’ll be building:&lt;/p&gt;

&lt;div class=&quot;highlight center-text&quot;&gt;
    &lt;img src=&quot;/images/post/golang-opengl-conway-1.gif&quot; width=&quot;516&quot; height=&quot;536&quot; alt=&quot;Conway's Game of Life in OpenGL and Golang Tutorial - Demo Game&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;In our simulation, a white cell indicates that it is alive, and black cell indicates that it is not.&lt;/p&gt;

&lt;h2 id=&quot;outline&quot;&gt;Outline&lt;/h2&gt;

&lt;p&gt;The tutorial is going to cover a lot of ground starting with the basics, however it will assume you have a minimal working knowledge of Go - at the very least you should know the basics of variables, slices, functions and structs, and have a working Go environment setup. I’ve developed the tutorial using Go version 1.8, but it should be compatible with previous versions as well. There is nothing particularly novel here in the Go implementation, so if you have experience in any similar programming language you should be just fine.&lt;/p&gt;

&lt;p&gt;As for the tutorial, here’s what we’ll be covering:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/tutorial-opengl-with-golang-part-1-hello-opengl&quot;&gt;Part 1: Hello, OpenGL&lt;/a&gt;: Install and Setup OpenGL and &lt;a href=&quot;http://www.glfw.org/&quot;&gt;GLFW&lt;/a&gt;, Draw a Triangle to the Window&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/blog/tutorial-opengl-with-golang-part-2-drawing-the-game-board&quot;&gt;Part 2: Drawing the Game Board&lt;/a&gt;: Make a Square out of Triangles, Draw a Grid of Squares covering the Window&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;blog/tutorial-opengl-with-golang-part-3-implementing-the-game&quot;&gt;Part 3: Implementing the Game&lt;/a&gt;: Implement Conway’s Game&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The final source code is available on &lt;a href=&quot;https://github.com/KyleBanks/conways-gol&quot;&gt;GitHub&lt;/a&gt; but each &lt;em&gt;Part&lt;/em&gt; includes a &lt;em&gt;Checkpoint&lt;/em&gt; at the bottom containing the code up until that point. If anything is ever unclear or if you feel lost, check the bottom of the post for the full source!&lt;/p&gt;

&lt;p&gt;Let’s get started!&lt;/p&gt;

&lt;h2 id=&quot;install-and-setup-opengl-and-glfw&quot;&gt;Install and Setup OpenGL and GLFW&lt;/h2&gt;

&lt;p&gt;We’ve introduced OpenGL but in order to use it we’re going to need a window to draw on to. &lt;a href=&quot;http://www.glfw.org/&quot;&gt;GLFW&lt;/a&gt; is a cross-platform API for OpenGL that allows us to create and reference a window, and is also provided by the &lt;a href=&quot;https://github.com/go-gl/glfw&quot;&gt;go-gl&lt;/a&gt; suite.&lt;/p&gt;

&lt;p&gt;The first thing we need to do is decide on an OpenGL version. For the purposes of this tutorial we’ll use &lt;strong&gt;OpenGL v4.1&lt;/strong&gt; but you can use &lt;strong&gt;v2.1&lt;/strong&gt; just fine if your system doesn’t have the latest OpenGL versions. In order to install OpenGL we’ll do the following:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
# For OpenGL 4.1
$ go get github.com/go-gl/gl/v4.1-core/gl

# Or 2.1
$ go get github.com/go-gl/gl/v2.1/gl
&lt;/pre&gt;

&lt;p&gt;Next up, let’s install GLFW:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
$ go get github.com/go-gl/glfw/v3.2/glfw
&lt;/pre&gt;

&lt;p&gt;With these two packages installed, we’re ready to get started! We’re going to start by creating &lt;strong&gt;main.go&lt;/strong&gt; and importing the packages (and a couple others we’ll need in a moment).&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
package main

import (
    &quot;log&quot;
    &quot;runtime&quot;

    &quot;github.com/go-gl/gl/v4.1-core/gl&quot; // OR: github.com/go-gl/gl/v2.1/gl
    &quot;github.com/go-gl/glfw/v3.2/glfw&quot;
)
&lt;/pre&gt;

&lt;p&gt;Next lets define the &lt;strong&gt;main&lt;/strong&gt; function, the purpose of which is to initialize OpenGL and GLFW and display the window:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
const (
    width  = 500
    height = 500
)

func main() {
    runtime.LockOSThread()

    window := initGlfw()
    defer glfw.Terminate()

    for !window.ShouldClose() {
        // TODO
    }
}

// initGlfw initializes glfw and returns a Window to use.
func initGlfw() *glfw.Window {
    if err := glfw.Init(); err != nil {
            panic(err)
    }
    
    glfw.WindowHint(glfw.Resizable, glfw.False)
    glfw.WindowHint(glfw.ContextVersionMajor, 4) // OR 2
    glfw.WindowHint(glfw.ContextVersionMinor, 1)
    glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
    glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)

    window, err := glfw.CreateWindow(width, height, &quot;Conway's Game of Life&quot;, nil, nil)
    if err != nil {
            panic(err)
    }
    window.MakeContextCurrent()

    return window
}
&lt;/pre&gt;

&lt;p&gt;Alright let’s take a minute to walk through this and see what’s going on. First we define a couple constants, &lt;strong&gt;width&lt;/strong&gt; and &lt;strong&gt;height&lt;/strong&gt; - these will determine the size of the window, in pixels.&lt;/p&gt;

&lt;p&gt;Next we have the &lt;strong&gt;main&lt;/strong&gt; function. Here we instruct the &lt;strong&gt;runtime&lt;/strong&gt; package to &lt;strong&gt;LockOSThread()&lt;/strong&gt;, which ensures we will always execute in the same operating system thread, which is important for GLFW which must always be called from the same thread it was initialized on. Speaking of which, next we call &lt;strong&gt;initGlfw&lt;/strong&gt; to get a window reference, and defer terminating. The window reference is then used in a for-loop where we say as long as the window should remain open, do &lt;em&gt;something&lt;/em&gt;. We’ll come back to this in a bit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;initGlfw&lt;/strong&gt; is our next function, wherein we call &lt;strong&gt;glfw.Init()&lt;/strong&gt; to initialize the GLFW package. After that, we define some global GLFW properties, including disabling window resizing and the properties of our OpenGL version. Next it’s time to create a &lt;strong&gt;glfw.Window&lt;/strong&gt; which is where we’re going to do our future drawing. We simply tell it the width and height we want, as well as a title, and then call &lt;strong&gt;window.MakeContextCurrent&lt;/strong&gt;, binding the window to our current thread. Finally, we return the window.&lt;/p&gt;

&lt;p&gt;If you build and run the program now, you should see… nothing. This makes sense, because we’re not actually doing anything with the window yet.&lt;/p&gt;

&lt;p&gt;Let’s fix that by defining a new function that initializes OpenGL:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
// initOpenGL initializes OpenGL and returns an intiialized program.
func initOpenGL() uint32 {
    if err := gl.Init(); err != nil {
            panic(err)
    }
    version := gl.GoStr(gl.GetString(gl.VERSION))
    log.Println(&quot;OpenGL version&quot;, version)

    prog := gl.CreateProgram()
    gl.LinkProgram(prog)
    return prog
}
&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;initOpenGL&lt;/strong&gt;, like our &lt;strong&gt;initGlfw&lt;/strong&gt; function above, initializes the OpenGL library and creates a &lt;em&gt;program&lt;/em&gt;. A program gives us a reference to store shaders, which can then be used for drawing. We’ll come back to this in a bit, but for now just know that OpenGL is initialized and we have a &lt;strong&gt;program&lt;/strong&gt; reference. We also print out the OpenGL version which can be helpful for debugging.&lt;/p&gt;

&lt;p&gt;Back in &lt;strong&gt;main&lt;/strong&gt;, let’s call this new function:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
func main() {
    runtime.LockOSThread()

    window := initGlfw()
    defer glfw.Terminate()
    
    program := initOpenGL()

    for !window.ShouldClose() {
        draw(window, program)
    }
}
&lt;/pre&gt;

&lt;p&gt;You’ll notice now that we have our &lt;strong&gt;program&lt;/strong&gt; reference, we’re calling a new &lt;strong&gt;draw&lt;/strong&gt; function within our core window loop. Eventually this function will draw all of our cells to visualize the game state, but for now its just going to clear the window so we get a black screen:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
func draw(window *glfw.Window, program uint32) {
    gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
    gl.UseProgram(prog)
    
    glfw.PollEvents()
    window.SwapBuffers()
}
&lt;/pre&gt;

&lt;p&gt;The first thing we do is call &lt;strong&gt;gl.Clear&lt;/strong&gt; to remove anything from the window that was drawn last frame, giving us a clean slate. Next we tell OpenGL to use our program reference, which currently does nothing. Finally, we tell GLFW to check if there were any mouse or keyboard events (which we won’t be handling in this tutorial) with the &lt;strong&gt;PollEvents&lt;/strong&gt; function, and tell the window to &lt;strong&gt;SwapBuffers&lt;/strong&gt;. &lt;a href=&quot;http://www.glfw.org/docs/latest/window_guide.html#buffer_swap&quot;&gt;Buffer swapping&lt;/a&gt; is important because GLFW (like many graphics libraries) uses double buffering, meaning everything you draw is actually drawn to an invisible canvas, and only put onto the visible canvas when you’re ready - which in this case, is indicated by calling &lt;strong&gt;SwapBuffers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Alright, we’ve covered a lot here, so let’s take a moment to see the fruits of our labors. Go ahead and run the program now, and you should get to see your first visual:&lt;/p&gt;

&lt;div class=&quot;highlight center-text&quot;&gt;
    &lt;img src=&quot;/images/post/golang-opengl-conway-2.png&quot; width=&quot;500&quot; height=&quot;519&quot; alt=&quot;Conway's Game of Life in OpenGL and Golang Tutorial - First Window&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Beautiful.&lt;/p&gt;

&lt;h2 id=&quot;draw-a-triangle-to-the-window&quot;&gt;Draw a Triangle to the Window&lt;/h2&gt;

&lt;p&gt;We’ve made some serious progress, even if it doesn’t look like much, but we still need to actually draw something. We’ll start by drawing a triangle, which may at first seem like it would be more difficult to draw than the squares we’re eventually going to, but you’d be mistaken for thinking so. What you may not know is that triangles are probably the easiest shapes to draw, and in fact we’ll eventually be making our squares out of triangles anyways.&lt;/p&gt;

&lt;p&gt;Alright so we want to draw a triangle, but how? Well, we draw shapes by defining the vertices of the shapes and providing them to OpenGL to be drawn. Let’s first define our triangle at the top of &lt;strong&gt;main.go&lt;/strong&gt;:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
var (
    triangle = []float32{
        0, 0.5, 0, // top
        -0.5, -0.5, 0, // left
        0.5, -0.5, 0, // right
    }
)
&lt;/pre&gt;

&lt;p&gt;This looks weird, but let’s break it down. First we have a slice of &lt;strong&gt;float32&lt;/strong&gt;, which is the datatype we always use when providing vertices to OpenGL. The slice contains 9 values, three for each vertex of a triangle. The top line, &lt;strong&gt;0, 0.5, 0&lt;/strong&gt;, is the top vertex represented as X, Y, and Z coordinates, the second line is the left vertex, and the third line is the right vertex. Each of these pairs of three represents the X, Y, and Z coordinates of the vertex relative to the center of the window, between &lt;strong&gt;-1 and 1&lt;/strong&gt;. So the top point has an X of zero because its X is in the center of the window, a Y of &lt;em&gt;0.5&lt;/em&gt; meaning it will be up one quarter (because the range is -1 to 1) of the window relative to the center of the window, and a Z of zero. For our purposes because we are drawing only in two dimensions, our Z values will always be zero. Now have a look at the left and right vertices and see if you can understand why they are defined as they are - it’s okay if it isn’t immediately clear, we’re going to see it on the screen soon enough so we’ll have a perfect visualization to play with.&lt;/p&gt;

&lt;p&gt;Okay, we have a triangle defined, but now we need to draw it. In order to draw it, we need what’s called a &lt;strong&gt;Vertex Array Object&lt;/strong&gt; or &lt;strong&gt;vao&lt;/strong&gt; which is created from a set of points (what we defined as our triangle), and can be provided to OpenGL to draw. Let’s create a function called &lt;strong&gt;makeVao&lt;/strong&gt; that we can provide with a slice of points and have it return a pointer to an OpenGL vertex array object:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
// makeVao initializes and returns a vertex array from the points provided.
func makeVao(points []float32) uint32 {
    var vbo uint32
    gl.GenBuffers(1, &amp;amp;vbo)
    gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
    gl.BufferData(gl.ARRAY_BUFFER, 4*len(points), gl.Ptr(points), gl.STATIC_DRAW)
    
    var vao uint32
    gl.GenVertexArrays(1, &amp;amp;vao)
    gl.BindVertexArray(vao)
    gl.EnableVertexAttribArray(0)
    gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
    gl.VertexAttribPointer(0, 3, gl.FLOAT, false, 0, nil)
    
    return vao
}
&lt;/pre&gt;

&lt;p&gt;First we create a &lt;strong&gt;Vertex Buffer Object&lt;/strong&gt; or &lt;strong&gt;vbo&lt;/strong&gt; to bind our &lt;strong&gt;vao&lt;/strong&gt; to, which is created by providing the size (&lt;strong&gt;4 x len(points)&lt;/strong&gt;) and a pointer to the points (&lt;strong&gt;gl.Ptr(points)&lt;/strong&gt;). You may be wondering why it’s &lt;strong&gt;4 x len(points)&lt;/strong&gt; - why not 6 or 3 or 1078? The reason is we are using &lt;strong&gt;float32&lt;/strong&gt; slices, and a 32-bit float has 4 bytes, so we are saying the size of the buffer, in bytes, is 4 times the number of points.&lt;/p&gt;

&lt;p&gt;Now that we have a buffer, we can create the &lt;strong&gt;vao&lt;/strong&gt; and bind it to the buffer with &lt;strong&gt;gl.BindBuffer&lt;/strong&gt;, and finally return the &lt;strong&gt;vao&lt;/strong&gt;. This &lt;strong&gt;vao&lt;/strong&gt; will then be used to draw the triangle!&lt;/p&gt;

&lt;p&gt;Back in &lt;strong&gt;main&lt;/strong&gt;:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
func main() {
    ...

    vao := makeVao(triangle)
    for !window.ShouldClose() {
        draw(vao, window, program)
    }
}

Here we call **makeVao** to get our **vao** reference from the **triangle** points we defined before, and pass it as a new argument to the **draw** function:

func draw(vao uint32, window *glfw.Window, program uint32) {
    gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
    gl.UseProgram(program)
    
    gl.BindVertexArray(vao)
    gl.DrawArrays(gl.TRIANGLES, 0, int32(len(triangle) / 3))
    
    glfw.PollEvents()
    window.SwapBuffers()
}
&lt;/pre&gt;

&lt;p&gt;Then we bind OpenGL to our &lt;strong&gt;vao&lt;/strong&gt; so it knows what we’re talking above when we tell it to &lt;strong&gt;DrawArrays&lt;/strong&gt;, and tell it the length of the triangle (divided by three, one for each X, Y, Z coordinate) slice so it knows how many vertices to draw.&lt;/p&gt;

&lt;p&gt;If you run the application at this point you might be expecting to see a beautiful triangle in the center of the window, but unfortunately you would be mistaken. There’s still one thing left to do, you see we’ve told OpenGL that we want to draw a triangle, but we need to tell it &lt;em&gt;how&lt;/em&gt; to draw the triangle.&lt;/p&gt;

&lt;p&gt;In order to do that, we need what are called fragment and vertex shaders, which are beyond the scope of this tutorial. All you really need to understand for this application is that shaders are their own mini-programs (written in &lt;a href=&quot;https://www.opengl.org/sdk/docs/tutorials/ClockworkCoders/glsl_overview.php&quot;&gt;OpenGL Shader Language or GLSL&lt;/a&gt;) that typically run on the GPU. They’re really interesting and force you to think in a different way to typically programming tasks, but again they’re out of scope for this tutorial. For our purposes, just understand that a vertex shader manipulates the vertices to be drawn by OpenGL and generates the data passed to the fragment shader, which then determines the color of each fragment (you can just consider a fragment to be a pixel) to be drawn to the screen.&lt;/p&gt;

&lt;p&gt;We start by adding two more imports and a function called &lt;strong&gt;compileShader&lt;/strong&gt;:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
import (
    &quot;strings&quot;
    &quot;fmt&quot;
)

func compileShader(source string, shaderType uint32) (uint32, error) {
    shader := gl.CreateShader(shaderType)
    
    csources, free := gl.Strs(source)
    gl.ShaderSource(shader, 1, csources, nil)
    free()
    gl.CompileShader(shader)
    
    var status int32
    gl.GetShaderiv(shader, gl.COMPILE_STATUS, &amp;amp;status)
    if status == gl.FALSE {
        var logLength int32
        gl.GetShaderiv(shader, gl.INFO_LOG_LENGTH, &amp;amp;logLength)
        
        log := strings.Repeat(&quot;\x00&quot;, int(logLength+1))
        gl.GetShaderInfoLog(shader, logLength, nil, gl.Str(log))
        
        return 0, fmt.Errorf(&quot;failed to compile %v: %v&quot;, source, log)
    }
    
    return shader, nil
}
&lt;/pre&gt;

&lt;p&gt;The purpose of this function is to receive the shader source code as a string as well as its type, and return a pointer to the resulting compiled shader. If it fails to compile we’ll get an error returned containing the details.&lt;/p&gt;

&lt;p&gt;Now let’s define the shaders and compile them from &lt;strong&gt;makeProgram&lt;/strong&gt;. Back up in our &lt;strong&gt;const&lt;/strong&gt; block where we define &lt;strong&gt;width&lt;/strong&gt; and &lt;strong&gt;height&lt;/strong&gt;:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
vertexShaderSource = `
    #version 410
    in vec3 vp;
    void main() {
        gl_Position = vec4(vp, 1.0);
    }
` + &quot;\x00&quot;

fragmentShaderSource = `
    #version 410
    out vec4 frag_colour;
    void main() {
        frag_colour = vec4(1, 1, 1, 1);
    }
` + &quot;\x00&quot;
&lt;/pre&gt;

&lt;p&gt;As you can see these are strings containing GLSL source code for two shaders, one for a &lt;em&gt;vertex shader&lt;/em&gt; and another for a &lt;em&gt;fragment shader&lt;/em&gt;. The only thing special about these strings is that they both end in a null-termination character, &lt;strong&gt;\x00&lt;/strong&gt; - a requirement for OpenGL to be able to compile them. Make note of the &lt;strong&gt;fragmentShaderSource&lt;/strong&gt;, this is where we define the color of our shape in RGBA format using a &lt;strong&gt;vec4&lt;/strong&gt;. You can change the value here, which is currently &lt;strong&gt;RGBA(1, 1, 1, 1)&lt;/strong&gt; or &lt;em&gt;white&lt;/em&gt;, to change the color of the triangle.&lt;/p&gt;

&lt;p&gt;Also of note is that both programs start with &lt;strong&gt;#version 410&lt;/strong&gt;, which you should change to &lt;strong&gt;#version 120&lt;/strong&gt; if using OpenGL 2.1. &lt;strong&gt;120&lt;/strong&gt; is not a typo - use &lt;strong&gt;120&lt;/strong&gt; not &lt;strong&gt;210&lt;/strong&gt; if you’re on OpenGL 2.1!&lt;/p&gt;

&lt;p&gt;Next in &lt;strong&gt;initOpenGL&lt;/strong&gt; we’ll compile the shaders and attach them to our &lt;strong&gt;program&lt;/strong&gt;:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
func initOpenGL() uint32 {
	if err := gl.Init(); err != nil {
		panic(err)
	}
	version := gl.GoStr(gl.GetString(gl.VERSION))
	log.Println(&quot;OpenGL version&quot;, version)
    
    vertexShader, err := compileShader(vertexShaderSource, gl.VERTEX_SHADER)
    if err != nil {
        panic(err)
    }
    fragmentShader, err := compileShader(fragmentShaderSource, gl.FRAGMENT_SHADER)
    if err != nil {
        panic(err)
    }
    
    prog := gl.CreateProgram()
    gl.AttachShader(prog, vertexShader)
    gl.AttachShader(prog, fragmentShader)    
    gl.LinkProgram(prog)
    return prog
}
&lt;/pre&gt;

&lt;p&gt;Here we call our &lt;strong&gt;compileShader&lt;/strong&gt; function with the &lt;em&gt;vertex shader&lt;/em&gt;, specifying its type as a &lt;strong&gt;gl.VERTEX_SHADER&lt;/strong&gt;, and do the same with the &lt;em&gt;fragment shader&lt;/em&gt; but specifying its type as a &lt;strong&gt;gl.FRAGMENT_SHADER&lt;/strong&gt;. After compiling them, we attach them to our program by calling &lt;strong&gt;gl.AttachShader&lt;/strong&gt; with our program and each compiled shader.&lt;/p&gt;

&lt;p&gt;And now we’re finally ready to see our glorious triangle! Go ahead and run, and if all is well you’ll see:&lt;/p&gt;

&lt;div class=&quot;highlight center-text&quot;&gt;
    &lt;img src=&quot;/images/post/golang-opengl-conway-3.png&quot; width=&quot;500&quot; height=&quot;522&quot; alt=&quot;Conway's Game of Life in OpenGL and Golang Tutorial - Hello, Triangle!&quot; /&gt;
&lt;/div&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;Amazing, right! All that for a single triangle, but I promise you we’ve setup the majority of the OpenGL code that will serve us for the rest of the tutorial. I highly encourage you to take a few minutes to play with the code and see if you can move, resize, and change the color of the triangle. OpenGL can be &lt;em&gt;very&lt;/em&gt; intimidating, and it can feel at times like its difficult to understand what’s going on, but understand that this isn’t magic - it only looks like it is.&lt;/p&gt;

&lt;p&gt;In the next part of the tutorial we’ll make a square out of two right-angled triangles - see if you can try and figure this part out before moving on. If not, don’t worry because we’ll be walking through the code in &lt;a href=&quot;/blog/tutorial-opengl-with-golang-part-2-drawing-the-game-board&quot;&gt;Part 2&lt;/a&gt;, followed by creating a full grid of squares that will act as our game board.&lt;/p&gt;

&lt;p&gt;Finally, in &lt;a href=&quot;/blog/tutorial-opengl-with-golang-part-3-implementing-the-game&quot;&gt;Part 3&lt;/a&gt; we continue by using the grid to implement &lt;em&gt;Conway’s Game of Life!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href=&quot;/blog/tutorial-opengl-with-golang-part-1-hello-opengl&quot;&gt;Part 1: Hello, OpenGL&lt;/a&gt;&lt;/em&gt; | &lt;em&gt;&lt;a href=&quot;/blog/tutorial-opengl-with-golang-part-2-drawing-the-game-board&quot;&gt;Part 2: Drawing the Game Board&lt;/a&gt;&lt;/em&gt; | &lt;em&gt;&lt;a href=&quot;/blog/tutorial-opengl-with-golang-part-3-implementing-the-game&quot;&gt;Part 3: Implementing the Game&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The full source code of the tutorial is available on &lt;a href=&quot;https://github.com/KyleBanks/conways-gol&quot;&gt;GitHub&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;checkpoint&quot;&gt;Checkpoint&lt;/h2&gt;

&lt;p&gt;Here’s the contents of &lt;strong&gt;main.go&lt;/strong&gt; at this point of the tutorial:&lt;/p&gt;

&lt;pre class=&quot;prettyprint&quot;&gt;
package main

import (
	&quot;fmt&quot;
	&quot;log&quot;
	&quot;runtime&quot;
	&quot;strings&quot;

	&quot;github.com/go-gl/gl/v4.1-core/gl&quot; // OR: github.com/go-gl/gl/v2.1/gl
	&quot;github.com/go-gl/glfw/v3.2/glfw&quot;
)

const (
	width  = 500
	height = 500

	vertexShaderSource = `
		#version 410
		in vec3 vp;
		void main() {
			gl_Position = vec4(vp, 1.0);
		}
	` + &quot;\x00&quot;

	fragmentShaderSource = `
		#version 410
		out vec4 frag_colour;
		void main() {
			frag_colour = vec4(1, 1, 1, 1.0);
		}
	` + &quot;\x00&quot;
)

var (
	triangle = []float32{
		0, 0.5, 0,
		-0.5, -0.5, 0,
		0.5, -0.5, 0,
	}
)

func main() {
	runtime.LockOSThread()

	window := initGlfw()
	defer glfw.Terminate()
	program := initOpenGL()

	vao := makeVao(triangle)
	for !window.ShouldClose() {
		draw(vao, window, program)
	}
}

func draw(vao uint32, window *glfw.Window, program uint32) {
	gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
	gl.UseProgram(program)

	gl.BindVertexArray(vao)
	gl.DrawArrays(gl.TRIANGLES, 0, int32(len(triangle)/3))

	glfw.PollEvents()
	window.SwapBuffers()
}

// initGlfw initializes glfw and returns a Window to use.
func initGlfw() *glfw.Window {
	if err := glfw.Init(); err != nil {
		panic(err)
	}
	glfw.WindowHint(glfw.Resizable, glfw.False)
	glfw.WindowHint(glfw.ContextVersionMajor, 4)
	glfw.WindowHint(glfw.ContextVersionMinor, 1)
	glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
	glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)

	window, err := glfw.CreateWindow(width, height, &quot;Conway's Game of Life&quot;, nil, nil)
	if err != nil {
		panic(err)
	}
	window.MakeContextCurrent()

	return window
}

// initOpenGL initializes OpenGL and returns an intiialized program.
func initOpenGL() uint32 {
	if err := gl.Init(); err != nil {
		panic(err)
	}
	version := gl.GoStr(gl.GetString(gl.VERSION))
	log.Println(&quot;OpenGL version&quot;, version)

	vertexShader, err := compileShader(vertexShaderSource, gl.VERTEX_SHADER)
	if err != nil {
		panic(err)
	}

	fragmentShader, err := compileShader(fragmentShaderSource, gl.FRAGMENT_SHADER)
	if err != nil {
		panic(err)
	}

	prog := gl.CreateProgram()
	gl.AttachShader(prog, vertexShader)
	gl.AttachShader(prog, fragmentShader)
	gl.LinkProgram(prog)
	return prog
}

// makeVao initializes and returns a vertex array from the points provided.
func makeVao(points []float32) uint32 {
	var vbo uint32
	gl.GenBuffers(1, &amp;amp;vbo)
	gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
	gl.BufferData(gl.ARRAY_BUFFER, 4*len(points), gl.Ptr(points), gl.STATIC_DRAW)

	var vao uint32
	gl.GenVertexArrays(1, &amp;amp;vao)
	gl.BindVertexArray(vao)
	gl.EnableVertexAttribArray(0)
	gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
	gl.VertexAttribPointer(0, 3, gl.FLOAT, false, 0, nil)

	return vao
}

func compileShader(source string, shaderType uint32) (uint32, error) {
	shader := gl.CreateShader(shaderType)

	csources, free := gl.Strs(source)
	gl.ShaderSource(shader, 1, csources, nil)
	free()
	gl.CompileShader(shader)

	var status int32
	gl.GetShaderiv(shader, gl.COMPILE_STATUS, &amp;amp;status)
	if status == gl.FALSE {
		var logLength int32
		gl.GetShaderiv(shader, gl.INFO_LOG_LENGTH, &amp;amp;logLength)

		log := strings.Repeat(&quot;\x00&quot;, int(logLength+1))
		gl.GetShaderInfoLog(shader, logLength, nil, gl.Str(log))

		return 0, fmt.Errorf(&quot;failed to compile %v: %v&quot;, source, log)
	}

	return shader, nil
}
&lt;/pre&gt;
</description>
            </item>
        
  </channel>
</rss>
