Thursday, May 19, 2016

Ceviche’s Café

Not a blog post about food - though that sounds good right about now.

Instead, this is more about griping about technology, which is more in line with what I usually write.

The 2016 Seattle International Film Festival has just opened as I write this. 25 days of upwards of 300 movies. I was told upwards of 400 movies, but I'm not sure about that. The biggest film festival in the United States.

In years past, I've got the big fancy catalog to flip through to decide what I wanted to see. There's a PDF of a smaller catalog, which is also helpful. And on SIFF's website, there's a "My SIFF" feature which allows you to keep track of the stuff you have tickets for. Or, for the folks who buy a series pass, you can still register your interest in specific showings.

It doesn't (as far as I can tell) export to useful things like Google Calendar for easy reference on the go.

So, in addition to cursing the darkness, I set about to put things into a more useful format. I didn't get explicit permission from SIFF for this, so I'm not advocating that you do what I have done. I wrote a Python script that uses urllib(2) and Beautiful Soup to pull down and then interpret web pages. With a little bit of poking around, I was able to interpret individual movie pages, to figure out where and when the showings are. There are a lot of venues and a lot of screenings going on.

After collecting that information, I proceeded to push the movies up onto Google Calendar, which you can see here: https://calendar.google.com/calendar/embed?src=tbbr77hpo9aqi5b98qdr2el2ls%40group.calendar.google.com&ctz=America/Los_Angeles

I actually did most of that last year for SIFF 2015. This year, I discovered that some of the movies some friends wanted to see weren't showing up on the Google Calendar. I poked through the debug log that was generated when I wrote the data to the calendar, and it turned out I was detecting some sort of error condition on certain movies, skipping them, and continuing on.

As I dug deeper, I determined that the error condition had something to do with Unicode encoding and/or decoding. Oh, joy.

One thing that was an interesting issue is that some of the URLs that SIFF uses have non-ASCII characters in them. It's OK, as long as you encode those characters properly. For example, http://www.siff.net/festival-2016/ceviche%E2%80%99s-dna has the right quote (not part of 7-bit ASCII) properly wrapped. If you try to get urllib2 to download the URL that you see in the browser address bar, it'll choke.

Maybe there's a better way to do this, but I ended up just finding the last slash and hitting the part of the URL after that with an encoding pass, because my efforts to encode the whole string led to the slashes being converted, which isn't any good.

Ok, so I can handle right quotes, maybe.

There's a bunch of other characters that show up, like in the opening movie, "Café Society". My tool took several passes, writing and rewriting title text, using the title as a key when storing the movie information in the python "shelve" format, reloading it, and somewhere along there, unicode titles were getting mangled, and I was having a hard time making sure that they got re-encoded or re-decoded, or encoded and decoded or something. I kept throwing more random layers at the problem, and it still wasn't really working for me.

In the end, I realized that I could grab the title text as ascii for the purposes it already served (particularly being a key for shelve) and then also grab a Unicode version of it alongside for generating the calendar entries.

Which ended up working really well. I'm astonished I didn't think of it earlier.

I also added in a pass where if I found '&' in the text, I'd convert it to '&'. Again, there were fancier, probably better ways which I tried and had a hard time with. So, I did a simple replacement specifically targeting that one character.

In the end, it works pretty well - I've got several things that I might change about the script before 2017, but in a lot of cases, my life would be easier if SIFF exposed an API to pull movie information from. I know that SIFF isn't in the API business, so maybe if I contacted them, they'd refer me to the company that handles their web presence, and maybe that'd be a useful conversation.

Or, maybe what I've got is good enough for a while.

Sunday, February 14, 2016

Now with more intentional pew pew, and randomly driving into stuff that doesn't need to be driven into


What's in there that you didn't see last time? A few things.

  • I added in a raycast to determine if the shot that a box takes is occluded (by a static box, by a moving box, by a dead box), which makes things seem more purposeful.
  • Not that you'd notice it, but there were several bugs in my collision code. One made the physics boxes twice as wide as they should have been, but only for dynamic tests, like for the paths of bullets and moving boxes. Thus the "corridor map" was out of sync with things that moved.
  • Boxes target nearby boxes sometimes, they randomly pick places to patrol to sometimes.
  • Boxes target nearby boxes, which may lead to one or more of them shooting them up (which, I know, you've seen that bit) or it may lead to them getting stuck in an embrace of, I want to say "death", but it's just an embrace of hostility - they're trying very hard to move into the location of the other box, which is simultaneously trying very hard to move in the opposite direction. I've seen two and three boxes get in these cycles. I could put some special case logic in there to say "oh, no, what you really want to do is engage at this ideal radius for this weapon", but I want to come back to that later, possibly with a different approach altogether.
It's getting to the point where the stuff I want to do next is largely falling under the category of "activity selection", like choosing to search for a better path for several ticks, or choosing not to patrol when a box discovers an enemy box. Also, there's stuff here I'll call "aggregate behavior" that I'd like to do, like allowing boxes to call for help, and flank their targets.

It feels like I've done a lot, and after spending a bunch of time refactoring just to fix bugs, working on this doesn't feel quite as exciting as it did before that, but things are in a better state, so that's good. I recently heard Jonathan Blow use the term "code morale" which matters on real projects and screwy little tech demos like this.

One thing you don't see in that movie is a piece I added in where I can hit a key to cycle a "selection" marker from colored box to colored box, which draws them with a little highlight, but more interestingly (to me, I don't want to speak for you good people), it dumps a bunch of debug spew to the console for just that one box. Hm, potential feature for approximately never: create debugging facilities that are keyed on the box, and a debug console that can select what feed to watch.


