Monday, June 17, 2013
Friday, May 10, 2013
Personal: Links to My G+ and Twitter Accounts
If you enjoy my blog posts on Python, Ruby, Dart, etc., and you're looking for a new way to follow me now that Google Reader is going away, here are my Twitter and G+ accounts:
Thursday, May 09, 2013
Drawing Sierpinski's Triangle in Minecraft Using Python
In his keynote at PyCon, Eben Upton, the Executive Director of the Rasberry Pi Foundation, mentioned that not only has Minecraft been ported to the Rasberry Pi, but you can even control it with Python. Since four of my kids are avid Minecraft fans, I figured this might be a good time to teach them to program using Python. So I started yesterday with the goal of programming something cool for Minecraft and then showing it off at the San Francisco Python Meetup in the evening.The first problem that I faced was that I didn't have a Rasberry Pi. You can't hack Minecraft by just installing the Minecraft client. Speaking of which, I didn't have the Minecraft client installed either ;) My kids always play it on their Nexus 7s. I found an open source Minecraft server called Bukkit that "provides the means to extend the popular Minecraft multiplayer server." Then I found a plugin called RaspberryJuice that implements a subset of the Minecraft Pi modding API for Bukkit servers. Next, I found this handy guide to the Minecraft Pi Protocol. Finally, I found a Python library called mcpipy that implements the Minecraft Pi Protocol in Python.
Between looking at the Minecraft Pi Protocol documentation and peeking at the mcpipy source code, it's pretty easy to figure out how to control Minecraft from Python. My next step was to figure out how to draw something cool. Naturally, the first thing to come to mind was fractals, but it's not so easy to draw most fractals with fixed sized blocks. However, Sierpinski's triangle is not so hard to draw using blocks, so that's what I did.Here's the psuedocode for drawing Sierpinski's triangle:
draw_the_three_vertices()
current_point =
random_point_in_triangle()
while True:
vertex = random_vertex()
current_point = midpoint_between(
current_point,
vertex)
draw(current_point)
Here's the actual source code:
#!/usr/bine/env python
"""Draw Sierpinski's triangle in Minecraft."""
import random
import mcpi.minecraft
import mcpi.block as block
import server
# It goes from -MAX_XZ to MAX_XZ.
MAX_XZ = 128
MAX_Y = 64
# These are the vertices of the triangle. It's a list of points. Each point
# is an (X, Y, X) tuple.
TRIANGLE_HEIGHT = MAX_Y - 1
TOP = (-MAX_XZ, TRIANGLE_HEIGHT, 0)
BOTTOM_LEFT = (MAX_XZ, TRIANGLE_HEIGHT, MAX_XZ)
BOTTOM_RIGHT = (MAX_XZ, TRIANGLE_HEIGHT, -MAX_XZ)
TRIANGLE_VERTICES = [TOP, BOTTOM_LEFT, BOTTOM_RIGHT]
BASE_BLOCK_ID = block.SANDSTONE.id
TRIANGLE_BLOCK_ID = block.SNOW.id
# This is the maximum number of iterations to let the algorithm run. The
# algorithm relies on randomness, so I'm just picking a sensible value.
MAX_ITERATIONS = MAX_XZ ** 2
PRINT_FREQ = 1000
def clear_board(minecraft):
minecraft.setBlocks(-MAX_XZ, 0, -MAX_XZ, MAX_XZ, MAX_Y, MAX_XZ, 0)
minecraft.setBlocks(-MAX_XZ, 0, -MAX_XZ, MAX_XZ, -MAX_Y, MAX_XZ, BASE_BLOCK_ID)
def draw_sierpinski_triangle(minecraft):
def random_in_range():
return random.randint(-MAX_XZ, MAX_XZ)
def int_average(a, b):
return int(round((a + b) / 2.0))
# Draw the triangle vertices.
for (x, y, z) in TRIANGLE_VERTICES:
minecraft.setBlock(x, y, z, TRIANGLE_BLOCK_ID)
# Pick a random point to start at.
current = (random_in_range(),
TRIANGLE_HEIGHT,
random_in_range())
for i in xrange(MAX_ITERATIONS):
if i % PRINT_FREQ == 0:
print("Drew %s blocks" % i)
# Pick a random vertex to "walk" toward.
destination = random.choice(TRIANGLE_VERTICES)
# Draw a block in the middle of the current location and the
# destination.
(c_x, c_y, c_z) = current
(d_x, d_y, d_z) = destination
current = (
int_average(c_x, d_x),
TRIANGLE_HEIGHT,
int_average(c_z, d_z)
)
(x, y, z) = current
minecraft.setBlock(x, y, z, TRIANGLE_BLOCK_ID)
if __name__ == "__main__":
minecraft = mcpi.minecraft.Minecraft.create(server.address)
# Uncomment this if you need it.
# clear_board(minecraft)
draw_sierpinski_triangle(minecraft)
The Gory Details
If you're interested, here are all the gory details.I got all of this running on OS X 10.7.
First, you'll need Java to run Bukkit. I installed Java SE Development Kit 7u21.
Next, you need to install Bukkit. Note, you must use a version of Bukkit that is compatible with your version of the Minecraft client. For me, that meant installing the latest, development version of Bukkit. See here for more information:
mkdir -p ~/Local/bukkit_server cd ~/Local/bukkit_server curl -L http://dl.bukkit.org/downloads/craftbukkit/get/02122_1.5.2-R0.2/craftbukkit-dev.jar -o craftbukkit.jar echo "cd ~/Local/bukkit_server/" > start.command echo "java -Xms1024M -Xmx1024M -jar craftbukkit.jar -o true" >> start.command chmod +x start.commandTo start the server, execute the start.command file. To stop the server, type "stop" into the console.
Next, I installed RasberryJuice. Download the jar file and move it to ~/Local/bukkit_server/plugins. Then type "reload" in the console where Bukkit is running.
Next, you'll need to install Minecraft itself. That costs roughly $30. I put it in ~/Local. When I first ran it, it insisted on installing "Java 6". To connect to your local server, choose Multiplayer, then Direct Connect, and then enter "localhost".
To install mcpipy, you can either use Git (if you have it installed), or you can download and uncompress the zip file. I put it in ~/Local/mcpipy. To test that it's working, try:
cd ~/Local/mcpipy python zhuowei_rainbow.pyThis will draw a rainbow in your running copy of Minecraft. After running the command, assuming there were no errors, it takes a little while for the rainbow to show up.
To try out my code, create a file called ~/Local/mcpipy/jjinux_sierpinski_triangle.py with the code from above. Then run:
cd ~/Local/mcpipy python jjinux_sierpinski_triangle.pyIt'll print out messages as it draws all the blocks. This will draw Sierpinski's triangle in the sky. It takes a minute or two to show up. You can tweak the script to draw the triangle using more blocks or with a different type of block. However, I've found that making certain changes causes Bukkit to crash, so keep an eye on the console where you started Bukkit to make sure nothing bad happened. If anything bad does happen, you might want to use control-c to stop the server. Then you can delete the world, world_nether, and world_the_end directories in ~/Local/bukkit_server and restart the server.
Monday, April 29, 2013
"Await" in Python
In Guido van Rossum's PyCon 2013 keynote, he presents "a new, interoperable approach to asynchronous I/O that is being developed for inclusion in Python 3.4." Part of his proposal is a way to use "yield from" in a manner similar to await in C#. Let's just say, I'm super excited about it!
Thursday, March 14, 2013
Irrduino: A Sprinkler System Built Using Arduino, Android, Google App Engine, Python, and Dart
Cross-posted from Dart News & Updates.
Developers frequently ask me if Dart is ready for the real world. Well, of course, that depends on the application. Check out this short video in which Joe Fernandez and I not only show that Dart can be used in the real world, we also show that it can be used to take the tedium out of watering your lawn!
The Dart code for Lawnville was originally written in January of 2012, a mere three months after Dart was launched as a "technology preview". That was six months before Dart's M1 release, so it's been updated a few times along the way. However, the code really hasn't fundamentally changed that much since the beginning.
Perhaps the most interesting piece of code is the use of a Queue (from the
You might wonder why I chose to use Dart so soon after its release, especially since I wasn't even on the Dart team at the time. I've always gotten a kick out of coding in new languages. At the time, I figured that as long as I could talk to the DOM and make XMLHttpRequests, I could do almost anything. These days, Dart is a lot more useful thanks to the growing selection of pub packages available, but even before these things existed, Dart had enough functionality to help water a lawn ;)
If you want to download the complete source code for Irrduino, you can get it from bit.ly/waterjoeslawn.
Developers frequently ask me if Dart is ready for the real world. Well, of course, that depends on the application. Check out this short video in which Joe Fernandez and I not only show that Dart can be used in the real world, we also show that it can be used to take the tedium out of watering your lawn!
The Dart code for Lawnville was originally written in January of 2012, a mere three months after Dart was launched as a "technology preview". That was six months before Dart's M1 release, so it's been updated a few times along the way. However, the code really hasn't fundamentally changed that much since the beginning.
Perhaps the most interesting piece of code is the use of a Queue (from the
dart:collection library) to schedule watering tasks. You can click on different parts of the lawn, and the droid will fly over and water each section for a short amount of time:
_actionQueue = new Queue();
...
_actionQueue.add({'action': 'water', 'zone': el.id});
...
void _executeActionQueue() {
if (_actionQueue.isEmpty) {
_waitingForTimer = false;
_idle();
} else {
var action = _actionQueue.removeFirst();
_doAction(action);
_waitingForTimer = true;
new Timer(new Duration(milliseconds: TIMER_INTERVAL),
_executeActionQueue);
}
}
A Timer and window.requestAnimationFrame are used to control animations:
void _repositionDroid(int x, int y, [Callback callback = null]) {
x -= (HALF * DROID_WIDTH).toInt();
y -= DROID_HEIGHT;
_droid.src = "/static/images/droid-jetpack-on-front.png";
_droid.style.left = "${x}px";
_droid.style.top = "${y}px";
new Timer(new Duration(milliseconds: REPOSITION_DURATION), () {
if (callback != null) {
callback();
} else {
_droid.src = "/static/images/droid-waiting-front.png";
}
});
}
void _startAnimationLoop() {
_animationStartTime = new DateTime.now().millisecondsSinceEpoch;
window.requestAnimationFrame(_animationLoop);
}
void _animationLoop(int timestamp) {
_animationProgress = timestamp - _animationStartTime;
for (Callback callback in _animationCallbacks.values) {
callback();
}
window.requestAnimationFrame(_animationLoop);
}
An HttpRequest is used to send commands to IrrduinoServer which in turn sends commands to IrrduinoController in order to control the sprinkler system:
void _waterRpc(int zone) {
var req = new HttpRequest();
int secs = (TIMER_INTERVAL * SECS_PER_MS).toInt();
req.open("POST", "/?water-zone=true&zone=${zone}&secs=${secs}", true);
req.onReadyStateChange.listen((Event e) {
if (req.readyState == 4) {
if (req.status == 200) {
window.console.log("Watering was successful");
} else {
window.console.log("Watering was unsuccessful");
}
}
});
req.send();
}
In total, the complete Dart code is about 110 lines long, not counting comments and closing braces.
You might wonder why I chose to use Dart so soon after its release, especially since I wasn't even on the Dart team at the time. I've always gotten a kick out of coding in new languages. At the time, I figured that as long as I could talk to the DOM and make XMLHttpRequests, I could do almost anything. These days, Dart is a lot more useful thanks to the growing selection of pub packages available, but even before these things existed, Dart had enough functionality to help water a lawn ;)
If you want to download the complete source code for Irrduino, you can get it from bit.ly/waterjoeslawn.
Labels:
android,
arduino,
dartlang,
Google App Engine,
python
Wednesday, February 27, 2013
Dart on a Chromebook: Success!
I finally have a viable approach to editing Dart directly on a Chromebook running ChromeOS! The usual approach to developing Dart code on a Chromebook is to use Chrome Remote Desktop to connect to another development machine. However, I wanted an approach that would let me develop in Dart while offline, for instance if I'm giving a talk on Dart and my internet connection goes down.Crouton is a set of scripts based around debootstrap that bundle up into an easy-to-use, Chromium OS-centric Ubuntu chroot generator. Using Crouton, I was able to create a chroot running a basic Ubuntu setup. Within the chroot, I was able to install a JDK and then Dart Editor. Everything works, as you can see in the picture. I can switch back and forth between XFCE and ChromeOS's desktop using a key combination, and everything still runs at native speed since it's just a simple chroot.
I got everything working on my wife's Samsung Series 5 Chromebook running an Intel Atom processor. I have a newer ARM-based Chromebook, but there is currently no ARM port of the Dart VM. I used the 32-bit version of the JDK and the 32-bit version of Dart Editor.
I'm pretty excited that this works because this is one of the few things that was preventing me from fully switching to a Chromebook :) Now, all I need to do is get my hands on a Chromebook Pixel!
Tuesday, February 19, 2013
Dart with Google Web Toolkit
In this episode of Dartisans, I'm going to show you a variety of ways to use Dart with Google Web Toolkit. I know that there are a lot of GWT developers out there who would like to give Dart a shot, but they aren't sure how because they already have a large, successful app that's written in GWT. I'm going to show you ways to integrate Dart into your existing GWT application without having to rewrite it from scratch.
To do this, I've built a sample application that uses both GWT and Dart. I'll show you how to setup a development environment so that you can work with both technologies. Then, I'll show you a variety of ways in which you can get GWT and Dart to interoperate, such as:
- Using GWT and Dart to manage different parts of the same page
- Using Dart to retrieve JSON from a Java servlet
- Using window.postMessage and JSNI to pass messages between GWT and Dart
- Using JavaScript, JSNI, and Dart's js package for synchronous interoperability between GWT and Dart
- Using CustomEvent objects and Elemental to pass messages between GWT and Dart
Aside from watching the video, you can also download the source code or view the video transcript.
As always, we invite you to join the discussion on the Dart mailing list, and ask us questions on Stack Overflow. Your feedback is important. Thanks for checking out Dart!
Subscribe to:
Posts (Atom)


