42 Astounding Scripts

MacOS uses Perl, Python, AppleScript, and Automator and you can write scripts in all of these. Build a talking alarm. Roll dice. Preflight your social media comments. Play music and create ASCII art. Get your retro on and bring your Macintosh into the world of tomorrow with 42 Astoundingly Useful Scripts and Automations for the Macintosh!

Jerry Stratton

Innovation takes an exasperatingly long time, and we live with it, though not graciously. — Wayne Green (80 Microcomputing Magazine October 1980)

Avoiding lockFocus when drawing images in Swift on macOS—Wednesday, July 29th, 2020
Lovecraft Lies Dreaming

Lovecraft lies dreaming…

Among the coolest uses of command line scripts in Swift on the Macintosh are those that intermediate between images and text. These are the kind of scripts that bring me back to ma jeuness of staying up into the morning hours programming.

My favorite of these wee hour efforts is a script I wrote for 42 Astoundingly Useful Scripts and Automations for the Macintosh to turn photographs into ascii art. I wrote it to do basically what ascii art used to be, an ingenious method of greyscaling images at very low resolution. But I’ve since extended the script to include color, color overlays, and random color, as well as sequential text instead of text chosen for its density.

I wrote another script more recently that takes standard input and converts it to an image of the text. Originally for converting tabular data to an image I now use it for taking paragraphs and wrapping them and justifying them or aligning them right or center. It is both a more serious program than asciiArt and more frivolous. It has pretty much only one use case, online outlets that accept images but not tables. If you’ve read 42 Astounding Scripts, this is an image-oriented variation of my alignTabs script and makeHTMLTable script.

Both asciiArt and text2image take text and create images out of the text. Almost all of the examples of creating images in Apple’s documentation and on sites such as stack overflow assume that you’re creating images to display to the screen. They use lockFocus() to create the image. Most of the few remaining examples continue to use lockFocus probably because that’s what gets used most often.

That’s a problem, because lockFocus does things that only make sense when displaying to a screen, such as automatically changing the number of dots in the image depending on whether your screen is a retina screen. This means that a command-line script written using lockFocus will change its behavior depending on what kind of a monitor you’re using.

While writing text2image I ran across Apple’s page recommending against lockFocus for creating image files. On that page, it said something, albeit without examples, that I hadn’t seen before:

The code in the block should be the same code that you would use between the lockFocus and unlockFocus methods.

Reversi in SuperBASIC on the Color Computer—Wednesday, July 8th, 2020

Reversi is a fun game to write on an early computer. I suspect one of the reasons it was so popular in early BASIC books is because it’s also an easy game to write on early computers. It’s very easy to get a version that basically works, even if it doesn’t work well.

I took the logic for this game from Tim Hartnell’s Giant Book of Computer Games. It was a fun game, but it didn’t handle everything it really ought to have. That was Hartnell’s style: provide a basic structure, and let the reader learn by adding to it. Among the things that needed to be added were:

  • Require a move by the human player if one is available.
  • Recognize more quickly that the game is over when the game is over1.
  • Disallow a move by the human player that doesn’t flip any pieces.
  • Recognize that the game is over if one player has no pieces. Sadly, I have lost all of my pieces while playing this not particularly smart game. My excuse is that I was often playing the game while distracted by programming the game.

And of course there were a lot of other changes I wanted to make so that the game would play better on the Color Computer.

Reversi checking moves

Checking to see if the player has any valid moves, and highlighting them as they’re found.

I decided it would be even easier to learn by adding to it, if I first rewrote it completely in superBASIC to make the logic easier to understand. As written, the game uses all of the block types currently possible in superBASIC: loops, switches, and both if/endif and if/else/endif. It’s a very good example of how to use superBASIC to write an old-school BASIC program.

While my next game project is going to use the Color Computer’s graphics screen, I decided to keep this one retro. The board is constructed using text, just as in Hartnell’s version, with ‘O’ for the human player and ‘X’ for the computer. This makes it easier to manipulate the board; for example, highlighting a move is as simple as adding 32 to the ASCII code for the character. The characters themselves are stored as numbers, making that sort of conversion even easier.

