Lux Absio Bervatum

Tuesday, March 30, 2021

Turning strings into pattern instructions with the hex translator

I thought it would be interesting to try to explain, step by step, how my Hex Translator thing turns strings into instructions. Specifically, how the first direction (for the 2nd cell of the pattern) is determined.

First, a few definitions: UniCh is the unicode value of the current character in the string. UniCu is the sum of the unicode value of the current character and the unicode value of every character preceding it. UniMx is the sum of all unicode values for all characters. StrLen is the number of characters in the input string. Constants are various primes with special focus on 48,271 and 2^31-1 (the 8th Mersenne prime).

Green bracketed text shows values and calculations for the example string "Sassafras." starting from the first character "S" (UniCh=83).

Let DirA = (StrLen + 389) times UniMx. [(10+389)*981=391,419]
Let DirB = mod(DirA, 701). [391,419 mod 701=261]
Let DirC = 48,271 times UniCu. [48,271*83=4,006,493]
Let DirD = mod(DirC + DirB, 2^31-1). The sum of DirC and DirB is way less than the modulus, so the modulo operation doesn't really matter here. [(4,006,493+261)=4,006,754; 4,006,754 mod 2,147,483,647=4,006,493]

Now we advance to the 2nd character, "a" (UniCh=97 so UniCu=180).

Let DirE = 48,271 times DirD. [48,271*4,006,493=193,410,022,334]
Let DirF = DirE + UniCu. [193,410,022,334+180=193,410,022,514]
Let DirG = mod(DirF, 2^31-1). [193,410,022,334 mod 2,147,483,647=136,494,284]
Let DirH = (DirG divided by 2^31-1) rounded to 16 decimal places if number of decimal places is greater than 16. [136,494,284/2,147,483,647=0.0635601040271856]
Let DirI = the last 7 digits of DirH. [0.0635601040271856 (last 7 digits)→ 0271856]
Let DirJ = the first 6 digits of DirI + UniCh. [0271856 (first 6 digits)→ 027185; 027185+97=27282]
Let DirK = mod(DirJ - 1, 6) + 1. [27282-1=27281; 27281 mod 6=5; 5+1=6]

Now we look up DirK's value on this table to get the direction:

6 = NW (northwest).

Why is this process so convoluted? I wanted to make the output hard to predict and ensure that relationships between different properties weren't obvious. Over many iterations the system got more and more complex. It isn't elegant, but I'm satisfied with how it behaves. The patterns it produces are what matter.

Sunday, March 21, 2021

How I make crosswords

I recently made my last crossword ("crossweird") for Tumbleweird. Coincidentally, it turned out to be my 50th published crossword. Here are all 50 together in chronological order:

This is meant to be an overview of how I make crosswords. My approach is a little unorthodox (overly verbose clues, non-rectangular/asymmetrical puzzle shapes, an obsession with Roman numerals, etc.), so it's not a how-to. Doing a lot of crosswords by mainstream crosswordists (is that a thing? syndicated puzzlemakers) would probably prepare a person better than hearing my process. But I'm going to explain it anyway.


I start in Excel, but any spreadsheet software should work. Google Sheets works fine. Sorting out snarls and making words fit together with as much overlap as possible is way easier with word/pattern search engines. OneLook is the best for this, no question. A2zWordFinder can be useful too; has some foreign language options. People by Initials is good for 2- and 3-letter strings. Wikipedia and Wiktionary go without saying. Once the puzzle is done, Inkscape to pretty it up. But Inkscape doesn't play nice with CMYK (at least, in my experience; even if the color tools in Inkscape say something is K-100 black I always seem to end up with rich black when I view the ink separations independently). So I take that output and use Scribus to make the colors behave themselves. Import the puzzle to InDesign, type up the clues, add extras like title, byline, etc. Done!

Making the Solution to the Puzzle

It helps to pre-format the spreadsheet by setting every cell to the intended font and sizing the rows and columns to make each cell square.

I usually try to begin with one or two "anchor" words meant to run the width and/or length of the puzzle. Here's an example:

STRANGERTHINGS is the Across anchor and DUFFERBROS is the Down anchor. This kind of synergy is nice because the Down clue can refer back to the Across answer (e.g., "9-Across: Netflix series that follows Mike, Lucas, Dustin, and Will as they contend with otherworldly forces in the 1980s (2 words)" and "21-Down: Creators of 9-across (2 words)"). Ideally, I can hang the rest of the puzzle off the anchors, though it doesn't always work out that way. I find making puzzles requires a lot of patience because oftentimes a great "mesh" of words turns out to be unresolvable and it's better to scrap it for something more elegant than to kludge it together with too many unconnected letters (i.e., letters with black cells on either side of them) and lazy clues (e.g., "D_ey__al_" (Dreysdale) to produce RSDE). Early on it felt like a waste of time, but I came to accept that progress requires a willingness to backtrack from dead ends.

