Category Archives: Programming

Organizing a Small-Scale Programming Competition: Question Writing

As soon as I joined the committee, I got started working on the next competition and learned about the processes in place. We constantly worked to improve them. In this post, I will talk about old processes, why they existed, and how we attempted to improve them.

Writing Questions

Writing questions for the competition is the most important step in the competition design process. In our committee, question writing was done by a designated group of committee members. They would write a rough-draft of their question, a small sample, and potential background stories. After a few weeks, the committee gathered to review all questions and narrow them down to the 15 we would use for the competition. To do this, we gave each question a difficulty rating of easy, medium, or hard. We then eliminated questions until all that remained were the 15 we would use, where the majority of them were “medium” difficulty.

Writing Test Cases

Of course, we also needed to create a collection of test cases to test contestant’s programs against. The test cases consisted of both INPUT and OUTPUT. Creating these test cases by hand for each problem posed a problem: crafting inputs was easy, but doing the work to calculate the expected output by hand was challenging. Further, we wanted a fairly large number of inputs to catch any corner-cases that contestants may have missed.

Sample Cases, Input / Output, and Method Stub from the Fall 2014 competition

Another challenge was test case formatting. Test cases had to be fed to contestant’s programs, whose output then had to be verified. Some of our test cases were also pretty complex (e.g Given a 2D array which represents one map, a 2D array which represents locations of hazards, find a path to the square with coordinates (X,Y)). Contestants definitely shouldn’t have to write this parsing code and instead should only focus on solving the problem in a pre-defined function stub.

Thus, the following problems had to be solved:
1. Given hand-crafted input, auto-generate output that we would use for judging contestants.
2. Provide the contestants with programs that already contained input-parsing and output-formatting logic. Contestants would simply complete a function stub.

Behold: “Template Writers” and “Solution Writers”

We solved the problem by having committee members be “solution writers”, who would act just as the contestants. For each problem, a “template writer” would write a template program that parsed input/output. Solution writers would then use the template and implement the function stub. As long as there were 3-or-so solution writers for each problem, this went very well. After everyone was finished, input could be added into a single file and provided to the solution writer’s programs. If all their outputs agreed, this input/output combination would be considered a new “test case”.

Eventually, we settled on a standard input format (separate test cases were delineated with newlines, components of each test case were determined by the template writer) and a sort-of standard template pattern.

Below is a Java template and case input for a problem in Fall 2014:

import java.util.*;

public class Problem4 {

  //Parameter(s): char ch - the character to be searched for in the String
  //              String phrase - the String to be searched through
  //Return:       int - the number of character triples in the String
  public static int spyingOnTriplets(char ch, String phrase) {

    //YOUR CODE HERE

    return 0;
  }


  /////////////////////DO NOT MODIFY ANYTHING BELOW THIS LINE///////////////////
  public static void main(String[] args) {
    Scanner in = new Scanner(System.in);
    ArrayList<String> input = new ArrayList<String>();
    while (in.hasNext()) {
      input.add(in.nextLine());
    }
    for (int i = 0; i < input.size(); i++) {
      char searchLetter = input.get(i).charAt(0);
      String searchString = input.get(i).substring(2);

      System.out.println(spyingOnTriplets(searchLetter, searchString));
    }

  }

}
d ddidddd
f ffffffluffffffy
f fluffyyyyy
z heyhowyoudoin
o ooooo
o oooo
b blblbl
b bbb
c c-c-c
' '''
- -----
p chicken

 

At the time, we continued writing inputs and templates by hand. However, we put a lot of effort into PCFramework, which was a collection of shell scripts that would allow all testing of test-cases to be handled automatically.

As an example, basic workflow looked like:

cd BPCFa15/Solutions/dev # Move into the solution writer directory
cp ../Templates/Problem1.java Brandon/ # Move the template into my own workdir
vim Brandon/Problem1.java # Fill in the function stub with my solution
./test.sh 1 Brandon # Test my solution against "sample input" and "corner input", which are hand crafted
./compare.sh 1 Brandon Dylan Marisa # Compare outputs of solutions and verify they are the same
cp Brandon/problem1.out tests/problem1.out # Move Brandon's output into the official tests folder

