Warmth – an attention engineering game

Core Concept

This is an idea for a shared awareness based exploration and building game called Warmth. The core concept of Warmth is cultivating, directing and then using a magical mana-like resource called “Warmth.” The mechanics of warmth generation, collection, and use encourage emergent game play that creates cozy, fractal patterns of building and interaction. Warmth itself manifests as a faint fire like glow which can be collected by the player for various uses. Continue reading

Python Scripts

Over the years I’ve written quite a few python utilities. Most of them are really short, and too specific to be useful to others. Those that aren’t are so long that they don’t feel elegant enough to share.

And then, between these two extremes, are the gems that I find myself coming back to time and again. I thought I’d share these with you. Keep in mind that all of these are covered by the Paul Spooner “IP is Wicked Nonsense” license, and you are encouraged to evaluate them on their own merits as distinct from their history. If you insist that the origins of ideas are important, then go pledge your support to my efforts.

TextOddifier.py is a text manipulation script to convert letters in UTF-8 to fairly similar looking letters. It makes text that looks like this ḽӧœĸ ŀįҟԙ ҭԡ༑ṩ ѩʼnᵴťӕаԂ. You can find the source below, or through the link at the start of the description.

# Similar letter substituter
# To make text look a bit strange

from random import choice

SLD = { 'A':'ĀĂĄАѦѨӐӒӔḀẲⰡ⍲ᗗ','a':'āăąаѧѩӑӓӕḁẳ⎀',

def oddify(text):
    result = ""
    for i in text:
        try: result += choice(SLD[i])
        except: result += i
    return result

s = input("enter the text you want to oddify: ")
#s = "I don't even really know how this is going to work any more"

input("Press enter when done:")

BaseConverter_py.py is a number base converter that we collaborated on to convert numbers to and from arbitrary radix. The neat thing about it is it works on floating point numbers as well as integers. The example (and test case) is 135.5 converted to base 12 is B3.6. Going the other way around, S4 in base 35 is 984 in decimal! You can find the source below, or through the link at the start of the description.

# dozinal.py

BASE = 12
PREC = 8

def compute_glyphs():
	GLYPHS = {}
	VALUES = {}

	for i in range(BASE):
		if i < 10: GLYPHS[i] = str(i)
		else: GLYPHS[i] = chr(i+55)

	for i in range(len(GLYPHS)):

def rebase(num):
	if len(GLYPHS) != BASE: compute_glyphs()
	if num < 0:
		sign = '-'
		num = -num
	else: sign = ''
	whole = int(num)
	frac = num - whole

	whole_parts = []
	frac_parts = []
	prec = PREC
	while prec > 0:
		prec -= 1
		frac *= BASE

		part = int(frac)
		frac -= part
		if part == 0: break


	while whole > 0:
		mod = whole % BASE
		whole = whole // BASE
	if len(whole_parts) == 0:
	if len(frac_parts) == 0:
		return sign + "".join(reversed(whole_parts))

	return sign + "{}.{}".format("".join(reversed(whole_parts)),

def debase(string):
	if len(GLYPHS) != BASE: compute_glyphs()
	if string[0] == '-':
		negative = True
		string = string[1:]
	else: negative = False
		whole_parts, frac_parts = string.split(".")
		whole_parts = string
		frac_parts = ''

	whole = 0

	for idx in range(len(whole_parts)):
		whole += VALUES[whole_parts[idx]]
		if idx < len(whole_parts) - 1:
			whole *= BASE

	frac = 0
	max_idx = len(frac_parts) - 1

	for idx in range(len(frac_parts)):
		part = frac_parts[max_idx - idx]
		frac += VALUES[part] / BASE

		if idx < max_idx:
			frac /= BASE

	result = whole + round(frac,PREC)
	if negative: return -result
	return result

TestConvert = 135.5
TestDozenal = rebase(TestConvert)
print("{} converted to base {} is".format(TestConvert,BASE), TestDozenal)
ConvertedBack = debase(TestDozenal)
print("{} in base {} is".format(TestDozenal,BASE), ConvertedBack, "in decimal")
if TestConvert == ConvertedBack: print("success!")
else: print("Something went wrong")
print("Assign BASE to set the number base,\nand PREC to set the precision.\nCall rebase() to convert,\nand debase() to convert back to decimal.")

Renamer.py Is a short program I wrote to do simple renaming operations on files. It only operates on the files in the folder, so it’s pretty easy to target. I include it here mostly as a syntax reminder.

# Rename files to add "_"

from os import rename, listdir
thesefiles = listdir()
target = "Prefix"
tlen = len(target)
	for f in thesefiles:
	if f[:tlen] == target:
		n = f
		n = n[:tlen] + '_' + n[tlen:]
		rename(f, n)

mcm_page.py is kind of an odd one. I really like the McMaster-Carr website, and enjoy browsing their catalog for inspiration. Time was when the catalog was paper that you could turn to a random page and peruse it. However, the online catalog is so efficient at delivering what you want that this becomes difficult. I’d also like to ensure that I don’t keep seeing the same page over again, at least until I’ve gone through the whole catalog. This script does all of that, opening a random page of the catalog when you start it, and allowing a save file listing all the pages you haven’t visited yet. Could be easily modified for other things… monte-carlo webcomic binges for example.

# opens a random McMaster Carr catalog page
from random import choice
import webbrowser

# 3873 fetched on 2017-09-20

    f = open('mcm_page_numbers.txt','r')
    maxpgraw = f.readline()
    raw = f.readline()
    maxpg = int(maxpgraw)
    rem_pgs = eval(raw)
    if maxpg == HIGHEST_PAGE_NUMBER: pass
    elif maxpg > HIGHEST_PAGE_NUMBER:
        while len(rem_pgs)>0:
            if rem_pgs[-1] > HIGHEST_PAGE_NUMBER: rem_pgs.pop()
            else: break
    elif maxpg < HIGHEST_PAGE_NUMBER:
        for i in range(maxpg,HIGHEST_PAGE_NUMBER+1):
    else: print("Something went terribly wrong")
    rem_pgs = [i for i in range(1,HIGHEST_PAGE_NUMBER+1)]

inchoice = ""
print('Enter to bring up a McMaster page\n"s" to save, "sc" to save and close, "p" to print')
while len(rem_pgs) > 0:
    printflag = False
    if len(inchoice)!= 0:
        inchoice = inchoice.lower()
        initial = inchoice[0]
        if initial == 's':
            f = open('mcm_page_numbers.txt','w')
            if inchoice == 'sc': break
            inchoice = input('Saved :')
        elif initial == 'p':
            inchoice = input('Those are the currently loaded indicies :')
    idx = choice(range(len(rem_pgs)))
    chosen_page = rem_pgs.pop(idx)
    inchoice = input('Page {} queued:'.format(chosen_page))