I had some fun learning about JUnit recently. I've always believed that it's important to develop incrementally. The neat thing (to me) about unit testing is that it encourages incremental development -- if you have lots of tests that don't pass, then the natural thing to do is to pick them off, one at a time, and fix them. In grad school, and now as a professor, I've had a fair number of occasions where someone said "I'm almost done writing it up, I should be ready to compile in a day or two". Perhaps encouraging students to develop their tests first will discourage them from falling into that pattern of behavior.
Anyhow, I built a tutorial about JUnit, for use in my CSE398 class. Feel free to share your thoughts on the tutorial, JUnit, and test-driven development in the comments!
Tuesday, March 17, 2015
Tuesday, March 3, 2015
Callbacks and Scribble Mode
Last week, we had a mobiLEHIGH tutorial session, and a student asked about how to make Fruit Ninja with LibLOL. It turns out that getting the right behavior isn't all that hard... you can use the "scribble" feature to detect a "slice" movement on the screen, and configure the obstacles that are scribbled to have the power to defeat enemies.
There was just one problem... configuring the obstacles requires changing the LibLOL code. I don't discourage people from changing LibLOL, but it's better to have an orthogonal way of getting the same behavior. In this case, it's easy: let the scribble mode code take a callback, and use that callback to modify an obstacle immediately after it is created.
This is one of those changes that I can't help but love... there's less code in LibLOL, and more power is exposed to the programmer. But it's not really any harder, and there's less "magic" going on behind the scenes now.
Here's an example of how to provide a callback to scribble mode:
I'm starting to think that I should redesign more of the LibLOL interfaces to use callbacks... what do you think?
There was just one problem... configuring the obstacles requires changing the LibLOL code. I don't discourage people from changing LibLOL, but it's better to have an orthogonal way of getting the same behavior. In this case, it's easy: let the scribble mode code take a callback, and use that callback to modify an obstacle immediately after it is created.
This is one of those changes that I can't help but love... there's less code in LibLOL, and more power is exposed to the programmer. But it's not really any harder, and there's less "magic" going on behind the scenes now.
Here's an example of how to provide a callback to scribble mode:
// turn on 'scribble mode'... this says "draw a purple ball that is 1.5x1.5 at the // location where the scribble happened, but only do it if we haven't drawn anything in // 10 milliseconds." It also says "when an obstacle is drawn, do some stuff to the // obstacle". If you don't want any of this functionality, you can replace the whole // "new LolCallback..." region of code with "null". Level.setScribbleMode("purpleball.png", 1.5f, 1.5f, 10, new LolCallback(){ @Override public void onEvent() { // each time we draw an obstacle, it will be visible to this code as the // callback's "attached Actor". We'll change its elasticity, make it disappear // after 10 seconds, and make it so that the obstacles aren't stationary mAttachedActor.setPhysics(0, 2, 0); mAttachedActor.setDisappearDelay(10, true); mAttachedActor.setCanFall(); } });
I'm starting to think that I should redesign more of the LibLOL interfaces to use callbacks... what do you think?
Saturday, February 21, 2015
Getting Started with OpenCV
OpenCV is a great library for doing all sorts of computer vision. It's also easy enough that you can use it for all sorts of menial tasks, like resizing images, cropping, adjusting colors, etc. And best of all, it's FAST. I have used ImageMagick in the past, and OpenCV feels a ton faster. If you want some data to support that claim, see this link.
Given that OpenCV is fast, general-purpose, and not too hard to use, I thought it would be a good topic for CSE398. Here's the tutorial I wrote.
I opted to do everything in Java, because that seemed easier than worrying about memory management. Of course, that also means it's harder to find good documentation. I ended up transliterating a lot of C++ code to show how various features work.
Since I'm not expert in Computer Vision, I wouldn't be surprised if I got some things wrong in the tutorial. Please don't hesitate to send a note if you find any errors!
Given that OpenCV is fast, general-purpose, and not too hard to use, I thought it would be a good topic for CSE398. Here's the tutorial I wrote.
I opted to do everything in Java, because that seemed easier than worrying about memory management. Of course, that also means it's harder to find good documentation. I ended up transliterating a lot of C++ code to show how various features work.
Since I'm not expert in Computer Vision, I wouldn't be surprised if I got some things wrong in the tutorial. Please don't hesitate to send a note if you find any errors!
Monday, February 16, 2015
An Introduction to Extending Code
Here's yet another CSE398 tutorial. This time it's about how to dynamically load code, or to otherwise create extensions that expand the behavior of a program. I realized that while students have heard of "DLL Hell", they don't know how to make DLLs (or their Unix equivalent, "shared objects").
DLLs are like lambdas (did you like yesterday's post?): if you don't know how to use them, you end up doing an outrageous amount of work to get an effect that would otherwise be simple. The tutorial starts by showing how to load and use a shared object in C++, which lets me introduce my basic Makefile template, function pointers, and C++ name mangling. Then it shows how to do dynamic class loading in Java. We move from there to using exec or spawn to do inter-process communication (IPC) between Node.js and Java or C++ programs.
I tried to make the tutorial a little bit more fun, by hiding the code for a Java Pig Latin converter. This was also an attempt to get people to look at the HTML code for my tutorials. I don't think students realize how easy it is to do clean web design by hand, once you know a little CSS and jQuery.
As with all of my CSE398 tutorials, I wrap up with next steps, this time involving the use of existing Node.js packages to load C++ and Java code directly into a running node server.
DLLs are like lambdas (did you like yesterday's post?): if you don't know how to use them, you end up doing an outrageous amount of work to get an effect that would otherwise be simple. The tutorial starts by showing how to load and use a shared object in C++, which lets me introduce my basic Makefile template, function pointers, and C++ name mangling. Then it shows how to do dynamic class loading in Java. We move from there to using exec or spawn to do inter-process communication (IPC) between Node.js and Java or C++ programs.
I tried to make the tutorial a little bit more fun, by hiding the code for a Java Pig Latin converter. This was also an attempt to get people to look at the HTML code for my tutorials. I don't think students realize how easy it is to do clean web design by hand, once you know a little CSS and jQuery.
As with all of my CSE398 tutorials, I wrap up with next steps, this time involving the use of existing Node.js packages to load C++ and Java code directly into a running node server.
Sunday, February 15, 2015
A Few Great C++11 Features
A few years back, I heard a talk by John Spicer of Edison Design Group on new features in C++11. After hearing John's talk, I realized that my students and I all fell into his category of programmers who knew the "FORTRAN subset of C++". Sure, I've written lots of code over the years, and a C++ compiler will understand that code. But was it really C++? Was it idiomatic? And even if it was, would it still be considered idiomatic in the face of C++11?
C++11 adds tons of cool features. The concurrency support is great. The STL is even better than before. But the best part, in my opinion, is lambdas. With lambdas, data structure design gets a lot easier. One "map" function can replace all of those one-off functions that otherwise go into a data structure (min, max, average, selectIf, countIf, etc.).
Here's a program I wrote to demonstrate some of the features of C++11.
Don't forget that you need to use the -std=c++11 flag when you compile this with g++.
C++11 adds tons of cool features. The concurrency support is great. The STL is even better than before. But the best part, in my opinion, is lambdas. With lambdas, data structure design gets a lot easier. One "map" function can replace all of those one-off functions that otherwise go into a data structure (min, max, average, selectIf, countIf, etc.).
Here's a program I wrote to demonstrate some of the features of C++11.
/// This is a demonstration of a few nice C++11 features: auto, the ':' /// iterator, initializer lists, std::function, and lambda expressions. In /// many cases, it's possible to achieve the same effect as I present using /// even less code, but by being explicit I hope I have made the code and /// comments easy to follow #include <functional> #include <iostream> #include <map> #include <string> #include <vector> using namespace std; // I'm being lazy here... should explicitly use cout, // endl, function, map, pair, string, and vector /// wrapped_map_t extends map<string, string>. We start with a map of /// key/value pairs, where both the key and value are strings, and we add a /// new method to it. The new method, apply_to_all, lets us apply a lambda /// to (a copy of) every key/value pair that is in the map. /// /// my claim is that lambdas fundamentally change the art of data structure /// design. To support my claim, I will show how this one simple function /// obviates many public functions that one might want int a data structure /// (count, print, extract_keys, find_matching_keys, etc). struct wrapped_map_t : public map<string, string> { /// the apply_to_all function simply iterates through the key/value pairs /// of the map, calling lambda(key, value) for each pair. Strictly /// speaking, std::map is a red/black tree, and this will do a pre-order /// traversal void apply_to_all(function<void(const string, const string)>& lambda) { // note the use of C++11 'auto' keyword to avoid having to specify // the type of the iterator for (auto i = begin(), e = end(); i != e; ++i) lambda(i->first, i->second); } }; int main() { // declare an instance of the extended map wrapped_map_t kvpairs; // populate the map with some keys and values. We're going to use some // great C++ magic here: initializer lists. We don't even have to know // the type of the list, but the compiler will deduce that it's something // like pair<string,string>[] kvpairs.insert({{"donald", "duck"}, {"mickey", "mouse"}, {"minnie", "mouse"}, {"bat", "man"}, {"super", "man"}, {"milo", "otis"}, {"mighty", "mouse"}, {"rocky", "squirrel"}, {"bullwinkle", "moose"}}); // 'func' is a reference to a function that takes two strings as its // parameters, and returns nothing. This is a lot nicer than the old C // syntax in use before C++11 (i.e., void (*func)(string, string)). function<void(string, string)> func; // let's assign a new lambda to func. the lambda will simply print its // parameters func = [](string k, string v) { cout << "{" << k << ", " << v << "} "; }; // now let's apply func to every element in the set. No need for a // "print_in_sorted_key_order" function in our class. It would be // trivial to add "print keys" and "print values" features without // changing the data structure... we'd just need to pass different // lambdas cout << "KVPairs = "; kvpairs.apply_to_all(func); cout << endl; // The last example was pretty boring. A function pointer could have // done that easily. Now let's pass in a function that has a captured // reference to a variable that is local to this function. In that way, // each time the lambda is called, it can access the function 'my_count' // that we declare *right here*. The net result is that we can count the // elements in the map, without requiring map to provide a "count()" // function. Note that the parameters to the lambda aren't used, and // that's OK. int my_count = 0; func = [&my_count](string k, string v) { my_count++; }; kvpairs.apply_to_all(func); cout << "Elements in map = " << my_count << endl; // OK, so we could have achieved that effect with an apply_to_all that // took three parameters: string, string, int&. But would we really want // to do that for every possible pass-by-reference type? For example, // here we pass a vector of strings so that we can copy out all keys from // the map vector<string> keys; func = [&keys](string k, string v) {keys.push_back(k);}; kvpairs.apply_to_all(func); // print the keys, to show that it worked cout << "Keys in map = {"; for (auto i : keys) cout << i << ","; cout << "}" << endl; // note, too, that we can use the lambda to capture multiple local // variables, and that some can be pass by value while others are pass by // reference. Here 'pre' is pass by value, 'keys' is pass by reference, // and our function copies into 'keys' all keys in the map whose values // begin with 'mo' string pre = "mo"; keys.clear(); func = [&keys, pre](string k, string v) { if (v.find(pre) == 0) keys.push_back(k);}; kvpairs.apply_to_all(func); cout << "Keys whose values start with 'mo' = {"; for (auto i : keys) cout << i << ","; cout << "}" << endl; // this example is much like the prior one. Here we extract all // key/value pairs where the key begins with 'mi' pre = "mi"; vector<pair<string, string>> pairs; func = [&pairs, pre] (string k, string v) { if (k.find(pre) == 0) pairs.push_back(make_pair(k, v)); }; kvpairs.apply_to_all(func); cout << "Elements whose key begins with 'mi' = {"; for (auto i : pairs) cout << "{"<<i.first<<", "<<i.second<<"} "; cout << "}" << endl; // the point of this example is to illustrate that when the lambda is // called with the key and value, the function we are executing *cannot* // modify the internals of the map. Put another way, the lambda does not // become a member function of the class. So, for example, if we wanted // to add a suffix to every key, then the only way we could do it would // be by explicitly updating the k/v pair in the map. string suf = " <3"; // note: we need to capture *kvpairs itself* by reference func = [&kvpairs, suf] (string k, string v) { kvpairs[k] = v+suf; }; kvpairs.apply_to_all(func); // use a lambda to print it out func = [](string k, string v) { cout << "{" << k << ", " << v << "} "; }; cout << "Modified kvpairs = "; kvpairs.apply_to_all(func); cout << endl; }
Don't forget that you need to use the -std=c++11 flag when you compile this with g++.
Saturday, February 14, 2015
Fun with Google Forms
Here's a link to another of my tutorials for CSE398. I figured this out in the course of making a registration page for an elementary school's after-school enrichment program. We wanted the convenience of a Google Form, with all results going to a shared spreadsheet, but we also wanted to be able to keep people from registering for activities that were either (a) not available based on their child's grade level, or (b) already at capacity.
The trick is to make a separate worksheet in the Google Spreadsheet that is attached to the form, set it up to summarize the data in the main sheet of the spreadsheet, publish the second worksheet, and only the second worksheet, and then consume it as JSON. Then it's just a matter of using JavaScript on the client side to fetch the JSON, parse it, and use the resulting data to drive the UI.
Somewhere along the way, I realized that the Google Form is really two components with a straightforward API connecting them. We can't change the API, but we can have a different front-end that interacts with the same back-end, as long as we respect the API. Once I realized that, it seemed worthwhile to make a tutorial about it.
The link to the tutorial is here. Hopefully it is easy to follow. As with my other CSE398 tutorials, there are "next steps" that I leave up to the student.
Disclaimer: there are ways to hack the technique I present, so don't use it for anything mission-critical. You'll still get the safety that Google Forms provides, but people can get around the JavaScript-based validation.
The trick is to make a separate worksheet in the Google Spreadsheet that is attached to the form, set it up to summarize the data in the main sheet of the spreadsheet, publish the second worksheet, and only the second worksheet, and then consume it as JSON. Then it's just a matter of using JavaScript on the client side to fetch the JSON, parse it, and use the resulting data to drive the UI.
Somewhere along the way, I realized that the Google Form is really two components with a straightforward API connecting them. We can't change the API, but we can have a different front-end that interacts with the same back-end, as long as we respect the API. Once I realized that, it seemed worthwhile to make a tutorial about it.
The link to the tutorial is here. Hopefully it is easy to follow. As with my other CSE398 tutorials, there are "next steps" that I leave up to the student.
Disclaimer: there are ways to hack the technique I present, so don't use it for anything mission-critical. You'll still get the safety that Google Forms provides, but people can get around the JavaScript-based validation.
Friday, February 13, 2015
My Favorite Graphics Tutorials
This isn't a particularly long post, but if anyone is looking for tutorials to help them make graphics for their mobiLEHIGH games, I think Chris Hildenbrand's tutorials on making vector art with Inkscape are great. Here are some links:
You can also check out Chris's blog.
Remember: when making art for games, png is the preferred format. It has transparency support, and it uses lossless compression, so your nice crisp lines won't get blurred like in jpegs.
Subscribe to:
Posts (Atom)