This allowed us to have “Sample inputs” (sanity inputs whose outputs were provided), “Corner inputs” (Difficult corner cases whose outputs were hand-crafted), and “Generated inputs” (inputs that we created by hand but whose outputs were generated by solutions).

Other Benefits of Solution Writers

On the surface, solution writers provided the competition with usable outputs. In addition, the process of crafting solutions by hand provided us with insight into other metrics, such as how difficult the problems really were and how easily they could be understood. More than once, we revoked a question from the question pool after we discovered that no solution writers could agree upon a solution.

On one occasion, we discovered that one of our problems actually boiled down to a difficult scheduling problem and none of our solution writers could optimally solve it. Obviously, this question was pulled.

A “golden solution” for the above problem:

import java.util.*;

public class Problem4 {

  //Parameter(s): char ch - the character to be searched for in the String
  //              String phrase - the String to be searched through
  //Return:       int - the number of character triples in the String
  public static int spyingOnTriplets(char ch, String phrase)
  {
    int count = 0;
    char[] characters = phrase.toCharArray();
    for (int i = 0; i < characters.length - 2; i++)
    {
      if (characters[i] == ch &&
          characters[i+1] == ch &&
          characters[i+2] == ch)
      count++;
    }
    return count;
  }


  /////////////////////DO NOT MODIFY ANYTHING BELOW THIS LINE///////////////////
  public static void main(String[] args) {
    Scanner in = new Scanner(System.in);
    ArrayList<String> input = new ArrayList<String>();
    while (in.hasNext()) {
      input.add(in.nextLine());
    }
    for (int i = 0; i < input.size(); i++) {
      char searchLetter = input.get(i).charAt(0);
      String searchString = input.get(i).substring(2);

      System.out.println(spyingOnTriplets(searchLetter, searchString));
    }

  }

}

 

Supporting More than Java

The usefulness of these verification tools quickly became evident. Since verifying inputs/outputs was now trivial, we could start supporting languages other than Java in our competition (as long as someone wrote a template and we had enough solution writers). Due to contestant demand, the first additional language we supported was C++.

At this point, our competition moved to HackerRank to manage contestant solutions and inputs/outputs.

Organizing a Small-Scale Programming Competition: Background

My Story

Near the end of my first quarter at UCSD, I began seeing posts on Facebook which
advertised a “Beginner’s Programming Competition”. Students who have not yet
taken any upper-division Computer Science courses could solve small programming
questions. Whoever completed the most in the shortest time would be given a
prize. I’d been programming long before college, so of course I’d sign up.

Advertisement for Spring 2014 Competition

The flyer for the first competition that I helped run. I got a BitTorrent T-Shirt

I arrived and was given a dedicated workstation and a packet of questions. We
had three hours to solve as many problems as we could using Java. All
submissions were to be sent through PC2 and three winners would be announced at the end.

I learned three things that day:

  1. A competition environment makes programming very stressful and much more
    difficult.
  2. I was not the only one who had been programming “long-before college”
  3. I was hooked.

I did not win. Heck, I didn’t even place in the top 10. But I had a blast.

Next quarter, I teamed up with a long-time friend and we ended up placing in
the top 5. I was satisfied and immediately signed up to join the committee. I
would spend my entire college career working to improve the competition.

What Was So Great?

Obviously, I had a good enough time while competing to justify joining the
committee. Indeed, the competition did a lot of things right.

  1. The beginners-only spirit of the competition made it easily accessible for
    me. It also thoroughly proved the joys of programming without intimidating
    me into my own self-loathing.
  2. All of the questions had cute backstories and the competition had an
    overarching theme. For my second competition, all questions followed an
    unnamed chef as he encountered difficult problems in the kitchen. This
    really helped lighten the mood and made it enjoyable.
  3. Balloons. There were people whose sole job was to deliver balloons to
    contestants every time they solved 2 problems. Not only was this a morale
    booster while struggling, but it was also fun. Some even had little faces
    drawn on them.
  4. The competition was run by students, for students. Something about
    partaking in a competition designed by my fellow students made the problems
    seem even more solvable. (If my TA wrote the question, there must be an
    easy solution!
    ) Further, the competition was not too corporate. Sure, there
    was a small corporate sponsor, but they only provided some prizes to the
    winners. Definitely nothing too in-your-face.
The question packets for each year I was involved in the competition