Next, I try to work out at least one 4x4 section with no black cells. There are different ways to attack this. I like to pick one 4-letter word as a starting point, then focus on the letters in the center 2x2 section. It's easier when the center letters are common (re: dictionary letter frequency). And of course some combinations here are the kiss of death, like ?SN? or ?NS? (even though S and N are very common by themselves). In smaller areas like this, when word options seem equally good, I usually tilt toward the one that lets me alternate vowels and consonants in the crossing (perpendicular) words.

The Puzzle Grid & Numbering

Once the solution is done I end up with something like this in my spreadsheet:

Apply the borders and black cells:

Then I copy it over to one side, delete the text, decrease the font size, change cell alignment to top-left and number the Across and Down answers:

Important note on numbering: There's an established system for numbering the puzzle answers. Start with the leftmost cell in the topmost row. That's 1. Move across that entire row, left to right, skipping over gaps, and assign the next number to the next Across answer you encounter (ignore the Downs). Then move down one row and start at its leftmost cell. Assign the next number to the next Across answer you encounter. Repeat this process all the way down for all the Across answers. When all the Across answers are numbered, go back to the leftmost cell in the topmost row and repeat the numbering process for the Down answers.

My first puzzles were numbered incorrectly and I didn't realize it until my friend Molly explained the numbering system to me. Numbering answers correctly makes the puzzle easier to navigate. It also makes mistakes (like failing to number an answer) less likely.

Vector Post-Processing

With this part done, I select the "solution" grid and print the selection to PDF. Repeat for the puzzle grid. With Excel, this produces 8.5x11 in. pages with the content way up in the upper-left corner. That needs to be cropped properly and Excel does some odd things with PDFs that can lead to printing problems, so these get imported to Inkscape for cleanup. In Inkscape, I ungroup everything and convert it all to paths (including borders, which need Stroke to Path). Some elements can be nested, so I do a few rounds of Ungroup-Object to Path-Stroke to Path to make sure it's all normal paths with black fills and no strokes.

I find Excel doesn't get the numbers quite as far into the corners as I like, so I select those and tweak the positioning. While I have them selected, I make them all a tiny bit narrower (Transform > Scale > width 95%, apply to each object separately, Apply).

Once the puzzle grid looks the way I want, I select everything and use Union to make it a single object. Then I put a colored rectangle behind it, Duplicate the puzzle object, Difference the duplicate onto the rectangle (destroying the duplicate), Break Apart the rectangle, select the rectangle region outside the puzzle, delete that, select everything again, un-select the puzzle object, and Union the rest together. This makes a perfect uniform background for the puzzle cells. However, its edges are exactly identical to the puzzle's edges, which can cause tiny hairline defects when printed. So I select the background object, zoom way in, and use Dynamic Offset to pull the edge in about half the thickness of the puzzle's outer border. Then Object to Path on the background, change fill to white, and group with the puzzle. Now the puzzle can be dropped onto any background and the puzzle's cells will always have nice white backgrounds and everything will print the way it appears on the screen.

At this point, I dress the puzzle up a little. The style I like best, the one I've settled on anyway, is a black circle that totally encompasses the puzzle. I decorate the circle's black space with white vector traces of public domain clipart (thank you, British Library!) and stars. Like so:

My last step before saving as PDF is to go to Document Properties and resize page to content.

As I said earlier, Inkscape doesn't play nice with CMYK so I open that PDF in Scribus and force all the colors into CMYK with K-100 black. This is really important if you're designing for print because rich black will blur easily. Also, people touch the page when they're working the puzzle and if you stack lots of color in one place it'll rub/smear onto their skin much more easily. That's gross.

Layout, Writing Clues

With the puzzle part done, I place the post-Scribus PDF in InDesign and start writing the clues. I find it's very helpful to place the solution in the pasteboard area just off the page so I can refer to it easily.

If the puzzle is numbered correctly all the Across clues will be sequential and the Down clues will have one or more gaps in the numbering.

That's about it!

Friday, March 5, 2021

Hex translator XII

Made a particularly large one this time, 507 characters. The input is "the largest non-titanic prime which can be expressed as the difference of equal powers of two consecutive primes (i.e., 3^1061 - 2^1061)." (Credit to Shyam Sunder Gupta for submitting this number to Prime Curios!)

This is what the pseudocode looked like:

This was my 36th hexagon-translator-output-thing. Need a word for these. They kind of look like macromolecules. Hex patterns? Will think on it.

Wednesday, February 24, 2021

Hex translator number distributions issue

I was wrong, those numbers were biased. In more than one way. Hopefully fixed now. I made another worksheet to collect stats and the distributions look okay. The flatter these bars are, the more even the distribution (and the more "random" the output).

