Sunday, April 30, 2017

Lulu + ReportLab = unembedded fonts, by default - FIXED

I use ReportLab's PDFGen Python library to generate PDFs. I use it for a lot of different stuff, including my line of Kakuro books. It's not tricky to get it to do what I want, most of the time. When I generated the PDFs for those Kakuro books, I submitted them to lulu.com and immediately got an error complaining that my books didn't properly embed the Helvetica font.

I did vague digging around and some sort of hacking (so many years ago, I don't recall the details), and got something gross that didn't have a reference to Helvetica.

I also shelled out money to Adobe for their commercial PDF tool, and massaged the output.

Neither of these solutions were really satisfying, but they each seemed to work at various times.

Fast forward to today, and I wanted to make a notebook of hex grid paper:


I uploaded the PDF of my graph paper, and got that same error again. To be clear, the entire book was graph paper - no fonts were being used. I poked around in the PDFGen documentation (there's a user's tutorial, not so much a reference manual), and found some information that was useful for importing TTF files and embedding them, but nothing for an unused Helvetica font.

I poked around inside the source again, and discovered the initialFontName and initialFontSize arguments to the canvas object, so now, my canvas creation looks like this:

ttfFile = os.path.join('.', 'UniversalisADFStd-Regular.ttf')  
pdfmetrics.registerFont(TTFont("Universalis", ttfFile))
c = canvas.Canvas("hex_book.pdf", initialFontName='Universalis', initialFontSize = 24, pagesize=pageSize)
c.setFont('Universalis', 24)


And there's no dangling use of Helvetica, and Lulu's happy, and I'm happy. Maybe this is useful to you, maybe it'll be useful to me, next time I run into this particular weirdness.

Saturday, April 8, 2017

Hamiltonian Cubes

A little while ago, as an exercise in procedural content generation, I made a stupid little maze generation script, like this.

A buddy of mine asked how configurable the algorithm was, and I admitted that it didn't really have any knobs to adjust.

My buddy was looking for what I'd call a "labyrinth" generator - a complete tour of every location in the space. Also, Hamiltonian_path sounds cool, because everybody's crazy about Hamilton these days, right?

In particular, he wanted a complete tour of all of the squares on the surface of a 6x6x6 cube.

I adjusted my script a little bit, and came up with randomly generating a path around the cube, that didn't visit all the locations:
which is a step in the right direction - getting the edge crossings working correctly, that's an accomplishment. I was considering making modifications of the solution, like the rewriting that goes on in L-systems. I wasn't really convinced that would work, so I went more for the more direct approach of creating a path and validating certain constraints as I went.

In particular, I found Frank Rubin's paper: A Search Procedure for Hamilton Paths and Circuits which described a bunch of constraints on potential passageways (edges), and ways to determine if the solution so far is already inconsistent. For example, if there's any location that can't be reached from both the start or the endpoint, you've painted yourself into a corner. (Or maybe the opposite, painted yourself out of reach of a corner?)

It also identifies other kill conditions, like a location with only one passageway available, that's a dead end, and no good.

Also, passageways can be "required", like a node that is down to two passageways incident to it, they both have to be used.

This led to some solutions, and I presented the first of them to my friend yesterday morning, along with the script, so he could generate more on his own.


My friend discovered that the algorithm would often find solutions quickly, or very slowly - like 25% of the time, a solution would be found in one minute, but 75% of the time, it'd take longer than three minutes. I haven't done and real data collection, but there seems like an optimization problem to be had - pick a timeout value t, which will yield a solution in 1/n(t) cases, and then iterating until you get a solution.

I implemented a variation on that, with exponential backoff - I first try a small timeout, and if I fail to get a solution in that time, I multiply the timeout by a constant value and start over.

I've got extra optimizations that I could put in, but really, the point of the project has been accomplished, my "customer" is happy, and I should really go to work on other projects.

Friday, March 3, 2017

GDC 2017 Part I : AI Summit (plus and minus)

It's been just over a year now since I leapt back into being a game developer for money (after a six year hiatus where I was letting non-game stuff pay the bills, but still doing games for fun). That lines up nicely with the Game Developers Conference (GDC), which has historically been a huge source of inspiration for me. Networking is good, but I'm bad at it, seeing San Francisco and family is nice, but I can do that at other times. Friends and colleagues suggest that watching the presentations after the fact is just as good, but I don't agree.

This was the first year I attended the AI summit, an extra two days focused on AI topics. As it happens, there was a bunch of other stuff going on for those two days, and my pass allowed me to browse, so I did.

This is a quick rundown of what I saw and did up to the main conference, which will be Part II. Maybe I'll even make that a link.

Day -1: Saturday

Flew down at crazy-early-o-clock, probably leaving the house later than I should have. Met up with my sister and brother in law, saw some Monet, got chastised for standing closer than 18 inches from the Monet. Went to the exploratorium. Science is weird.

Day 0: Sunday

Had Nepalese food with said sister and brother in law. Went to the San Francisco Museum of Modern Art.

Went to an AI Programmers' mixer thing. Bumped into Kate Compton, who gave me one of her Tracery zine/manuals, a library for generative grammars, e.g. for writing a TwitterBot. This stuck in my brain for the remainder of GDC. (spoiler)

Day 1: Monday

Ok, so if you're skimming past the preliminary bits, this is where we get to actual sessions.

Crowd AI in Watch Dogs 2

I would have titled this "Bystander AI". WD2 is an open world game, where stuff happens on the streets of San Francisco. They implemented an architecture where events get posted (playing guitar, posing for a photo), and other NPCs trigger on those events, which can cascade into emergent crazy street scenes. An example was shown of an NPC proposing to another NPC, and then they posed for a selfie, which got photobombed, which led to a furious fight.

Behavior Tree Arborist

A year ago, I was trying to decide the AI architecture necessary for BattleTech, the game I'm working on at the day job. Since then, I've built a behavior tree / influence map / blackboard system, which is probably not terribly different from other systems out there. I was looking forward to this session (three mini-sessions) to see if there were best practices that I should have adopted a year ago. Turns out, not a whole lot of bad decisions, so that's cool.

The first mini-session by Mika Vehkala talked about flipping around the idea of decorator nodes and making node decorations - things that hang off of nodes to make better composition of reusable nodes. That's an interesting idea, and I could imagine it condensing the presentation of my behavior trees. I'm not sure if it would make things any more reusable, but more concise expression is good.

There were a few decorations presented that would make more advanced control flows than I currently use. Again, not sure if that would be useful for my current project.

Also mentioned was splitting behavior trees, which just makes sense. My current one is getting a little bulky. I'm the only person writing the code, so there isn't any contention for locking the file for writing, but it'd be worth considering for later. The practice suggested was to author the trees with references, but at compile/load time, merge them into a single tree. That's interesting, but I think that one might get some value out of dynamic tree references. Extra cost, complexity? Sure.

Also mentioned was dynamic behavior tree references, slotting in specific behaviors at runtime. That seems promising, but again, nothing for my current project.


The second mini-session by Bobby Anguelov was a stern instruction to know the relative merits of Behavior Trees and Finite State Machines. If you're having to jump out of your tree to replan, you might be doing it wrong.

I don't know if it was this micro-session, but along the way, I began to think that my Behavior Tree work might actually be accomplished as well or better by a "Decision Tree", which I think is closer to what I actually use.

The final sub-talk was by Ben Weber, who talked about a few additional node types that he found useful (spawn goal, working memory modifier, success test (wait until conditions are true)) and offered a few patterns he found useful (daemon processes, managers, message passing, behavior locking, and unit subtasks). I vaguely recall these being interesting, but not immediately relevant - I'd like to go back and review the presentation to see if it sinks in better.

The Simplest AI Trick in the Book

Another collection of mini-talks, this one gave small techniques to get great effects.

Steve Rabin advocated for making the AI believable, "You must sell the AI". This is largely a design issue, but the AI engineer is probably the best person to advocate for things that make the AI look less like a robot.

David Churchill gave a quick little implementation of a stack guard implementation that caught a buffer overrun in some of his code.

Mike Lewis suggested adding a button to freeze output for cases where the debug spew is flying too fast. If you've ever hit Ctrl-S to pause a stdio program, that's the idea.

Xavier (I missed his last name) talked about adding a dynamic proxy object for events that happen quickly and your AI should react to. I might call this a "bread crumb", but I think he had another name for it.

Brian Schwab suggested sitting quietly behind a tester and see how they play the game.


Predictable Projectiles

Again, I misunderstood the point of this talk, I thought it was going to be about stable math for projectile simulation, so that you could network your games without having to adjust the simulations. Instead, it was a talk by Chris Stark about "Orcs must Die", and how they used linear and ballistic projectiles to shoot at the player character, leading the player in both cases. Lots of math was presented. I've wanted to write some code for leading the target for linear projectiles before, but now I also want to write a ballistic solver.


ELO, TrueSkill, or write your own

ELO is a ranking system, designed to give chess players a score. I write it as ELO, because it feels like it wants to be an acronym. It's named after a guy, though. I had read the Wikipedia article on ELO a while ago, and this talk didn't give me a whole lot of new information. One thing that I did get was that Mario Izquierdo had used ELO (or some variant) to score user-generated levels, which seems relevant to some of my PCG projects.

TrueSkill is Microsoft's proprietary version of this, which extends to supporting team play. Glicko is an open source system that's similar, but still only 1v1.


Kate Compton's PCG Talk

Didn't manage to make it to this, but she's really good about posting resources, so I've managed to collect a lot of what was presented, and do my own homework. I'll probably come back to edit in some of those links.


Deep Learning Math

Not learning how to do math using a neural network, just the calculations going on inside the latest iteration on neural nets.

A phrase Alex Champanard presented was "differentiable computing", which places this stuff in a good context - we're trying to compute a value, and the process for doing that is continuous functions, which we can adjust to get a better approximation of the function we're trying to represent.

A surprising bit of trivia for me is that I had always thought of neural networks as simple fully connected layer affairs - a few input nodes, and then those connecting to layer 1, which fully connected to layer 2, which fully connected to layer 3, until you got to the output nodes. Turns out, these days, nodes are clustered, with one node on layer 0 having a link to a node on layer 5, or whatever - it's still a directed acyclic graph (right?), but it's not as uniform as I was taught so many years ago.


Harmonic Functions and Mean Value Coordinates

I like trying to fit math ideas into my head. This talk didn't try to give immediate practical tools, but present some tools that could be used for some mesh analysis tasks. I'm not entirely sure what those tasks are, which made the talk even more abstract. But if I was writing a mesh unwrapper for assigning texture coordinates, I think I'd really want to know about this stuff.

And hey, I won't use the phrase "discretize the mesh laplacian" elsewhere in this writeup, so this is my one opportunity.


B-Rep for Triangle Meshes

I remember Gino van den Bergen as having given a talk many years ago, I think about collision detection and measuring penetration depth for a variety of interesting geometric primitives. In this talk, he presented a pretty optimized representation of the familiar half-edge/winged-edge representation, optimized for triangle meshes, especially for dynamically cut meshes for "Farming Simulator". I won't get into the code here, but it's some pretty tight stuff, and if I needed to dynamically modify meshes, I should revisit his stuff.


Also

I spent some time between sessions using PyTracery to generate "LifePaths" for characters in a post-apocalyptic road warrior setting. I want to adjust the LifePath sim logic to have different probabilities for different events, and probably do an event-based sim, rather than a simple grammar generator. I'd also like to try to drive things backwards, so I could say "I need one crime boss and 10 street thugs - go!", but maybe the best way to go about that is to generate NPCs ahead of time and store them in a database for later retrieval.

Day 2 - Tuesday

Narrative Innovation Showcase

Several small talks (again!) about games not yet released,

Francisco Gonzalez presented "Lamplight City", a detective game where you're not railroaded into being a super-detective; you can be bad at your job, and the game will react, but not stop you.

Cara Ellison presented "Where the Water Tastes Like Wine", a roadtrip interactive fiction story, which tackled having different characters sound different by having different writers for different characters.

Greg Heffernan showed "The Norwood Suite", a graphic adventure game with a strong music theme. When characters speak, their speech bubbles get populated with words, and when each word arrives, there's a note from a distinctive instrument. Like taking the trombone wah wah sounds from the Charile Brown specials and passing it through "Peter and the Wolf". Grampa is an oboe.

Emily Short showed an "interrogation demo", where you're grilling a robot about a murder it witnessed (hello, Susan Calvin). There was a lot of interesting data in the knowledge graph, and the conversation was a means to explore that graph. The graph also had information about "narrative beats", so over time, the robot guided the conversation.

Navid Khonsari presented "Blindfold", a VR verite experience that used nodding and shaking of the head as the only user input while putting the player in a room with a member of a violent (terrorist?) faction.

Procedural Content Shotgun

Mitu Kandaker-Kokoris talked about the spectrum between agent driven stories and story driven agents.

Tanya Short talked about "maximizing the impact of generated personalities", which was recently on Gamasutra.

Tarn Adams of "Dwarf Fortress" talked about using personality traits to generate content. I didn't fully follow what he was saying, but it seemed really interesting. I want to take another run at it. There was some discussion of NPCs creating artifacts (statues, books) based on events in the game world, then those artifacts effecting NPCs later activities. Also, something about history being an allegory, which can provide structure for the NPCs. A lot to unpack.

Zach Aikman talked about using Cellular Automata and Hilbert Curves to create tiles and mazes for "Galak-Z". This was a very short version of a longer talk given at Unite, previously.

[somebody] talked about contextual barks, based on Elan Ruskin's "Left 4 Dead" 2012 GDC presentation, which I should watch.

Luiz Kruel talked about a procedurally generated FPS

Tyler Coleman talked about things to do with your random seeds, maybe seeding some stuff off of player ID, so it would never change for that player. I still don't buy that's really interesting, but maybe in a social game.


Crackpot AI Dev Talks

The premise of this session was off-the-wall ideas for techniques that might just work, or be interesting enough to pursue anyway.

Zach Aikman talked about synesthesia and generating music based on a color palette

Tyler Coleman proposed a layered AI memory, including a socially shared layer for the longest term memories

Mitu Khandaker-Kokoris demoed an AI bot that assisted a Massively Multiplayer game player who was being harassed ingame.

Luiz Kruel talked about a procedurally generated FPS

Rez talked about longform improv as a model for collaborative storytelling. An example of something not quite working, was playing Oblivion as a thief and ignoring the scripted story, just playing the systemic game. What if the game saw that, and served scripted story based on what the user did?



Stopping AI fires before they start

Andrea Schiel talked about a few cognitive biases that led to antipatterns in AI development
- because it's there: using the wrong engine because it's what you have
- "beware the goalie playing out": using idioms from the last system inappropriate to the current system
- "too many heroes": overlapping roles, duplicated code doing similar functionality (maybe simultaneously)


Can you see me now?

Eric Martel talked about sensor construction for AI NPCs.
One big takeaway is to put sensor locations on non-rendered bones, to allow the animators to put in the eye location in a deliberate place, rather than just put it on the head, which is noisy, and might not be synced the way you want. (sensor follows animation gives players the ability to get out of the way)


Bringing Hell to life with full-body animations in Doom

Lots of straightforward techniques, from delta correction to get jumps to land at the right spot, to focus tracking, to use IK to get the NPC to look at a target.


Indie Soapbox

Yet another rapid-fire session of microsessions

Brandon Sheffield advocated embracing your own sense of taste. Make a game that works for you, and go with it. "People identify with what they like more than what they do, from foodies to film buffs". His game is "Oh, Deer", a pseudo-3d driving game.

Tanya Short told us that self-care is important, and don't work all the time, it's not as productive, and you burn out.

Jarryd Huntley talked about indie rock bands, and how they're just like us.

Sadia Bashir talked about the importance of having a good process when making games

Marben Exposito told us that "People fuckin' love surprises", and showed a little bit of "Showering With Your Dad Simulator 2015".

Gemma Thompson talked about "owning your space", pushing for a broader notion of what an indie game developer is (not just Jonathan Blow in a coffee shop on his laptop).

Jerry Belich called for more industry people to work with academic people to share knowledge with the new crop of kids

Brie Code talked about techniques for public speaking

Colm Larkin talked about sharing the game early, including a tweet of the one-sentence game design (elevator pitch) for "Guild of Dungeoneers" when it was just a game jam idea

Jane Ng talked about thinking about your game as a product, and sometimes thinking of the potential player of the game, not just the player of the game. Product design is a huge thing.



To Be Continued

That's a lot of really short snippets, I'm frankly exhausted writing even that much. The next post [TODO link] will have 3 days of sessions, some of which will be as spartan as the above, maybe some will be fleshed out more.



 


Saturday, August 20, 2016

AxiDraw circles in Python

So, I got an AxiDraw 2-axis plotter (or, as I prefer to refer to it, "DrawBot") from Evil Mad Science - ordered it a while ago, just arrived about a week ago.

I drew several of the sample figures that came with it, including Barack Obama and Taylor Swift's signatures, which will be useful when I want to forge the signatures on the Obama-Swift treaty I'm writing up.

And then, me being me, I dug into the Python code to draw some test figures.

My first attempt was using the axidraw-xy code, which connects to the CNCserver node.js server, which yielded not entirely satisfactory results.



It seems that the AxiDraw's stepper motors need to be driven together or opposing to get axis aligned steps, and at equal magnitudes. CNCserver imposes some scaling and some clamping. I spent a little time trying to reverse those transformations, but decided that it was easier to take the Inkscape extension code and kill off the Inkscape-specific bits and make a standalone bit of code.

The results are promising:



The code I was working with provides functionality for starting from a stop, accelerating along the path, and decelerating to come to a stop at the end. So, for my circle drawing, I just draw a bunch of short segments, which means the head is lurching along the entire time. It seems like it wouldn't be too hard to pass in a set of points to connect, and base the exit velocity of one segment (and entrance velocity of the next) on the angle between the segments - for basically colinear segments, maintain full speed - for perpendicular or sharper angles, drop to a stop.

Still, it's satisfying to have a little bit of Python producing tangible results:



or, if that doesn't work: https://goo.gl/photos/fmmXhqagCtpUrCLZ9



If you want to mess around with this, first buy a plotter DrawBot, then grab my code from GitHub: https://github.com/tsmaster/axidraw/tree/master/inkscape%20driver



Monday, August 1, 2016

More-onoi


More thinking about Voronoi regions, and using them to generate irregular game tiles.

Actually, I haven't done a lot of new thinking, but I've been meaning to jot down some notes and open questions, so when I get time to work on this, I'll make sure I'm not missing things.

Before the questions, though - maybe you want to hit this link:

http://bigdicegames.com/TheTwenty/IVor/index.html

And hit 'R' after things settle down to restart it.

What that tool is doing:
  • places some number of "sites" (gray dots) on the screen, with a random radius from 24 to 40 pixels.
  • for each pair of sites A and B, constrains them to be no closer than the sum of the two sites' radii
  • for each site, constrains it to remain onscreen
  • repeat the above until there's no remaining movement
  • generate a voronoi diagram for the resulting locations
  • draw the diagram, leaving out line segments to infinity
Simple stuff. I'm using https://github.com/jceipek/Unity-delaunay for my voronoi generation, which seems adequate. I tried some other (downstream) forks of that code, and couldn't get stuff to work. I may fiddle with this version and upload my own unmaintained fork, because we need more of that.

So, some thoughts about what I see in that demo:
  • It's fast enough that I could probably regenerate the voronoi diagram every frame.
  • The caption says "interactive", and aside from pressing 'R', it's not.
  • I'm not entirely satisfied with the site topology - if you look at the bottom center of the picture above, you'll see one tallish thinnish tile with a bunch of sites clustered around it like a horseshoe or a little bit like the Saint Louis Arch. Maybe not very much like the Saint Louis Arch. It doesn't feel like the kind of connectivity I want. I suspect that if I get the Lloyd Relaxation step in, that kind of clustering might go away.
  • I'm not defining what's wrong with the horseshoe/arch clustering. I'm not sure I have a good definition. I think what's bothering me is the short edges. You can see other short edges elsewhere, and they bother me, too.
  • There are long edges in the diagram, like ones that go off the edge of the screen. I don't really care about those, as I intend to be generating these maps at larger than screen resolution.
  • There are occasionally places where a tile will be drawn, but the gray dot won't be drawn. That's almost certainly a bug in the way that I'm drawing my gray dots. I'm using Vectrosity for my line and dot drawing, and I like it, but it's a "retained mode" API, and I think I'm updating the dot list incorrectly, leading to some dots getting lost.
  • I generate all the dots at once. I could generate them adaptively, putting dots in areas that aren't densely filled.
  • I want to stick in some obstacles (walls, trees) and terrain types (open, rough, water) and plop a player-controlled character on there to get the feel of walking around. I meant to do that a week ago, but have got distracted with other stuff.
Ok, so that's what I've done. The point of the post was meant to be what my concerns and open questions are about this whole approach, what I'm trying to answer with these experiments.
  • This is a whole lot of work, is it worth it? That's the big question. I think most of the rest of the questions feed in to this one.
  • How do you handle straight-line effects? There's two parts of this, and maybe they have different answers. Let's think of two spell effects that one might have: Explosive Fireball and Ray of Embitterment. The fireball's effect might be centered somewhere in a tile, and effect everything "nearby". Is "nearby" defined in terms of tiles? Probably not. In order to feel right, I suspect that I want to draw an actual circle in screenspace (or in cartesian worldspace, not tilespace) and use that as my area of effect. Similarly for the ray, I'll want to trace out a long, thin rectangle, and use that. These aren't hard to do for a computer game, and could be approximated for a miniatures game using rulers and whatnot. Seems like it can be done. A variant of this is how to handle flying movement, but that's really the same thing, I think.
  • If the tiles represent different movement effects, what about directional effects like "uphill/downhill"? I think that I'm going to have to handle certain effects on a case-by-case basis. A short list of these features: uphill/downhill, rivers (going with, against, across the current), roads (some vehicles will be able to move at good speed as long as they stay on a road, that's logic inside the vehicle, not inside the map).
  • How does one meaningfully author a map like this? For regular tiled grids, or "continuous" maps, you can use a tiled map editor or a 3d terrain editor. For this stuff, it feels like the editing pipeline is going to be hard to use. Right now, I'm guessing that the world will be laid out as vector features (a road is a spline with a width, a forest is a polygon) which will then be used to generate the grid.
  • How does "facing" feel? One reason that I think that people like hex grids is that if your game mechanics takes facing into account, a hexagon provides a reasonable level of fidelity. Better than a square, and... well, there aren't a lot of other regular options to work with. I want to get some code running to really answer this for myself, but my feeling right now is that with short edges, facing will feel fiddly. With more uniform edges, maybe it'll feel better.
  • Do the adjacent tiles feel close enough for tactical combat? In this demo, tiles are supposed to be pretty close to the same size, though even now, it's not entirely working. If I have a melee unit in a small tile, and the neighboring tile is 3x as big, does that feel unrealistically far away? Or, if I'm standing in a large tile, maybe I have a lot of nearby small tiles (in a horseshoe arch cluster, perhaps) - are they all able to engage me in melee?
  • If a tile is large, should it permit multiple units inside it? Does that break the whole notion of tiles? I think I'm going to have to play around a lot to get the feel for this. Maybe with good smoothing, the problem goes away. I don't know yet.
  • Supposing I want units of different sizes, ranging more than one order of magnitude - is that a problem? What if the units aren't roughly circular in footprint? I'll almost certainly have small creatures in the game. Rats, or spiders, or something suitable for an annoying first encounter in the basement of the first building you walk into. But I think I'll also want a rock giant. Maybe some colossal creature striding through the ocean that you encounter. There's lots of possibilities. I also have this half-baked idea of segmented monsters, a little like the dragon in "Space Harrier", or the tentacles in games like R-Type. It's maybe weird to think of using those kinds of approaches for a tiled, tactical, turn-based combat RPG. Maybe not. My current thinking is that a giant unit would have a center point that moves just like any other unit, so maybe there's nothing special about a giant. And segmented serpents might just have a sequence of adjacent tiles that they occupy. Now that I talk about it, there's a pretty good canonical segmented creature already in gaming.
  • One thing that discrete tiles offer is a manageable set of choices, fighting analysis paralysis. Does getting rid of regularity work against this? Maybe. I'm hoping that with good UI, it'll be easier to decide where I'm going and be able to make a good selection.
  • But keyboard control is basically out, right? Probably. If there's somewhere between 4 and 8 neighbors of each tile that you visit along your move, there's unlikely to be good key-bindings to select the correct neighboring tile.
  • But let's say that some places you want regular tiling, can you support a square grid or a hex grid? Would it be possible to smoothly go from chaotic irregular grids to regular grids? Probably. A while ago, I did some experiments with this question, and the results weren't immediately successful, but I think there's potential.