The question packets for each year I was involved in the competition.

What Could Be Changed

When I first joined the committee, I didn’t think much about improving the
competition. I simply wanted to help build it. Of course, I spent a lot of
time building tools to help create the competition, but it wasn’t until later
that I realized there was still work to be done. Most of this work was realized
because of post-competition-feedback we got from our contestants.

The biggest complaint was that contestants could only program in Java. Intro
computer science classes taught in Java, but many contestants were coming in
with pre-existing knowledge of Python and C++.

Some other contestants complained that prizes were lame. It was true. It cost
money to run the competition, so we asked programming-related companies to
provide us with funds and in return they could provide their latest tech
(read: advertisements) as prizes to the winners. Unfortunately, this meant that
companies often sent branded glasses, t-shirts, and stickers. No one felt good
about taking first place in a 3 hour competition only to receive a sticker.

Finally, the logistics of running the competition were a mess. Sure, we had
PC2 to help facilitate checking correctness, but volunteers were running around
like crazy delivering balloons, answering contestant questions, and ensuring
that no one was cheating. This meant that volunteers ran to the “control room”
to get a balloon, looked at a whiteboard to see who needed a balloon (the
whiteboard was managed by someone repeatedly refreshing the scoreboard), and
ran the balloon to the contestant. Over and over again.

I absolutely loved the competition and loved being on its committee even more.
In the next posts, I’ll detail how we decided to manage the logistics of
creating and running each competition. Hopefully they are useful to some other
competition would-be-designers.

Setting a Windows Desktop Background in Rust

While working on wallers, I came across the need to set the desktop background for Windows machines. For Linux machines, the answer was simple: delegate to feh. For Windows, I needed to delegate to a Windows API call.

The Windows API call of interest is SystemParametersInfo, specifically with the action as SPI_SETDESKWALLPAPER (20 in decimal). For SPI_SETDESKWALLPAPER specifically, the second and fourth parameters are not used, so they can be set to 0. Thus, in order to change the desktop wallpaper, one would call

SystemParametersInfo(20, 0, "path/to/wallpaper.png", 0)

In particular, this function is found in user32.dll. Luckily, retep998 has created a Rust binding for it and it is available as a crate. With this knowledge, changing the desktop wallpaper becomes quite trivial. The only complication is that there are two forms of SystemParametersInfo : SystemParametersInfoA and SystemParametersInfoW. From what I’ve gathered, the former should be called on 32 bit systems while the latter is called on 64 bit systems. This works on my desktop machine; however, on my 64bit Surface Book, SystemParametersInfoW sets the wallpaper to black while SystemParametersInfoA works as intended.

The final bit of difficulty comes in that these functions accept a *mut c_void as a parameter rather than a string (making the function unsafe.. sad). Thus, conversion must also take place.

extern crate user32;

use std::ffi::CString;
use std::os::raw::c_void;

fn set_wallpaper(path: String, force_32bit: bool) -> Result<(), ()> {
 let wallpaper_func = if force_32bit || cfg!(target_pointer_width = "32") {
        user32::SystemParametersInfoA
    }
    else {
        user32::SystemParametersInfoW
    };

    // do work to get the pointer of our owned string
    let path_ptr = CString::new(path).unwrap();
    let path_ptr_c = path_ptr.into_raw();
    let result = unsafe {
        match path_ptr_c.is_null() {
            false => wallpaper_func(20, 0, path_ptr_c as *mut c_void, 0),
            true => 0
        }
    };

    // rust documentation says we must return the pointer this way
    unsafe {
        CString::from_raw(path_ptr_c)
    };

    match result {
        0 => Err( () )
        _ => Ok( () )
    }
}

As you notice, we also insert a way for the user to call SystemParamtersInfoA on a 64bit system, just in-case…. Of course, since this uses OS-specific libraries, it’s best to use macros to prevent this code from running on non-Windows machines.

#[cfg(windows)] extern crate user32;

#[cfg(windows)] use std::ffi::CString;
#[cfg(windows)] use std::os::raw::c_void;
#[cfg(not(windows))] use std::process::Command;