A recent one made with the new 2021.02.23A build, 74 characters:

Think I might stop posting new hex thingies (maps?) here for a little bit. At least until there's some kind of notable development. I'll keep throwing them in this Flickr album if anyone wants to see.

Tuesday, February 23, 2021

Hex translator XI

Made some more of these. I find myself rooting for the algorithm to do different things while building the map, like "oh, that's a neat 'bay' you formed there, hope you don't fill that in" or "another hollow hex with three dots in it? be less repetitive!" And I get discouraged when it spits out a lot of "muddy" colors in a row. So some of these are more exciting to put together than others.

This is a new build, 2021.02.21A. Overhauled how the numbers for lookup tables are generated from inputs; they should have a more uniform distribution now. (I was worried that the hodgepodge of simpler methods I was using before were introducing bias.) Here are the first three maps made with the new build, ordered oldest-to-newest. 101 characters:

89 characters:

90 characters:

I'm concerned that the three-dots-in-a-hollow-cell thing is coming up so often, but I think the system behind it is sound and this is just a weird coincidence.

Friday, February 19, 2021

Hex translator X

Did a few more of these over the last three days. Still on the 2021.02.09A build. First, this 99-character map which is taller than any other so far:

This next one uses dialogue from O Brother, Where Art Thou? as input. 107 characters:

And this one I did this morning. 115 characters:

Tuesday, February 16, 2021

Hex translator 9

A weird thing happened with this one, four red solids placed together at the western edge. More travel than usual. 120 characters.


Sunday, February 14, 2021

Hex translator 8

I like the shape of this one. 125 characters. 

Thursday, February 11, 2021

Hex translator 7

More changes. Sometimes symbols show up in cells now. And! I found this script that saves me having to type in all the CMYK values for the gradient shifts! I just adapted the spreadsheet to spit out "color,c,m,y,k" for each interstitial and save that as a .CSV, then run the script to convert that to a .ASE (Adobe Swatch Exchange) that I can load into InDesign (see screencap at right).

So here's the first thing I made with the new build, 82 characters:

Also, found this great resource for working with hex grids.

Saturday, February 6, 2021

Hex translator 6

Another one! 144 characters.

Sunday, January 31, 2021

Hex translator 5

I'm still on the hex translator. I've done five more since my last post. Still making adjustments to the system for generating them. Here they are in order from oldest to newest:

89 characters. I was unhappy with the spindly arms on this one, but it's what the translator spit out. Next:

57 characters. Next:

63 characters. This build (2021.01.29A) changed placement in a significant way. Previous builds would give a direction and a clockwise-anticlockwise tie-breaker. Go in the direction, if the way is blocked, rotate around the last completed cell in the tie-breaker direction till you hit an empty cell. With the 01.29A build, you go in the direction and if the way is blocked you just keep going in that direction till you hit an empty cell. I ended up reverting to the old method after the next build because I liked it better when the gradients stayed closer together. Next:

109 characters. See how the color shifts are less harmonious? Changed placement system after this. Next:

157 characters. New build (2021.01.31A). Replaced burgundy with "cloud" in the palette. Input string is a 157-digit prime number. Fixed palette generator so it'll never break again. Added "dupe" specials (duplicates the last cell as a solid roughly 3% of the time). Back to the old placement algorithm.

Tuesday, January 26, 2021

Hex translator 4

Another hex map, this time 82 cells with each cell's "code" in the middle.

Sunday, January 24, 2021

Hex translator 3

 Okay last one for today, this time a 93-character map:

Hex translator 2

Another, longer one. Fixed the palette thing.

 Here's an animation of the above image being generated:

New hex thing

I started messing around with my "tube translator" again and reworked it into something that generates shapes on a hex grid with more focus on colors (CMYK this time). Here's the first complete output (click for bigger):

(Rotated 90° anticlockwise to make it fit better... thus the arrow at the top.)

And here's the ugly spreadsheet that generated it:

Input string is the first bit of a recent horoscope my friend wrote. Will try to explain a bit about how this works later on. Also on my to-do list: Clean up the spreadsheet, fix generation of multiple palettes. One thing I like about this, though it's made everything way more complicated, is that nothing in the system is random. Everything in the final output is generated from the input string.

Tuesday, October 20, 2020

Terrible developments in M:tG

Magic: The Gathering is a great game that I've played off and on for the last 26 years. But the "promotional crossover" cards making their way into real gameplay (as opposed to Un-sets) really cheapens the game as a whole. This is a screencap from a game I played on MTGA last month where the opponent played a Godzilla monster. IIRC, this was in an Ikoria quick draft.

They've done similar promotional tie-ins with The Walking Dead and My Little Pony. I hope they put an end to this. Keep that stuff out of the canon.