ジェネラティブアート界のヴィンテージ「10 PRINT」の話


2018年02月23日
With
ジェネラティブアート界のヴィンテージ「10 PRINT」の話 はコメントを受け付けていません。

p5.jsでスケッチするようになってから、ちょくちょくYouTubeの「The Coding Train」というチャンネルをのぞいているのですが、そこで2017年の9月にアップされた「10 PRINT」という回を見つけました。

Coding Challenge #76: 10PRINT in p5.js(The Coding Train)

最初、「10 PRINT」というタイトルから内容をイメージできなかったのですが、↑の中で紹介されている↓のビデオを見て、いい年こいたオッサンである僕は瞬時に得心いたしました。これ見て「懐かしい…」と思ったあなたはまごうことなきご同輩。

10 PRINT CHR$(205.5+RND(1));:GOTO 10(YouTube)

「10 PRINT」とはつまり、↑のビデオタイトルにもなっている「コモドール64向けに書かれた1行のBASICプログラム」のことだったのですね。こういう「1行プログラム」のことを、英語では「one-liner」(ワンライナー)と呼ぶそうです。

このワンライナー自体の作者は不明ですが、原型となるプログラムは、1982年に米コモドールが発売し、日本にも輸入されていたホームコンピュータ「コモドール64」のユーザーズガイドに掲載されていたとのこと。

コモドール64 BASICのキャラクターコードでは「205」に「/」、「206」に「\」が割り当てられているのですが、「205.5」に「RND(1)」で発生した0~1の乱数を足すことで、そのいずれかをランダムに表示することを永久に繰り返すという、ただそれだけのプログラムです。「ただそれだけ」なんですが、画面に描かれていく迷路のようなパターンが楽しいですね。

コモドール64のキャラコード体系は「PETSCII」と呼ばれる、コモドール社独自のものなのですが、国産のレトロPCなどでも「/」「\」の両字形が入っているマシンであれば、ほぼ同じプログラムが動くと思われます。ただ、実際の見栄えはデフォルトの背景色や文字色、文字間や行間のマージンの取り方、ドットパターンなどによって個性が出るはずなので、いろんなマシンで動かして見比べてみると面白そうです。

MIT教授たちによるガチの「10 PRINT」研究本

そもそも、Shiffman先生がビデオで「10 PRINT」に言及したのは、こちらの本にインスパイアされてとのこと。

10 PRINT CHR$(205.5+RND(1)); : GOTO 10 (Software Studies) (Amazon.com)

ワンライナーそのままの書名で「328ページ」のペーパーバック…って、「10 PRINTについて328ページも書くことあるのかよ?」と思いつつ、よくよく探してみたら、公式サイトで全文のPDFファイルが無償公開されていました。うっかり買わなくてよかった(笑)。

10print.org

ダウンロードして読んでみたのですが、「10 PRINT」の構文解析(!)に加え、「10 PRINT」の出力に含まれている「迷路」「規則性」「ランダム性」などに関する考察、「10 PRINT」の亜種や移植版の紹介、ホームコンピュータの名機である「コモドール64」と、それに「BASIC言語」が搭載されたことの意義などについてガチに追求したなかなか面白い本でした。日本だと、レトロPCの同人ソフトや研究本がイベントで売られていたりしますが、それと似たようなノリを感じます。興味があればぜひご一読を。

「10 PRINT」をp5.jsに移植してみた

そんなこんなで「10 PRINT」のp5.jsへの移植をやってみました。今回、2パターン作っています。

●[その1]”10 PRINT”クラシック for p5.js(クリックすると別タブが開きます)

1パターン目は、ワンライナーである「10 PRINT」のコンセプトをできる限り忠実に継承してみようと試みたものです。むりやり「6行」にしてみました。

function setup() {
    createCanvas(600, 600);
    for (var i = 0; i < 36000; i += 10) {
        text(String.fromCodePoint(0xFF0F + 0x2D * floor(random(0, 2))), i % 600, 10 + floor(i / 600) * 10);
    }
}

Unicodeにも「/」「\」はあるのですが、残念ながら隣り合わせではありません。文字の表示には、ES2015でUnicodeから文字列を取得する「String.fromCodePoint」を使っています。「/」のコードは「FF0F」。「\」は「FF3C」。「FF0F」に16進数での差分である「2D」を足すかどうかを乱数で決定しています。乱数では「0」か「1」かを選んでおり、「2D」にその値を掛けることで「/」か「\」のどちらかがランダムに選ばれるようにしています。さらに文字の表示位置については、for文のカウント変数「i」の値を調整して、ひとつの値から、x座標とy座標の両方を算出するようにしました。これで2行減らしています(笑)。

残念ながらワンライナーでの再現は無理でしたが、「10 PRINT」のコンセプトは表現できているのではないでしょうか。

●[その2]”10 PRINT”リターンズ for p5.js(クリックすると別タブが開きます)

2パターン目は、Shiffman先生のお手本をベースにしたものです。文字を使うのではなく、各正方形グリッドの対角をランダムに選んで「line」で線を引いています。オリジナル要素として、グリッドのサイズ、背景色、線色をランダムに選んで、ループ実行するようにしてみました。

let x = 0, y = 0;
const spArr = [20, 40, 60, 100, 120, 150];
let sp = spArr[0];
let r = 255, g = 255, b = 255;
function setup() {
	createCanvas(600, 600);
	background(0);
	strokeWeight(sp / 5);
}
function draw() {
	stroke(r, g, b);
	let flag = floor(random(0, 2));
	switch (flag) {
		case 0:
			line(x, y, x + sp, y + sp);
			break;
		case 1:
			line(x + sp, y, x, y + sp);
			break;
		default:
			break;
	}
	x += sp;
	if (x >= width) { x = 0; y += sp; }
	if (y > height) {
		sleep(2000);
		sp = spArr[floor(random(0, 6))];
		strokeWeight(sp / 5);
		x = 0;
		y = 0;
		r = floor(random(0, 256));
		g = floor(random(0, 256));
		b = floor(random(0, 256));
		if (random() > .5) {
			background(0);
		} else {
			background(255);
		}
	}
}
function sleep(waitTime) {
	let startTime = new Date();
	while (new Date() - startTime < waitTime);
}

コードは長くなりましたが、これはこれでイマ風です。…と、これを作っていて別のスケッチのアイデアが浮かびましたので次回はそちらを。