#[cfg(windows)]
fn set_wallpaper(path: String, force_32bit: bool) -> Result<(), ()> {
 let wallpaper_func = if force_32bit || cfg!(target_pointer_width = "32") {
        user32::SystemParametersInfoA
    }
    else {
        user32::SystemParametersInfoW
    };

    // do work to get the pointer of our owned string
    let path_ptr = CString::new(path).unwrap();
    let path_ptr_c = path_ptr.into_raw();
    let result = unsafe {
        match path_ptr_c.is_null() {
            false => wallpaper_func(20, 0, path_ptr_c as *mut c_void, 0),
            true => 0
        }
    };

    // rust documentation says we must return the pointer this way
    unsafe {
        CString::from_raw(path_ptr_c)
    };

    match result {
        0 => Err( () )
        _ => Ok( () )
    }
}

#[cfg(not(windows))]
fn set_wallpaper(path: String, _: bool) -> Result<(), ()> {
let result = Command::new("feh")
        .arg("--bg-fill")
        .arg(path)
        .status()?.success();

    match result {
        true => Ok( () ),
        false => Err( () )
    }
}

 

Moving Projects off of CodePlex

On March 31, Codeplex announced its plans to shut-down. Although this might be bad for competition in the hosted-repository space, I understand why Microsoft felt the need to shut-down its service.

Personally, I had 3 projects hosted on Codeplex: HTML-IDEx, UpdateVB, and NotifierForVB. I have decided to archive the latter two in a versioned zip file. Since HTML-IDEx has had some fairly recent membership requests, I moved it to GitHub.

Making the choice to archive UpdateVB and NotifierForVB was a tough one. After all, they were both artifacts of my first early years of programming and were used extensively in the software I created during that time. However, they both had not received any updates in nearly 7 years. Since I was quite the inexperienced programmer at that time, I also expect these libraries to be riddled with small issues and bugs.

UpdateVB is a unique case, since I actually started working on its successor in 2014. Thus, the decision to archive it was purely for historical purposes. If you are looking to use UpdateVB, please use update.net instead.

NotifierForVB, on the other hand, is a library that’s about 30 lines of code and strongly tied to the Krypton Toolkit (which is apparently now open source). Due to its simplicity and lack of usefulness, I’ve decided to archive it for historical purposes without a successor.

HTML-IDEx is my only project hosted on Codeplex that had real community collaboration. Further, it is the only open-source project owned by BrandonSoft. Due to a few membership requests in 2017, its popularity, and its tie-in with BrandonSoft, I’ve decided to package the source code and move it to GitHub. If git is not your thing, a versioned zip archive will also be hosted here.

It was a tough decision to officially deprecate and decommission two of my older projects, but it was in the best interests of those who may have wanted to use the libraries (Definitely don’t use them!) and for me and my dwindling free-time.

Thank you to everyone who supported, used, and helped create UpdateVB, NotifierForVB, and HTML-IDEx. You can view the projects in the Archive section of the code page.

Custom FileExtension Path-Based Importers in Python

Python 3.1 introduced importlib, which can be used to modify the behavior of Python’s import system. In fact, standard Python imports have also been ported to use this new library.

As stated in the documentation, one of the reasons for this libraries existence is to allow programmer’s to write their own Importer modules. As one can imagine, this functionality is not widely used, however, because most people don’t have a desire to alter the functionality of standard Python importing.

However, there are definitely use cases. One blog post describes using the system to block certain modules from being imported. Further, Python has actually used the module to write an Importer that allows one to import modules from zip files. There is also a great Usenix article that describes a lot of the functionality covered in this post.

In this post, I’d like to describe how one can use pre-existing machinery, namely importlib.machinery.FileFinder to quickly write a path-based Importer module to handle custom imports.

First, some background. Importing in Python is actually pretty straight-forward (and pretty elegant). During each import statement, a list of known-importers is consulted. Each importer returns whether it can handle the module name provided. The first importer that can handle the module name is then used to load the module.

Naturally, then, each Importer has two components, a finder and a loader:

find_loader(fullname) indicates whether a module can be loaded based on its name. If the module can be loaded, the loader is returned. If not, None is returned.

load_module(fullname) loads the module, returning the actual module and also doing some other work, such as placing it in sys.modules. All work is described here.

The Importers are loaded from two lists,  sys.meta_path and  sys.path_hooks .  The former imports modules simply based on their names, while the latter imports modules based on their names within a certain path.

Using this knowledge, our goal is to then allow something like this to happen:

