Feedback and Criticism on a Game of Life Implementation

Hi all,

I’m just starting my journey into the world of TouchDesigner and so far all I can say is WOW! What a cool environment to create in. I have a stronger background in computer science and programming than I do in the visual or 3D arts so, while I feel pretty handy with Python, I’ve been kind of blundering along trying to figure out the rest of TouchDesigner.

One really useful learning technique for me, whenever I pick up a new language or software, is to try and recreate a project that I’ve done in the past. My first go-to is trying to implement Conway’s Game of Life:

[url]https://en.wikipedia.org/wiki/Conway's_Game_of_Life[/url]

I’ve managed to get an implementation running in TouchDesigner using Python and NumPy arrays to do everything on the computational backend and to populate a TableDAT that controls instances of Geometry. It runs as it should, but at this point I think it would be very helpful to have some experienced eyes look at it and tell me things like “Don’t do that/do this” or “X is a horrible idea” so that I can get a feel for what I need to spend some time focusing on. If you would take a totally different route to implement the same functionality, I would LOVE to hear how you’d do it. I appreciate any comments/criticism/feedback you can offer.

Thanks for reading and I look forward to becoming a part of the TouchDesigner community!
Nic
GameofLife_Stripped.2.toe (11.2 KB)

Hi This is wonderful example. Same as you i tried to create some generative graphic things with python. I have on question on your TD patch. Do you have any reason to use timer to execute python? What about using execute DAT?

Thanks

Nice work.

The questions I would start to ask are largely about scale… what happens when you get larger arrays… much larger arrays. At a v1 size of 100 performance quickly drops to 1 fps with a timer length of 10 frames. What if you wanted / needed a v1 size of 1000, 2000 - numPy might not be the most efficient solution for large scales, and instead you might have to consider a CHOP based approach, or a shader to do the computation on the GPU.

A good challenge as a next step would be to see if you can do this with CHOP math instead of with numPy. CHOPs can initially feel like a tough nut to crack, but once you get a handle on them they’re incredibly powerful - a lesson I still learn every day.

Some other notes worth considering - you’ve added a new callback DAT for your timer rather than using the default. This is a fine approach, but you might consider deleting the original callbacks DAT and docking your new dat to the timer. This will ensure that the callbacks DAT and timer stay paired if you move them in the network space.

Your methods are pretty straightforward, but you might look at using extensions in future projects.

Tables make for a fine means of instancing, but in my experience CHOPs tend to be faster at larger scales - table contents are usually stored as strings adding some additional overhead in declaring them as ints or floats when referenced by other operators. To that end, you’re also doing all of the computation for the location of all grid elements with python - instead, you can just use a grid SOP to determine location information for your instances, and then only update the color information of your individual cells.

Working with a flat plain you might consider instead using an orthographic projection approach rather than perspective for your camera and rendering.

Changing the value associated with v1 changes the number of rows and columns, but does not maintain the distribution of your instances. I end up with more a grid that’s more tightly, or more sparsely packed. I’d think about how your camera moves and your grid re-sizes to maintain your spacing and sizes. A CHOP execute attached to your x_dim would facilitate this.

In terms of display, this works in network but not in perform mode. It might be worth thinking about how you’d like this to present / look in a non-network context.

This is a wonderful implementation as you’re exploring touch, so I hope this feedback doesn’t come across as overly critical - only from the perspective of someone who has already knocked his head against a lot of walls and keyboards.

cheers,
M

Hi indaeTouchdesigner,

Thanks for the kind words. I don’t have any reason (any good reason, at least) to use a Timer DAT to execute the script instead of an Execute DAT. I wanted the “game board” to spawn the next generation of cells automatically and regularly and I also wanted the ability to spawn an entirely new game board if it generated a pattern that loops infinitely (see https://en.wikipedia.org/wiki/Conway’s_Game_of_Life#Examples_of_patterns). The ideal solution would probably be to explicitly check the game board to see if it is stuck in one such loop before spawning a new one but my workaround was to just set an explicit limit on the number of generations the board could go through before a new one took its place. The Timer DAT seemed like a convenient way to accomplish both of these goals (see timer1’s Callbacks DAT text1).

I can’t say that I’m quite familiar enough with the Execute DAT to make a judgement call about if/why it would be a better option. How would you use it to accomplish the same goals?

Nic

Hey M,

Thank you for the very thorough reply! I appreciate the solid feedback and it absolutely didn’t come across as overly critical - you’ve given me a lot of good things to think about and work on. My next project will be trying to implement the same functionality using CHOPs, seems like a fun challenge :wink:

Nic