15.10.2009

Emacs shortcuts

C-y paste
C-w cut
M-w copy
M-space start/end select
C-_ undo and redo

C-v page down
M-v page up
M-n row down
M-p row up
M-f word forward
M-b word backward
C-a/C-e go to start/end of row
C-home/C-end go to start/end of file

C-x C-c quit
C-x C-s save
C-x C-w save as
C-x C-f open

M-x slime start Slime(clojure) environment
C-c C-k compile and run

C-x b select buffer
C-x <left> prev buffer
C-x <right> next buffer

C-x 1 show only current window
C-x 2 split horizontally -
C-x 3 split vertically |
right mouse button on window bar closes window

M-x color-theme-select select color theme (slightly bugged in win32)

C-z suspend Emacs
C-c I inspect class
M-. jump to definition

plugins:

clojure-mode
color-theme
ido-switch-to-buffer
winner-undo
C-x r w / C-x r j
elscreen

29.8.2009

Emacs, Clojure and Windows

How to: Latest Clojure in Windows Vista (and others) with EmacsW32

Plan A:

  1. Download EmacsW32 and install it from: http://ourcomments.org/cgi-bin/emacsw32-dl-latest.pl. You need to set HOME environment variable to point to your home directory. Note: the path is case sensitive! Otherwise Emacs will write all its stuff into users AppData directory.

  2. Install ELPA, copy the following to *scratch* buffer in Emacs:
    (let ((buffer (url-retrieve-synchronously
    "http://tromey.com/elpa/package-install.el")))
    (save-excursion
    (set-buffer buffer)
    (goto-char (point-min))
    (re-search-forward "^$" nil 'move)
    (eval-region (point) (point-max))
    (kill-buffer (current-buffer))))
    Place cursor right at the end of the last parentheses and press CTRL-j, which will run the code.

  3. M-x means press ALT-x in Emacs, write the text after it, and press enter. Tab completion works. Try package- to find out different commands.
    M-x package-install
    clojure-mode (press enter)

  4. At this point you need to install Git. Best way to do this in Windows Vista seems to be msysgit at this point. One could also install Git through Cygwin, but installing Cygwin just for Git seems a bit too much work.
    msysgit is found here: http://code.google.com/p/msysgit/downloads/list. Use the full installer.
    Personally I don't click Windows integration on, because it throws crap into my context menu, which is supremely annoying.

  5. Download and install Apache Ant. Set it into your path. This includes downloading and extracting the archive, setting ANT_HOME to Ant root, Ant bin directory into PATH, and JAVA_HOME pointing to JDK root (if you haven't already).

  6. M-x clojure-install. This will take a while as it downloads everything required from Git repositories and compiles them. I used c:/code/clj as my Clojure installation root.

  7. Add (clojure-slime-config "PATH") to your .emacs config file, where PATH is the path to your Clojure installation, which you specified during M-x clojure-install.

  8. Optionally you can M-x package-install paredit for some additional lispy goodness.

  9. Read up some documentation on Emacs, SLIME and Clojure. Happy hacking!

The installation might still have some warts which can be fixed by editing .emacs. Add the following to the end:
(clojure-slime-config "c:/code/clj")
(add-hook 'slime-connected-hook (lambda () (require 'clojure-mode)))

I don't like the toolbar so (tool-bar-mode -1) removes that.

Additionally, you might want to include additional libraries into Java classpath, which can be done by writing the following into .emacs configuration file, before package-initialize:
(setq swank-clojure-extra-classpaths (list "c:/code/java/libs/swt/swt.jar" "c:/more/java/libs/foo.jar"))

Plan B: Install Clojure Box, which uses Clojure 1.0.0

24.1.2009

Image to ASCII art with Python


Yes, it's very slow, but it's also quite cool, and a fun hack in a bit over an hour. I thought of adding error diffusion algorithm to smooth color slides, but because of so low "pixel" size, it doesn't seem worth it. Otherwise, I'm out of ideas how to match the characters better to pixels.

Script works also for variable width fonts. But they look awful compared to fixed width ones.

The actual script will be posted soon...

Update 1: Trying to use proper latin-1 character set in Pygame seems to be more difficult than previously anticipated. Full algorithm and funtionality: 1 hour, finetuning and debugging: 10 hours.

Update 2: Working script

Update 3: The whole thing grew a bit too large and complex for simple pasting. So I put it at Google Code. here

Now supports numpy, SMP and variable width fonts.

14.6.2008

Messing around with Python 2D arrays

So I wrote a simple script to render some Perlin noise. It's a fast hack, lot's of redundant code. It works and also shows that Python is kinda slow when dealing with large 2-dimensional arrays. Of course using linked lists as arrays is a bad idea. (I later learned that access by index for Python lists is O(1)). So what I'm going to do here is to try out Numpy to optimize my code.