In the directory of our project, there is a JSON file,  records.json , which contains customer records indexed by their full name. We want to seamlessly import this file and use it as if it were a dictionary. If the file doesn’t exist, naturally, we’d like to throw an error.

import records
print(records['Jane Doe'])

This seems pretty simple knowing what we know about how the Python import system works:

  1. Since we are operating on the FileSystem, we need to know information about paths. Therefore, we’d like to create an Importer module that can be appended to  sys.path_hooks .
  2. Our find_loader implementation should take the module name (records, in this case), append the “.json” extension to it, and then check to see if it exists on the filesystem. If it does, it should return the loader described in (3)
  3. Our load_module implementation should take the module name, append “.json” to it, read the contents from the filesystem, and load the JSON using Python’s  json module.

As you might notice, steps 1 and 2 are not necessarily JSON specific. In fact, they’re filesystem specific. Luckily, steps 1 and 2 have already been written and provided by Python in the form of importlib.machinery.FileFinder. We can then utilize this to write our JSON Importer.

FileFinder also has a nice helper function, FileFinder.path_hook, which allows us to specify a series of (loader, extensions) pairs. The function then returns a callable that is suitable to be inserted into  sys.path_hooks . We then only need to write the loader. The loader, by definition, is a callable that returns a Loader, which has a load_module(fullname) method. In our implementation, we are going to utilize a class’ constructor as this callable (as suggested in PEP302). We write our loader:

import json
import sys

class JsonLoader(object):
    def __init__(self, name, path):
        self.path = path

    def load_module(self, fullname):
        if fullname in sys.modules:
            return sys.modules[fullname]

        with open(self.path, 'r') as f:
            module = json.load(f.read())

        sys.modules[fullname] = module
        return module

Now we can use the already existing machinery to add this loader into our import system:

from importlib.machinery import FileFinder

json_hook = FileFinder.path_hook( (JsonImporter, ['.json']) )
sys.path_hooks.insert(0, json_hook)

# Need to invalidate the path hook's cache and force reload
sys.path_importer_cache.clear()

import records
print(records['Jane Doe'])

And voila! We have added our new JSON importing functionality. The most important part of the above codeblock is  sys.path_importer_cache.clear() . When your code begins running, all paths checked for imports in  sys.path have already had their hook’s cached. Therefore, in order to ensure that the newly added JSON hook is processed, we need to ensure that the cached list of Importers contains the JSON hook, so we simply invalidate the cache.

The great thing about this code is that FileFinder’s path_hook handles all of the Filesystem operations for you. It automatically traverses directories if directories are part of the import statement and automatically verifies extensions. All you have to do is worry about the loading logic!

Of course, no specific-solution is a good solution. It’s also possible to generalize what we’ve done.

from importlib.machinery import FileFinder
import json
import sys

class ExtensionImporter(object):
    def __init__(self, extension_list):
        self.extensions = extension_list

    def find_loader(self, name, path):
        self.path = path
        return self

    def load_module(self, fullname):
        if fullname in sys.modules:
            return sys.modules[fullname]
        
        return None

class JsonImporter(ExtensionImporter):
    def __init__(self):
        super(JsonImporter, self).__init__(['.json'])

    def load_module(self, fullname):
        premodule = super(JsonImporter, self).load_module(fullname)
        if premodule is None:
             with open(self.path, 'r') as f:
                module = json.load(f)
                sys.modules[fullname] = module
                return module
            raise ImportError('Couldn't open path')

extension_importers = [JsonImporter()]
hook_list = []
for importer in extension_importers:
    hook_list.append( (importer.find_loader, importer.extensions) )

sys.path_hooks.insert(0, FileFinder.path_hook(*hook_list))
sys.path_importer_cache.clear()

import records
print(records['Jane Doe'])

Now there’s no need to worry about any filesystem details. If we want a new importer based on a file extension, we simply extend the ExtensionImporter class, create a load_module method, and pop it into the extension_importers list.

And thus, a complete solution to creating custom file-extension based path-importers has been created. Two lessons I’ve learned while writing this post:

  1. Don’t forget to call  sys.path_importer_cache.clear()
  2. For some reason, appending the finder function to the end of  sys.path_hooks doesn’t seem to work. Inserting it at the beginning, however, does.