Saturday, February 13, 2016

Now with random Pew Pew


The first thing here is that I'm experimenting with MP4 movies of my progress - I'm using ffmpeg to capture the video, since my previous method (using byzanz to create animated GIFs) had an upper limit of less than a minute. Maybe you get enough of all of this in 15 seconds, but I, for one, need more box-moving-around-time than that.

Also, I split the teams up finer. Now, we have 6 teams of 2 boxes each, in festive colors. Were the people demanding that? Festive colored boxes seems good.

Also, they can shoot at each other now. There's no intelligence involved - each tick, there's a 1% chance that a box will spawn a bullet in a random direction. Bullets check for collision with the moving boxes and the static boxes. If they hit a moving box, they apply damage. If they hit anything, they deactivate themselves.

Boxes that lose 4 points of damage become inactive.

You can almost root for boxes to survive, if you want.

TODO:
aim more intelligently
retreat from threats (when wounded?)
track weapon heat
call for help
flanking
particle effects when bullets impact

Friday, February 12, 2016

Boxes not hugging the other boxes




What you see here is the introduction of a "corridor map", a network of navigation landmarks that the boxes use to find their way around obstacles. It's an improvement over yesterday's behavior of getting stuck on walls, in that the boxes are somewhat aware of the obstacles now. They can still get stuck, so there's room for being more aware of not making progress on a plan and bailing out to try something different.

Thursday, February 11, 2016

Boxes not overlapping


Adding to yesterday's demo, the boxes are now a couple different colors, still moving around. Now they bump into each other and use a simple constraint system to ensure that they don't overlap.

Also, I added some fixed boxes in the world that boxes might move around. Except they're not really smart enough to do that yet. Sometimes, they knock each other loose.

TODO: make stuff smarter.

Wednesday, February 10, 2016

Something a little different


This doesn't tie in to my previous posts, really. Just screwing around, getting a PyGame / OpenGL framework up and running.

There's a few boxes moving around the screen. So, that's something.

Friday, February 5, 2016

Spaceship Flying In Space

Back in college, before I knew much about anything, I gave a resume to a tiny little company called HDC Computer Corporation. That name kind of pegged them (constrained them?) to be a Microsoft Windows development house.

They managed to get some of their stuff bundled into Windows-286, if I recall correctly, including a little space shooter game called "HDC Rocks". Yes, it was about shooting rocks in space. Also, the title was a gag and tongue-in-cheek motto.

The Internet doesn't seem to remember that little nugget, but maybe it will now.


What you see here is the rebuilt version of as far as I had got on my "Space Rocks" demo - a little space ship moving around on the screen, rendering in OpenGL 2.1, with a window provided by SDL2.

Nothing's particularly exciting about it - the pathfinding, if you can call it that, is "move horizontally, then move vertically". There's no real obstacles. It doesn't have a lose condition.

But it's running again, OpenGL commands, as issued from my language, sent through a C shim to a vanilla OpenGL implementation.

As I mentioned in my previous post, I had lost a file (failed to check in my work) called gl_tools.c, which contained that layer, so the effort necessary to reproduce it was simply(?) a matter of exporting GL calls down into my library.

Sort of. The time management code is coming from SDL, so that took a little more attention. The initialization of an OpenGL context isn't quite as simple as I had recalled. I made use of Lazy Foo' Productions' SDL/OpenGL tutorial to figure out what bits I really had to rebuild inside my shim library.

And there you go, it's working again. And checked in, besides.

I even made myself a little convenience tool that launches the program, records frames of it rendering, then compresses that into an animated GIF all in one handy script. I could make it slightly cleverer, by forcing the window to open up at a particular point on the desktop, which would keep you from looking at my emacs window in the background. But maybe emacs makes you comfortable. I wouldn't want to deprive you of that.

The cursor, though, not so sure about that. I could easily suppress the cursor.


So. The demo is back up and running, and the thing I was running into back in July when I last checked stuff in (I don't remember this stuff, but GitHub does) was that I wanted to have a solid story about what I was doing with arrays of complex objects (like structs, say, like you might need to have for a bunch of asteroids floating across your screen). Would arrays have to be statically allocated? What's initialization like? Am I going to have pointers to these things? Python and Java don't have pointers, except that they do, but you don't see them. Is that what I want?

I want to avoid copying complex objects except by explicit deliberate action. It feels like there are a few other choices that can come as a result of that, but I haven't really meditated deeply enough to make it obvious how things ought to work. Perhaps the next step is to try some stuff, and be prepared to roll back if I don't like how things are working.