Update: Some benchmarking of my original script and Manu's numpy version. Thanks, Manu!
Original script: 42.360 seconds



import random
import math

import pygame
from pygame.locals import *

class GFX():
def __init__(self):
pygame.init()

self.display_flags = DOUBLEBUF
rect = self.width, self.height = 640, 480

if pygame.display.mode_ok(rect, self.display_flags):
self.screen = pygame.display.set_mode(rect, self.display_flags)


def linear_interp(a, b, x):
return a * (1 - x) + b * x

def cosine_interp(a, b, x):
f = (1 - math.cos(x * math.pi)) * 0.5
return a * (1 - f) + b * f

def cubic_interp(v0, v1, v2, v3, x):
p = (v3 - v2) - (v0 - v1)
Q = (v0 - v1) - p
R = v2 - v0
S = v1

return P * x ** 3 + Q * x ** 2 + R * x + S


class Arr:
def __init__(self):
self.arr = None

def size(self, w, h):
# Sanity checks
if w > 400 or h > 400:
raise Exception("Array size too large.")

self.arr = [[0] * w for i in range(h)]

def noise(self, w, h):
# Sanity checks
if w > 400 or h > 400:
raise Exception("Array size too large.")

print "noise"

# Create 2D array
self.arr = [[0] * w for i in range(h)]

# Fill it with noise
for i in range(h):
for j in range(w):
r = random.random()
self.arr[i][j] = r

def smooth(self, ite):
print "smooth"

h = len(self.arr)
w = len(self.arr[0])

for ps in range(ite):
x, y = 0, 0

for i in self.arr:
for j in i:
lp = self.arr[(x - 1) % w][y]
rp = self.arr[(x + 1) % h][y]
up = self.arr[x][(y - 1) % h]
dp = self.arr[x][(y + 1) % h]
mp = self.arr[x][y]

self.arr[x][y] = (lp + rp + up + dp + mp) / 5

x += 1
x = 0
y += 1

def normalize(self):
print "normalize"

h = len(self.arr)
w = len(self.arr[0])
x, y = 0, 0

max = 0
min = 1
# Find min and max
for i in self.arr:
for j in i:
val = self.arr[x][y]
if val > max:
max = val
if val < min:
min = val

x += 1
x = 0
y += 1

x, y = 0, 0
mult = 1 / (max - min)
for i in self.arr:
for j in i:
self.arr[x][y] -= min
self.arr[x][y] *= mult
x += 1
x = 0
y += 1

return self.arr


def add(self, arr2):
w = len(self.arr)
h = len(self.arr[0])

x, y = 0, 0
for j in self.arr:
for i in j:
self.arr[x][y] += arr2.arr[x][y]

x += 1
x = 0
y += 1

def div(self, val):
x, y = 0, 0
for j in self.arr:
for i in j:
self.arr[x][y] /= val

x += 1
x = 0
y += 1

def cosine_resize(self, mult):
# Sanity checks
if len(self.arr) * mult > 400:
raise Exception("Array size too large (tried resizing).")

print "linear resize"

h = len(self.arr)
w = len(self.arr[0])

w2 = w * mult
h2 = h * mult

arr_new = [[0] * w2 for i in range(h2)]

x, y = 0, 0
for i in self.arr:
for j in i:
p0 = self.arr[x][y]
p1 = self.arr[(x + 1) % w][y]
p2 = self.arr[x][(y + 1) % h]
p3 = self.arr[(x + 1) % w][(y + 1) % h]

for ny in range(mult):
for nx in range(mult):
v0 = cosine_interp(p0, p1, float(nx) / mult)
v1 = cosine_interp(p2, p3, float(nx) / mult)
arr_new[x * mult + nx][y * mult + ny] = cosine_interp(v0, v1, float(ny) / mult)

x += 1
x = 0
y += 1

self.arr = arr_new


def render_arr(screen, arc):
print "render"
x, y = 0, 0

arr = arc.arr

size = len(arr)
for i in range(screen.get_height()):
for j in range(screen.get_width()):
val = arr[x % size][y % size]

if val > 1:
val = 1
if val < 0:
val = 0

val = int(val * 255)
val = val % 256

color = (val, val, val)
screen.set_at((x, y), color)

x += 1
x = 0
y += 1


gfx = GFX()

run = 1
clock = pygame.time.Clock()

pw, ph = 256, 256
depth = 5

arr = []
farr = Arr()
farr.size(pw, ph)

# Generate perlin noise
for i in range(depth):
arr.append(Arr())

d = 2 ** i