The computer’s tactics are pretty basic. It uses a few decent metrics to decide on what a good move is. These are in the findMove subroutine:

Convert PCBASIC code to TRS-80 Extended Color BASIC—Wednesday, June 10th, 2020
Tim Hartnell’s Reversi

One of the nice things about the older strategy games is that it’s easier to win…

I recently found Tim Hartnell’s really nice Giant Book of Computer Games. Hartnell strikes exactly the tone I was looking for with 42 Astounding Scripts. Breezy, informative, and filled with useful code.

While he writes his book for “Microsoft BASIC on an IBM PC” he specifically avoids anything that might make it unusable on other computers, “no PEEKs and POKEs, no use of graphic character sets, and no use of such commands as SOUND or PLAY. I’ve assumed you have access to READ and DATA, and that your screen is around 32 to 40 characters wide”.

This makes it very suitable for customizing for any of the old 8-bit computers such as the TRS-80 Color Computer line. The changes that need to be made to get these programs to run on the CoCo are somewhat rote, and mostly easily automated. So of course I wrote a script for that (Zip file, 6.1 KB).

  1. On the IBM PC, PRINT TAB started from 1, and printed at that character. In Extended Color BASIC, PRINT TAB starts from 0, and moves that many characters over. So the script reduces PRINT TABs by one. This is especially important for board games like reversi. You can also use --shift-tabs xx to further shift any PRINT TAB statement to the left. For example, Hartnell’s chess program prints at tab 9, which pushes the chess board just barely over the edge of the 32-character CoCo screen.
  2. The IBM PC uses a bare RND function to generate a random number between 0 and 1. Extended Color BASIC uses RND(0) for the same. Most of the time, Hartnell uses RND to generate an integer, by multiplying the real number by a whole number and taking the INT of that. The format and variations are complex enough that I chose not to try and convert that to ECB’s cleaner RND(x) function. Hartnell’s random numbers usually start at zero, whereas the RND(x) function starts at 1.

Since the Color Computer’s screen is 32 characters wide, I chose to make an attempt to reformat PRINT statements to 32 characters maximum. It works surprisingly (to me, at least) well. The script handles these in two different ways. For PRINT statements that are each on their own line, it collects the statements and then recreates them in a series of single-digit incremented lines. If they’re followed by an INPUT statement, the string from the INPUT statement is also merged into the PRINT statements.

Random colors in your ASCII art—Wednesday, April 29th, 2020

I recently wanted to put dollar signs inside a Texas shape for a blog post about local sales taxes. That, of course, is easy with the asciiArt script: just set up a single-character palette and use a solid two-color image of Texas. But I also wanted to highlight the potential patchwork of sales taxes that people will have to know just to sell things online or even to send things sold in-person to the customer’s home.

The obvious solution was to randomly color each character in the image. The asciiArt script in the book can handle colors, but not random colors. It can use the color of the main image or overlay the color of a different image. Adding a random color option wasn’t difficult, however, because the script already grabs the red, green, and blue components of the image in a central place.

Here’s how I added a random color option to the script. The first question is, how to request random colors? There’s already a request for an overlay image file. What I want now is to, instead, overlay random colors. So I’m going to use --overlay random. It will make no sense to use an overlay file and random colors at the same time. The colors have to come from somewhere, and if they come randomly the file won’t be seen, and if they come from a file the random colors won’t be seen. So combining those options into a single place makes sense.

That means changing the case for --overlay:

[toggle code]

  • case "--overlay", "-o":
    • overlayFile = popString(warning:"Overlaying requires an image to overlay.")
    • if overlayFile == "random" || files.fileExists(atPath: overlayFile) {
      • useColors = true
    • } else {
      • help(message:"File " + overlayFile + " does not exist.")
    • }
  • case "--palette", "-p":

The bold lines, lines three through seven, are the new lines. All it really changes is to add “random” as a valid value for --overlay. If the overlay string exists as a file or, if the string is the word “random”, that section of code does what it did before. Otherwise, it displays the script’s help text and quits the script.

Because overlayFile can now contain text that is not a file, the check for reading the overlay file has to be changed, too:

Older posts