Pong in 30 Lines
Mar 19, 2008
NodeBox rocks. Copy this code into the nodebox window and hit apple-R to play pong.
size(400,400)
speed(40)
ball_diameter = 20
paddle_size = 75
v_x, v_y = (3, 4)
p_x, p_y = (10, 10)
bounce = 1.2
points = []
computer = WIDTH / 2
compuspeed = 10
def draw():
global v_x, v_y, p_x, p_y, points, bounce, computer, compuspeed
if not -ball_diameter < p_y < HEIGHT + ball_diameter:
text("Game Over", WIDTH/2, HEIGHT/2)
if p_y < 0: text("You win!", WIDTH/2, HEIGHT/2+20)
else: text("Computer wins", WIDTH/2, HEIGHT/2-20)
return
paddle_left = min(max(MOUSEX, 0), WIDTH-paddle_size)
ny = p_y + v_y
nx = p_x + v_x
if nx + (ball_diameter/2) > computer + paddle_size: computer += compuspeed
elif nx < computer: computer -= compuspeed
rect(computer, 0, paddle_size, 4, roundness=2)
if ny + ball_diameter > HEIGHT and v_y > 0 \
and paddle_left < nx + (ball_diameter / 2) < paddle_left + paddle_size:
v_y = -v_y * bounce
v_x = (nx - paddle_left - (paddle_size / 2)) * .25
ny = HEIGHT - ball_diameter
if ny < 0 and v_y < 0 \
and computer < nx + (ball_diameter / 2) < computer + paddle_size:
v_y = -v_y * bounce
v_x = (nx - computer - (paddle_size / 2)) * .25
ny = 0
elif nx + ball_diameter > WIDTH or nx < 0:
v_x = -v_x
mx = max(0, min(MOUSEX, WIDTH - paddle_size))
rect(mx, HEIGHT-4, paddle_size, 4, roundness=2)
p_x = nx
p_y = ny
oval(p_x, p_y, ball_diameter, ball_diameter)
I'd never written a game before, and they say you aren't allowed if you don't start with pong, so here it is. I was actually just playing around with motion in NodeBox for a seperate project, and did this for fun.
[# ▷] nodebox, python, programming
Functional Roman Numerals in Python
Jan 12, 2008
Just as a quck note, I thought I'd post the cleanest python I could come up with to solve the roman numerals problem I discussed earlier. It tries to use a functional style while actually avoiding recursion. To do so, I wrote an iterative python unfold:
def unfold(f, x):
res = []
while 1:
try:
w, x = f(x)
res.append(w)
except TypeError:
return res
And then the answer becomes:
numerals = [("M", 1000), ("CM", 900), ("D", 500), ("CD", 400),
("C", 100), ("XC", 90), ("L", 50), ("XL", 40),
("X", 10), ("IX", 9), ("V", 5), ("IV", 4),
("I", 1)]
def next(x):
for n in numerals:
if n[1] <= x: return (n[0], x-n[1])
def romanize(n):
return "".join(unfold(next, n))
Compare to the haskell I posted before:
romanize = concat . unfoldr next
where next 0 = Nothing
next x = Just $ second (x-) $ head $ filter ((<=x) . snd) numerals
numerals = [("M", 1000), ("CM", 900), ("D", 500), ("CD", 400),
("C", 100), ("XC", 90), ("L", 50), ("XL", 40),
("X", 10), ("IX", 9), ("V", 5), ("IV", 4),
("I", 1)]
The "where" idiom allows you to group helper functions and constants underneath the main function, and the unimportance of function order means you can highlight the high-level logic. The haskell code is much shorter and tighter than the python.
Having powerful iterative functions like unfoldr in the standard library is another clear win for Haskell; it took me more lines to define unfold than it did to define both next() and romanize(). (By the by, some googling failed to turn up a previous python implementation of unfold(); I think this code gets a lot uglier without it. I also don't see any obvious way to do it with itertools.)
On the other hand, I find the simplicity of the python next() appealing, with its constructive instead of declarative approach. It's a less generic solution that's intuitively simpler (for me, still an imperative thinker).
You could match the haskell more exactly:
from itertools import ifilter
def second(f, (a, b)): return (a, f(b))
def next(x):
return second(lambda a: x-a, ifilter(lambda (y, z): z <= x, numerals).next()
but the result is pretty ugly. The inability to compose functions compactly results in a lot of boilerplate, and in having to pick a lot of meaningless variable names that obscure what's going on. We could move the lambdas out of the call and give them names:
def next(x):
subx = lambda a: x-a
ltx = lambda (y, z): z <= x
return second(subx, ifilter(ltx, numerals).next())
And it's a little better, but I think we're now pretty far from idiomatic python.
Conclusion
The python translation of the haskell isn't bad, but I do think it loses something. The unfold() trick works really well, and translates easily into an imperative, pythonic implementation; I'll look for ways to use it in the future. And, finally, I'm pretty jealous of Haskell's function combination abilities.
Updates
In the comments at reddit, nostrademons posts a nicer unfold function:
def unfold(f, x):
while True:
w, x = f(x)
yield w
And Kay Schluehr prefers the iterative solution:
numerals = (("M", 1000), ("CM", 900), ("D", 500), ("CD", 400),
("C", 100),("XC", 90),("L", 50),("XL", 40), ("X", 10), ("IX", 9), ("V", 5),
("IV", 4), ("I", 1))
def romanize(n):
roman = []
for ltr, num in numerals:
(k,n) = divmod(n, num)
roman.append(ltr*k)
return "".join(roman)
David Pollak contributes a Scala unfold and romanize at his blog.
[# ▷] python, code, programming
Poe on Programming
Dec 28, 2007
One of the strongest influences on my programming has always been an essay I read in my sophomore year of high school, around about the same time I began to feel the magic of programming. Mr. Carino was a young man just out of college, a Slayer fan and ardent Twain admirer, and a man who would disappear mysteriously a year later. That year, though, he gave the most electric class I've ever taken, and one of the works we read in American Literature was Edgar Allan Poe's The Philosophy of Composition.
Code As Poetry
In The Philosophy of Composition, Poe attempts to describe exactly how he composed The Raven, simply because he's never seen such an attempt before. While we might be wise to doubt his motives (as did TS Eliot), it nevertheless may be interpreted to provide solid principles for the construction of a program.
Before we do so, I must first convince you that code should be read as poetry instead of prose. Since this will always be a matter of opinion, and I know that many people will disagree, my argument will be short and simple.
When you read prose, you read it as if it is being narrated to you; whether by a narrator, a character in the story, or many characters, the distinguishing characteristic of prose is its similarity to speech. We find that it is allowed a much greater freedom of verbosity, so long as it accomplishes its goal of conveying a plot to its reader.
Poetry, on the other hand, is an abstract block of words in which every one must carry meaning if the poem is to be any good. We value the poem for the beauty not only of the story or image given, but of the way in which it is constructed as well. It tends to be much denser and more compact than prose. When you read it, you must proceed carefully and consider the meaning of each word, and each group of words, and pay attention for double meanings and allusions if you are to grasp it fully.
To help us decide how we read code, let's go to a particularly nice bit of it, and meditate on it for a moment. Did you read it as if it were speech, or poetry? Did it have a narrative "flow" for you, or was it something of an abstract block of "words"?
Of course, code is really neither prose nor poetry; it is a distinct art form of which Poe could not have been aware. I like to think that it may be read much more closely to poetry than to prose, and we will proceed from here as if this were true.
Unity of Impression
If any literary work is too long to be read at one sitting, we must be content to dispense with the immensely important effect derivable from unity of impression- for, if two sittings be required, the affairs of the world interfere, and everything like totality is at once destroyed. But since, ceteris paribus, no poet can afford to dispense with anything that may advance his design, it but remains to be seen whether there is, in extent, any advantage to counterbalance the loss of unity which attends it. Here I say no, at once. What we term a long poem is, in fact, merely a succession of brief ones- that is to say, of brief poetical effects. It is needless to demonstrate that a poem is such only inasmuch as it intensely excites, by elevating the soul; and all intense excitements are, through a psychal necessity, brief. For this reason, at least, one-half of the Paradise Lost is essentially prose- a succession of poetical excitements interspersed, inevitably, with corresponding depressions- the whole being deprived, through the extremeness of its length, of the vastly important artistic element, totality, or unity of effect.
In the first sentence of this paragraph, Poe provides an alternate metric to Yegge's metric of "code size" - that of "unity of impression". Beautiful code is that which is not composed of "a succession of brief.. poetical effects", but of just the poem. It is code without filler, bureaucracy, or artifice, regardless of how long it is.
As a practical matter, not all programs may be written in this manner. In an operating system kernel, a great deal of "corresponding depressions" — documentation, error handling, and interrupt handling — must be interspersed in between the "poetical effects", making it "essentially prose".
This does not change the fact that the Linux kernel or a BSD kernel is a thing of beauty, just as Paradise Lost is great despite "the extremeness of its length". Instead, it should give us motivation for our programs, to write them with as few depressions as possible so as not to drag down their unity of impression.
A great example of code as poetry is OpenBSD's tail1, which I referenced in a previous post. After I sat down with it for an hour, it was extremely clear to me what it did. In the beginning, it set out the patterns of code which would continue throughout, enabling me to quickly find my way to the part that mattered, despite my relative unfamiliarity with C.
It is a great strength of the Unix philosophy that each bit of code may be kept as brief, self-contained, unified, and therefore beautiful. It is a pleasure to work with tools which have been pared down to their bare bits instead of expanded to encompass ever more functionality.
Design for a Purpose
My next thought concerned the choice of an impression, or effect, to be conveyed: and here I may as well observe that throughout the construction, I kept steadily in view the design of rendering the work universally appreciable. I should be carried too far out of my immediate topic were I to demonstrate a point upon which I have repeatedly insisted, and which, with the poetical, stands not in the slightest need of demonstration- the point, I mean, that Beauty is the sole legitimate province of the poem.
If beauty is the sole province of poetry, I propose that data transformation is the sole province of the computer program. (I am not the first to do, although I cannot recall where I read it first). Therefore, when designing a program, we should at all times keep in mind the transformation which we wish to achieve, and discard all those parts which do not assist in that goal.
While this seems at first straightforward, it is important to consider that programs are designed for humans and by humans. Unlike poetry, most code is not generated by its author for the appreciation of the masses. Instead, it is designed to fulfill a purpose, specifically to achieve a certain data transformation.
Just as very few great poems were authored by multiple people, very few great programs have been authored by multiple people. If we consider long programs to be composed of many poems separated by dull bits, their great parts are almost exclusively those parts over which their maintainers have slaved to bring to a state of terse beauty.
If you must have many people working on a program, it is of the utmost importance that they all know and share an understanding of what exactly it is that the program is intended to accomplish. Without this deep shared knowledge of intent, the program will lack a single impression, or effect, to be conveyed, and likely fail to impress.
All The Rest
The length, the province, and the tone, being thus determined, I betook myself to ordinary induction
Once you have determined the length, purpose, and tone of your program, the rest is, as they say, trivial. Poe dedicates the rest of his essay to applying the principles discussed in this essay, and showing how "The Raven" falls ever so simply out of them. If you write a program while at all times keeping in mind its unity of purpose and the impression you intend to convey, perhaps you will find some beauty in it.
I hope that you will read the essay in its entirety; I'm sure that I have failed to do it justice here. Although it is of questionable merit as a method of writing the next "The Raven", perhaps it will help you think about how to write your next program.
Notes
1 pybloxsom is another, and reddit readers provide many more.
[# ▷] poe, literature, programming, python, poetry
Iterating Over Database Results in C#
Dec 17, 2007
At my job, we use what is essentially a custom C# ORM. Soon after I arrived, we adopted this idiom to pull a DB connection from the pool and run a query:
class Something
{
public int ourIdiom(long identifier)
{
using (DBConnection db = new DBConnection())
{
using (IDataReader rec = db.execQuery(@"
SELECT some, rows
FROM Table1 t1, Table2 t2
WHERE t1.t2id = t2.id
AND t1.id = ?",
identifier))
{
while (rec.Read())
doSomething();
return 1;
}
}
}
}
Which is nice because it disposes of both the connection and the dataReader
properly on failure, but ugly because it uses a whole bunch of boilerplate.
Unfortunately, because doSomething() needs to execute inside both
using statements, and we weren't using C# 2.0 until a few months
ago, the only way to avoid the boilerplate would have been to pass in
delegates.
This would have been just as ugly as keeping the boilerplate in the code, so we stuck with the using2 idiom.
Since our switchover to 2.0 a few months ago, I've had an idea that I could make this idiom more concise and remove some boilerplate that I didn't get a chance to try until this week. Using 2.0's iterators, which seem awfully familiar from my python work, that can be reduced to:
class Something
{
public int ourIdiom(long identifier)
{
foreach (IDataReader rec in new SQL().Query(@"
SELECT some, rows
FROM Table1 t1, Table2 t2
WHERE t1.t2id = t2.id
AND t1.id = ?",
identifier))
{
doSomething();
}
return 1;
}
}
With some fairly simple code:
public class SQL :
System.Collections.Generic.IEnumerable<IDataReader>
{
string m_sql;
ArrayList m_sqlparams;
public SQL()
{
}
public SQL query(string sql, params object[] sqlparams)
{
m_sql = sql;
m_sqlparams = new ArrayList(sqlparams);
return this;
}
IEnumerator<IDataReader> IEnumerable<IDataReader>.GetEnumerator()
{
using (clsDBConnection db = new clsDBConnection(m_dbname))
{
using (IDataReader rec = db.execQuery(m_sql, m_sqlparams))
{
while (rec.Read())
yield return rec;
}
}
}
//this is required because IEnumerable<> inherits IEnumerable. bleh.
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator() }
}
}
This code should come in handy for more reasons than just its cleanliness. First off, if you ever need to change the idiom for accessing the DB, it's stored conveniently in one place.
Second, It makes a prepared SQL call into something like a thunk: a bit of code representing a future computation that can then be passed around to be performed later. An example:
void setUpQueries(nameId, addressId, custId)
{
List<SQL> stringsWeNeed = new List(new object[]{
new SQL().query("SELECT name FROM names WHERE id=?", nameId),
new SQL().query("SELECT addy FROM addresses WHERE id=?", addressId),
new SQL().query("SELECT zip FROM customers WHERE id=?", custId)});
List<string> strings = getOurStrings(stringsWeNeed);
mangleStrings(strings);
}
List<string> getOurStrings(List<SQL> queries)
{
List<string> strings = new List<string>();
foreach (SQL query in queries)
{
foreach (IDataReader rec in query)
strings.Add(rec.GetString(0));
}
return strings;
}
While the example is silly, this property can be exploited to seperate declaration from execution, which I often find to be a useful pattern.
Though I am far from the first person to discover this simplification, I did figure it out on my own and I thought it was neat enough to share.
A quick disclaimer: the code here is modified from the original to remove some details, and is completely untested, and probably doesn't compile. You may, however, use it or distribute it as you see fit; it's licensed under the wtfpl.
UPDATE: added the while(rec.Read()), which I'd forgotten
Reverse File Iterator and Premature Optimization
Oct 03, 2007
This afternoon, I had a need for a reverse file iterator in a script I was writing to process a quite large log file. After some unsuccessful googling followed by some quick hacking, I was left with a frustratingly close, but nonfunctional, iterator. Instead of fixing it while I was at work, I hacked up a solution calling "tail" and left it for a while.
When I came back to finish the job this evening, I figured that I ought to go look at the source of tail for some inspiration. Surely the unix hackers had figured this problem out long ago? In reverse.c, I found the inspiration I needed:
for (; pos >= start; pos--) {
/* A seek per char isn't a problem with a smart stdio */
if (fseeko(fp, pos, SEEK_SET) != 0) {
//snip
if ((ch = getc(fp)) == '\n')
I had been reading the file in chunks, splitting the chunk into lines, handling a cache of the lines, and compensating for unfinished lines, all because I had buried deep down in my lizard brain the idea that an fseek per character was "slow". In pure python, for chrissake!
Properly reminded of the fact that premature optimization can sneak up anywhere, I ended up with this code:
import os
class reversefile(object):
"""Iterate backwards through a file. f should be an open file handle"""
def __init__(self, f):
self._f = f
self.end = os.stat(f.name).st_size
def __iter__(self): return self
def next(self):
if self.end == 0:
raise StopIteration
pos = self.end-2
while pos >= 0:
self._f.seek(pos)
if self._f.read(1) == '\n':
end = self.end
self.end = pos
return self._f.read(end - pos - 1)
pos -= 1
end = self.end
self.end = 0
self._f.seek(0)
return self._f.read(end).strip("\n")
You can see the whole thing, with source and some very brief tests I hacked up, here.