arr[-1].noise(pw / d, ph / d)
arr[-1].smooth(3)
arr[-1].cosine_resize(d)
arr[-1].div(2 ** (depth - i))

farr.add(arr[-1])

farr.normalize()
render_arr(gfx.screen, farr)

while run:
events = pygame.event.get()

for event in events:
if event.type == QUIT:
run = 0

pygame.display.flip()

clock.tick(60)

Numpy: 00.639 seconds!


import random
import math
import time
import numpy

import pygame
from pygame.locals import *

class GFX():
def __init__(self):
pygame.init()

self.display_flags = DOUBLEBUF
rect = self.width, self.height = 256, 256

if pygame.display.mode_ok(rect, self.display_flags):
self.screen = pygame.display.set_mode(rect, self.display_flags)


def linear_interp(a, b, x):
return a * (1 - x) + b * x

def cosine_interp(a, b, x):
f = (1 - math.cos(x * math.pi)) * 0.5
return a * (1 - f) + b * f

def cubic_interp(v0, v1, v2, v3, x):
p = (v3 - v2) - (v0 - v1)
Q = (v0 - v1) - p
R = v2 - v0
S = v1

return P * x ** 3 + Q * x ** 2 + R * x + S


class Arr:
def __init__(self, w, h):
self.arr = numpy.zeros((w, h), float)

def size(self, w, h):
# Sanity checks
if w > 400 or h > 400:
raise Exception("Array size too large.")

self.arr = [[0] * w for i in range(h)]

def noise(self, w, h):
# Sanity checks
if w > 400 or h > 400:
raise Exception("Array size too large.")

print "noise"

# Create 2D array
self.arr = numpy.random.random_sample((w, h))

def smooth(self, ite):
print "smooth"

for i in range(ite):
soften = numpy.array(self.arr)

soften[1:,:] += self.arr[:-1,:]
soften[0,:] += self.arr[-1,:]

soften[:-1,:] += self.arr[1:,:]
soften[-1,:] += self.arr[0,:]

soften[:,1:] += self.arr[:,:-1]
soften[:,0] += self.arr[:,-1]

soften[:,:-1] += self.arr[:,1:]
soften[:,-1] += self.arr[:,0]

self.arr = soften / 5

def normalize(self):
print "normalize"

self.arr = (self.arr - self.arr.min()) / (self.arr.max() - self.arr.min())

return self.arr


def add(self, arr2):
self.arr += arr2.arr

def div(self, val):
self.arr /= val

def cosine_resize(self, mult):
# Sanity checks
if len(self.arr) * mult > 400:
raise Exception("Array size too large (tried resizing).")

print "linear resize"
w, h = self.arr.shape
w2, h2 = w*mult, h*mult

arr_new = numpy.zeros((w2, h2), float)
p0 = numpy.copy(self.arr)

p1 = numpy.zeros((w, h), float)
p1[:-1, :] = self.arr[1:, :]
p1[-1, :] = self.arr[0, :]

p2 = numpy.zeros((w, h), float)
p2[:, :-1] = self.arr[:, 1:]
p2[:, -1] = self.arr[:, 0]

p3 = numpy.zeros((w, h), float)
p3[:-1, :-1] = self.arr[1:, 1:]
p3[-1, :] = self.arr[0, :]

p3[:, -1] = self.arr[:, 0]

for nx in range(mult):
v0 = linear_interp(p0, p1, float(nx)/mult)
v1 = linear_interp(p2, p3, float(nx)/mult)
for ny in range(mult):
arr_new[nx::mult, ny::mult] = linear_interp(v0, v1, float(ny)/mult)

self.arr = arr_new

gfx = GFX()

run = 1
clock = pygame.time.Clock()

# run through 10 times for benchmarking purposes
t0 = pygame.time.get_ticks()
for it in xrange(10):
pw, ph = 256, 256
depth = 5

farr = Arr(pw, ph)

# Generate perlin noise
for i in range(depth):
d = 2 ** i

arr = Arr(pw,ph)
arr.noise(pw/d, ph/d)
arr.smooth(3)
arr.cosine_resize(d)
arr.div(2.**(depth-i))

farr.add(arr)

farr.normalize()

pygame.surfarray.use_arraytype("numpy")
print farr.arr.shape

tarr = numpy.zeros((256,256,3))
tarr[:,:,0] = farr.arr
tarr[:,:,1] = farr.arr
tarr[:,:,2] = farr.arr

pygame.surfarray.blit_array(gfx.screen, (tarr *256).astype(int))

print "elapsed: ",pygame.time.get_ticks()-t0

while run:
events = pygame.event.get()

for event in events:
if event.type == QUIT:
run = 0

pygame.display.flip()
clock.tick(60)