Sunday, March 31, 2019

Making a G+ Sendoff

I'm in the last few hours, as I write this, of Google+, the community-oriented social media site. Google will be (will have, by the time you probably read this) closing it down. The site never got a huge following, though there were people who really enjoyed using it.

I wanted to make a send-off in one way or another. I was thinking about using my AxiDraw pen plotter machine to draw a picture to G+, but that didn't click for me. And then I thought that it'd be fun to have an Apple ][ welcome G+ into the afterlife, a place where systems go after they're shut down for good.

First, I started up LinApple, an emulator of an Apple //e, and wrote a test program into it that would print some text to the screen, one character at a time, reminiscent of reading chat on an old BBS system at maybe 1200 baud.

Aside: years ago, I bought a 1200 baud modem for my family's Apple IIgs, and Dad was suspicious of what purpose I'd put it to. I pointed out that I could dial in to the county library and reserve books. Also, there were BBS systems where I could send messages and play games, but I knew that those purposes would be less compelling to Dad. So, Dad, I bought that modem so that I could remember using it and remember using Google+ and see the similarities. Probably still not compelling.

Listing 1

As you can see here, I first clear the screen and set the cursor to the upper left corner of the screen (Line 10), then I take two lines of text, assign them to the string variable A$ and call out to a subroutine. (Lines 20-50). That subroutine iterates through the line, printing one character at a time, then calling an additional subroutine (Lines 1000-1020), which simply spins, slowing down the program, making the text scroll onto the screen at a readable rate. (Slowdown from lines 2000 to 2020).

Interestingly, there's a bug in this code - the subroutine at 2000 doesn't return explicitly. I guess that it reaches the end of memory, knows that it needs to return, and goes back to line 1030.

At 1030, we continue on to the next character in the string, then at 1040, we print nothing other than a newline, terminating our printing to that row of the screen, automagically moving to the left and down one row. Later, we'll see scrolling, as well. All handled by the system. BASIC had a lot going on that I took for granted as a kid.

So, that structure seemed to work. I set out to write a blort of text that would be long enough to be fitting, short enough to be readable. I knew I didn't want to do text editing in my emulated Apple, so I copied this code out of the emulator and onto my Linux machine. Well, it was already ON my Linux machine, just in a disk image that the Apple emulator could read, but my Linux machine couldn't usefully edit.

So, I used AppleCommander to "export" the BASIC program to a text file, which I saved as reference.

The text file I wrote in emacs, because a) of course I did, and b) emacs is pretty good for editing fixed-width text files, which is the sort of thing that I wanted. It's got word wrapping, which made my life easier, too.

So, I wrote a page and a half or so of text, saved that out as a text file.

This next bit is perhaps unnecessary, but I wrote a Python script (again, because of course I did) that read the lines of my text file and wrote out a BASIC program that would print those lines to the screen. Sort of a compiler of sorts, that compiled a text file to BASIC.

The structure of the output file was the same as my test BASIC file (Listing 1), I just had a lot more calls to the line printing subroutine; one each for each line in the text file.

Listing 2


With this, you can see a few things. For one, you can see that emacs is happier providing syntax highlighting for Python than it was for BASIC. Maybe I don't have the Applesoft BASIC major mode installed. The structure is pretty simple - read all the source text file into memory, write a preamble, write out instructions to handle each line, and then write the closing matter, particularly the subroutines.

The header is super straightforward:

Listing 3


All it does is use the HOME command to move to the top left of the screen and clear it. You'll see that I also increment the line number by a healthy 10 numbers and return that.

Kids these days with their IDEs and their structured programming languages, they don't appreciate the value of leaving a healthy amount of space between line numbers, so that you could go back and add in extra commands if you needed to later.

Listing 4