Ok, so given all of those questions, I think my TODO list includes:
  • make a map with some obstacles and some different terrain types
  • put a character with facing on that map
  • build a UI that allows movement (with facing) on that map
  • put some other creatures on the map to "fight" with
So, yeah, basically make a game to figure out if this is how I want to make my game.

Saturday, July 23, 2016

Going Back to the Voronoi Well


I like hex maps. There's something pretty about them, and one of the first "serious games" I played - by which, I suppose I mean a game involving thinking, made for grown-ups - was on a hex grid. (That game was Outdoor Survival, derided as one of the worse Avalon Hill games, made on a bet, or a dare, or some other poor form of boardgame design inspiration).

I also dig maps with irregular spaces. Look at the spaces on the Risk board. OK, those are countries. How about the spaces on a Gammarauders board: https://boardgamegeek.com/image/118956/gammarauders?size=medium (still not a terrific game, but relevant to this discussion. Oh, and they're within larger hex tiles, to make layout interesting).

A while ago, I was doing some fiddling with using Voronoi Diagrams to make irregular polygonal tilings, with an itch to see if a computer RPG might use those as an interesting "grid" for a map.

Let's say your unit has a move of 8 spaces. And maybe the spaces are of different sizes, smaller on rough terrain, larger where it's smoother / flatter / clearer / easier. You can count out an 8 space path on the grid, and it's all easy. My barbarian guy only has a move of 6 spaces, and so he's not going to catch up to you, so long as you're trying to escape.

Irregular grids feel a little more natural - like something that'd be created by some natural process. Regular grids of squares or hexagons are obvious abstractions, lines laid down by some divine geometer.

One reservation I have with an irregular grid is that it assumes a single mode of travel - let's say walking. But what if your birdman unit wants to fly across the map? Seems like he would disregard surface terrain considerations (but he might have his own wind current issues to consider).

The above image is a Voronoi diagram of a bunch of vertices laid out in concentric circles. I've rotated each circle a random amount, to keep things from getting too regular, but you can still see regions where the spaces are nearly a square grid and others that look pretty close to a regular hexagon grid.

I'm considering implementing Lloyd's Relaxation algorithm to try to smooth out some of this, but it requires computing a centroid per tile, which is more work than I really care to do right now. I could do Laplacian relaxation, which is simpler, and might be just about as good.

I really just wanted to post the pretty picture.

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.