This simply takes a provided string of text (which I had read from my text file) and generate a line of BASIC that assigns that string into the A$ string variable, then on the same line (something done more in BASIC than any other language I've ever seen) invoked the print subroutine. Again, I increment the line number and return.

Listing 5


And that wraps up the BASIC output, and also the Python script. I just write out the code to print one character at a time, placing that subroutine at line 5000, because that seemed like a safe space. Just to be sure, though, I assert that my text printing body of the code hasn't pushed us past 5000 before we got here. Similarly, I have the delay subroutine at 6000.

So, I ran the program, and ran into a few bugs - I had forgotten the semicolon on "PRINT MID$(A$,I,1);" - the semicolon means "print this string, but do not move the cursor afterwards", which achieves the teletype incremental progress. I had also forgotten the carriage-return (again, the kids don't remember typing on a typewriter where there was a physical lever that would RETURN the physical cylinder (the CARRIAGE) such that the typewriter would go on from the left margin.

I fixed those things up, tweaked the text, and output my WELCOME.BAS output file.

I struggled a bit with AppleCommander, trying to get the BASIC code back onto the disk image that the emulator would use. The tricky bit was that Applesoft BASIC is stored on floppies in a "tokenized" format, not in plain text. This takes one step off the job of the interpreter at runtime, and it makes it more efficient to save BASIC programs to a 140k floppy.

So, I needed to figure out a way to take my plain-text WELCOME.BAS file and tokenize it, and store the tokenized output onto the disk image.

Turns out, AppleCommander has a command-line version with a -bas option that does exactly this. Almost exactly this. It isn't perfect about carriage return / line feed combos, so I tinkered with that, and eventually got my WELCOME.BAS onto a disk image.

I actually had some shenanigans with getting it onto the disk image that I wanted to use, which took some rebooting of my emulator, but in the end, I got the program running as expected.

I fiddled with the display options to get the green monochrome monitor effect, and set out to record the results. The first recording I did was using byzanz, a recorder that outputs an animated GIF. This has been effective enough for many of my previous projects, so I fired it up, and got pretty good results. I loaded the output into GIMP, and cropped the image to the size I wanted, and this was the outcome:

Figure 1 - Animated GIF

Good enough for a post to Google+. But I'm never sure if an animated GIF is really going to make it all the way to the viewer without being resampled, reprocessed, and ultimately de-animated. So, maybe that's not good enough. Also, somehow, there was a glitch of random white rectangles. I don't know what that was.

So, I used SimpleScreenRecorder to capture a movie (MPEG?), suitable for upload to YouTube, in case a GIF (appropriately enough, super old technology) doesn't work into the future. SimpleScreenRecorder has a lot of good options, including allowing me to tweak my recording window, turn off recording the mouse, turn off sound, all good things for this project. And, boom, I uploaded it to YouTube, and by the time that I had filled in the metadata, the upload and processing were complete, and my little bit of remembrance was ready to go live.

Figure 2 - Video on YouTube


At this point, I used the following technologies in this project:
  • LinApple
  • Ubuntu Linux
  • emacs
  • Python 2.7
  • Applesoft BASIC
  • AppleCommander 1.5.0 (GUI and command-line)
  • GIMP
  • byzanz
  • simple screen recorder
  • Google+
  • YouTube
  • Blogger
Seems like a lot, and a big part of writing this blog post was to capture the workflow in case anybody (mostly, my later self) could re-use a part of that flow for later projects.

Because I am putting myself to the fullest possible use, which is all I think that any conscious entity can ever hope to do.

Farewell, G+, we will miss you.



Saturday, March 16, 2019

Run/Walk: Kirkland Shamrock 5k

The weather forecast was highs in the 60s, but that doesn't equate to temperatures during the event.

Finish photo

Another year, another St. Patrick's Day themed run. This one took us from the marina park, up the hill to the cross-Kirkland connector trail, and then down through residential roads. The hills were hilly, the temperatures were comfortable, and the roads were dry.

If you can make out a time on the clock on the finish photo, it would say something over an hour, which I want to disclaim, as we were in the second half of the third wave, so there was well over 10 minutes on the clock before we got started. 50 minutes is still not a lightning-fast time, but for a casual jog/stroll, it's fine. I'm content, if not proud.




Sunday, November 25, 2018

Numberphile's "Epic Circles" easy bit

So, I was watching a little bit of Numberphile on YouTube, like you do before you get up on a lazy Sunday.

I was watching the "Epic Circles" video which talks about finding the diameter (or radius) of successive circles in a "Pappus Chain". I've played around in this space, playing with circle inversions, flashing back to a particularly bad math professor for my complex analysis class, but it's all still pretty cool stuff.

22 minutes and 20 seconds into the video, Simon Pampena has something like this that he's working with:

And he makes the claim that the smaller circle has a quarter the radius of the larger circle, so R/4 = n in my diagram. I've clearly redrawn the diagram, and am using R to mean something different than he is, and I've introduced n, which shouldn't be too scary. In any case, what we've got is a square of side R, with a quarter circle of radius R with its center at one corner, and a half circle of radius n tangent to the quarter circle, such that the center of the half circle is on the square and the top of the half circle hits that upper right hand corner. The diagram isn't perfect, but it's close.

In the video, Simon just zips past the claim that R/4 = n and it threw me for a bit - where did that come from? So, I took out some graph paper and doodled a bit. Let's first rename things again, making this into a unit square:


In this picture, I've drawn a line connecting the centers of the two circles. You'll see it goes through the point of tangency. (That's obvious, right?)

So, the radius of the large circle is now 1, and I've renamed the radius of the small circle x, just to make things prettier later on.

One thing I thought about halfway through working it out as I describe below is that maybe there was some well-known relationship going on here, and I did notice this:

That is, if we scale up the square to side length 4, we're asserting that the little circle is now a unit circle, and that makes the red diagonal the hypotenuse of a 3:4:5 right triangle. Ok, that's verifying the claim, but that's not really what I wanted - I wanted to derive x from the previous diagram. And now it occrus to me that x in this diagram is scaled up from x in the previous diagram. Don't get confused, this was a tangent. Sigh, math pun.

Ok, so going back to the second diagram, we have that same right triangle which has the red line as a hypotenuse. The length of the hypotenuse is:

hypotenuse = 1 + x

because it's the sum of the two radii of the circles, 1 and x. The height of the triangle is

height = x - 1

because the height of the square is the radius of the big circle, 1, less the radius of the small circle, x. And the width of the triangle, let's not always see the same hands, is

width = 1

because we said so.

And here's yet another picture of that:


We're nearly done now. All we have to do is hit that triangle with our Pythagoras hammer and we get:

hypotenuse ^ 2 = width ^ 2 + height ^ 2

(1+x) ^ 2 = 1 ^ 2 + (1 - x) ^ 2

1 + 2x + x^2 = 1 + 1 - 2x + x^2

And then we cancel and rearrange. I have to admit that it took me a few tries (I claim it's because I still had that lazy Sunday morning brain on), but if you're careful, you cancel out the x^2 terms, pull the -2x over to the left, pull a one from left to right, and get:

4x = 1

and so

x = 1/4

Which is what we believed all along; the small circle is 1/4 the radius of the big circle, and math works, and I can go back to bed.

Monday, November 19, 2018

GDC 2017 Part II : Main Conference Notes

Eesh, I've found this half-written post languishing for practically 2 years now. I could go through my notes and try to finish the post, but that's not going to happen. And maybe the notes are of some use in the state they're in.

Posting This for a Friend

S. John Ross is conducting an experiment of sorts, hosting a document in the cloud, but not in the way that I do when I upload a thing to Amazon. Instead, he sent out copies to folks to host on their own personal website, with the hope that other people would host it, and so on and so on. (And they tell two friends....)

So, if you want to read about Medieval Demographics Made Easy, you've come to (one of many of) the right place(s).

It's late Medieval, it's European, so it hits at what a lot of straight-from-the-box fantasy is going for, but you can adjust if your needs are different.


Share and Enjoy.

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.