The 2009 Summer Scripting Games will open today. I am going to participate and try to golf the entries as well.
Announcements of the events are a bit hard to find, though. I only started today since I didn't know they were already at event 5. But officially they begin today.
My solutions to the individual events can be found in my SVN repository.
Update (2009–08–06): I won a signed copy of Windows Powershell: Step by Step.
NOTE: I do not encourage anyone to use these suggestions for real code that needs to be maintained. I won't take any responsibilities for exploded brains and the like. Although I have to admit, the amount of obfuscation you can do with Powershell with these tips is minimal and in most cases still understandable. Certainly not harder than trying to recognize design patterns in a gazillion lines of Java code.
I am currently playing some sort of code golf with a friend. We're both trying to solve the Project Euler problems (the easier ones, for now, as I am not yet that far) in as little code as possible. He's using Ruby, while I try my best in Windows Powershell.
So probably by not using (or even knowing) Perl or Ruby I am as far as I could get from the whole code golf thing but nevertheless, it's fun and for some solutions he beat me just by mere two or four bytes. But still, he consistently beats me. Now, if only Powershell could lose all those $ for variables or operators as unwieldy and lengthy as -eq or -lt … (although Ruby has similar problems with such horrendously long names like times or inject)
However, I've gained a few insights on how you can still squeeze some bytes out of Powershell scripts by knowing how the shell behaves in certain situations.
The first thing you should do when aiming for as little code as possible is remove all whitespace from the code. This can be done even around operators such as -lt, -eq, -contains, etc. A snippet like $_%7-eq0 is perfectly valid.
Take advantage of predefined aliases, such as % for ForEach-Object and ? for Where-Object. Many commands also have very short aliases, should you need them; the command
will list all aliases with a name shorter than three characters.
Booleans are cumbersome. Period. Using $true and $false just gobbles up too many characters. You can take advantage of the following implicit conversions to boolean:
| True | False |
|---|---|
$TRUE |
$FALSE |
| Any string of length > 0, except the word “false” | Empty string or the string “false” |
| Any number ≠ 0 | Any number = 0 |
| Array of length > 1 | Array of length 0 |
| Array of length 1 whose element is true | Array of length 1 whose element is false |
| A reference to any object | Null |
So using $b=1 instead of $b=$true is much shorter. In many cases, however, you won't need explicit boolean variables. I'll illustrate this with the following example. Suppose you just want to check whether an array contains a multiple of 7 and take that result to do something else. Then you need a boolean value, somehow. A naïve implementation known from Java or so might look like the following:
This reflects how I have done things at first. I've already omitted all whitespace, but still, this is 32 characters long for returning a boolean. We can rewrite the check for the modulus as !($_%7) since everything zero gets casted to false. This saves one precious character:
Next we can get rid of the helper variable $b altogether, since we can just use the result of the pipeline as a boolean value:
Where-Object or ? and use the resulting output directly:
which reduces the length to 16 characters. Half of what we needed at the beginning.
Another thing that tends to come up sometimes is a logical operation of two values, like for example !($a)-or!($b). With De Morgan's laws you can easily rewrite that to !($a-and$b), saving two characters (or even four, if you had -and to begin with).
Maybe you won't need them often, but sometimes they come in handy. Why write out a number like 10000 or even 10000000 when you can shorten it to 1e4 or 1e7, respectively?
Semicolons separate commands in one line. However, when you are just doing imperative programming crammed into one line it might look like this:
The $s at the end simply drops the variable off the pipeline into the shell so it gets printed. However, you can omit the semicolon directly after a script block:
is perfectly valid and a whole character shorter.
for loopsThe for loop in Powershell looks very much like its cousin from C-like languages:
Many times you're probably better of rewriting such a snippet (29 characters) to a pipeline (14 characters):
But sometimes you need a for loop since maybe the terminating condition isn't that simple. I'll take the above example nonetheless. What you can do first here is getting rid of the increment part and pack it into the terminating condition (27 characters):
we need to use the prefix increment since we are comparing $i after the increment (which happens usually at the end of the loop). Unfortunately this messes up the loop since now the start of the loop isn't right. In fact, now we start at $i = 2 because of the additional increment at the start of the loop.
This can be easily fixed, however, by changing the initialization:
What we notice now, however, is that we actually don't need to use the initialization anymore. Variables get initialized to when they are first used (a fact that we already use with the summation variable $s). So the complete initalization can be removed (23 characters):
And then there is a last small thing with for loops and that is that any trailing semicolons in the loop header seem to be optional. So if we don't need the increment part of the header, we can throw away the semicolon as well:
Down to 22 characters now. Using a pipeline is more code-size-efficient in many cases (see above), but still, the good old for loop can be optimized a bit as well.
Powershell has a very powerful pipeline, based on objects instead of strings which is a great help in many cases. We have already seen that the for loop can be shortened tremendously in some cases by simply using the range operator and piping that array.
Some things lend themselves quite well for pipeline processing. Basically every time you need to do something with the members of an array or a range. For example the following while loop terminates only if $n contains nothing but ones:
Accomplished by a rather small but nice pipeline in an otherwise imperative environment. Some things can be quite cumbersome and long when done imperatively and reduce to very small amount of code when done in a pipeline.
ETA: I have to admit, that by now I have discovered an even shorter way of checking this:
This is certainly shorter than
and can be helpful in some circumstances. Careful though, in using the result in a boolean context, since the boolean conversion rules are a bit confusing at times.
Select-ObjectSelect-Object or its predefined alias select is a rather long way of getting the first or last element of a pipeline. Compare
with
for getting the first element of a pipeline. Similarly for getting the last element.
Sometimes they are necessary, for example if you want to treat a string or substring as a number or convert a number to a string. The straightforward approach would be
Not very short. In fact, I try to avoid typecasts whenever possible, at least when trying to write concise code no-one else needs to read. You can, however, take advantage of the fact that Powershell converts operands. So you can just add the neutral element to something you want to convert:
And we just got down the cost of a string typecast to two bytes, instead of eight, and for integers we're also at two bytes instead of five, while a double typecast can be shortened to three bytes instead of eight.
I have presented some techniques for getting Powershell scripts smaller by taking advantage of some mathematical properties, quirks in the Powershell syntax as well as different methods of accomplishing the same goal, sometimes with large differences in code size. Mostly accumulated over the past few days but I'm still learning.
If I find anything new then this list will get updated.
One-dimensional elementary cellular automata are very simple. You just got a single row of cells which have one of two states: On or Off (0 or 1, living or dead, whatever you want to call it), so they can be nicely represented by a simple two-color bitmap.
States in cellular automata change according to the neighbourhood of a cell in the previous (global) state. Let's say you're a living cell (On, 1) and your neighbours in both directions are dead (Off, 0). Suppose you also have a table that states that your state in exactly this case changes to dead (might happen, maybe you just were too lonely to exist, don't blame me). But in another configuration your left neighbour might still be living and in that case you get to live on. Or in yet another configuration you are a dead cell and regardless what your neighbours are you change state to living.
Such a table essentially needs only a few things: State of a cell, state of all neighbour cells (two in this case) and the state of the cell in the following generation. We can visualize this as follows:
In the top row we have a cell with two neighbours, one left, one right, so three cells each. The bottom row gives the following state for each configuration. As you may have noticed, there are only eight possible configurations. And we can impose an order on them as I have done here. And the relevant part, once that order is established is simply a string of eight zeros and ones—so essentially eight bits. We can simply write this rule as a number. What wonderful way of shortening things. This numbering was conceived by Stephen Wolfram, a British mathematician and thus it's called Wolfram code or a Wolfram rule.
The rule pictured above is rule 30.
So we now know that such a cellular automaton might be described by a single number and that it can change states. What good is that?
Well, we might display a certain state of the automaton as a series of either black or white boxes:
and then we might display each of these states below the previous one:
et voila, we got a nice picture. Slightly chaotic, but that's usual for rule 30 and we got some nice recurring triangle formations in there.
So the point of all that was to generate a weird-looking image. Now for the fun part of this. Programming such a beast.
It isn't exactly complicated to do this, so lets start at the top:
We obviously need some control over how much is calculated and rendered. I put a single cell with state 1 in the center of the first row (initial state) so it's advisable to choose an uneven width because many patterns fan out to both sides (as seen above) and then they reach the left and right edge simultaneuosly. Height might be chose for a similar reason, since as the pattern fans out and reaches the sides it gets meaningless pretty quickly.
If the rule is given as the first parameter we only ask for it if it lies outside the permitted range (0–255), else we ask anyway until a correct rule is given.
Following that I wrote a simple subroutine which dissects the numerical rule into its eight parts:
We then initialize the area in which we store the states of each cell for each generation:
Basically we just initialize everything with zero and add a single one in the center of the first generation.
We have a problem with this approach, however, since when states are computed they need a neighbourhood. But how does the neighbourhood look for the first and last cells in each row? At first I simply put another cell to the left and right of the row, containing a zero. This works fine for most rules and we leave it as that for now. How one would implement this I leave as an exercise for the reader.
We might need a subroutine to display the whole area:
As you can see, that are actually two subroutines. They come in handy later.
What is still missing, however, is the calculation of successor states. So let's do that now.
Nothing fancy here, we just delegate the computation of a single cell to another subroutine. As you may note we display the calculated row immediately after we calculated it, this makes the watching experience while the batch file runs a bit less boring as we see a new line every few seconds (yes it is that slow).
Here we calculate the new state for a given cell, by using another helper subroutine which looks up the specific case from the table. We make use of the fact that the configuration of a cell and its neighbours are essentially three-bit numbers and the table is laid out in such a way here that we can access it simply by converting the configuration into a number between 0 and 7. The code for that looks a little ugly, since lots of escaping is needed (I escaped the parentheses just out of fear they might break something, as they often do when nesting structures).
But that was it, essentially. Running the batch without arguments produces the following prompt:
entering, say, 54 in there, yields the following picture:
The actual source code is a bit longer, since I offer an option how the sides of the area are handled (all zero, all one, wraparound and copy, the last of which is now the default which seems the most sensible to me—rules like 169 look very different when calculated with the edges being zero).
I am now working on SVG export from within the same batch file and I hope I found all major bugs by now. But the first working version was just 54 lines long. I think, had I been using Java instead (which was the other choice here), I would have needed significantly more.
UPDATE (2008–12–26 16:21): SVG export is now done and works as it should. At the moment I am mis-using the terminal server in the uni to compute all 256 rules simultaneously:
The taskbar resides usually at the bottom of the screen (at least for 98.4 percent of users). But as widescreen displays become more prevalent (and since I usually have many windows open) it's tempting to put the taskbar either to the left or to the right of the screen. That has the benefit that you usually have longer window captions visible on each taskbar button, especially when there are lots of windows. And at least for me a wide monitor doesn't add much value over one with an aspect ratio of 4∶3. Things like browsing the web and writing code are inherently vertical activities and don't need as much space horizontal (ok, for IDEs like Eclipse or Visual Studio it's nice to have more space but I'd take more overall resolution over more horizontal resolution any time).
Now the taskbar displays tooltips for window captions that are too long to fit:
It does so for a vertical taskbar, too:
Now here lies the problem. While the tooltip on a horizontal taskbar doesn't get in the way very much since it would only overlay a status bar or similar the tooltip for a vertical taskbar intersects with the window content. This usually happens not in a location reserved for auxiliary purposes but rather in the main view of an application:
This is particularly nagging if you restore a minimized window that was maximized before so it begins immediately right of the taskbar. As seen above the tooltip overlays parts of the content of the window just restored. The tooltip appears about the instant the window comes up after a click so it sometimes appears right into content I'd like to see.
Since websites are usually scanned in an F-shaped pattern many websites have a navigation on the left. And I can see that on some regular software, too. The folder list in my e-mail client is on the left and gets neatly overlayed by the tooltip, for example. Since I restore it usually to look for folders with new mail this is particularly nagging, since I need a moment to get the tooltip out of the way. Doesn't sound much and is probably not nearly significant, but still, it bugs me.
Maybe it gets even worse with Aero enabled since then not the tooltip shows up first but rather the thumbnail view of the window which is even larger.
Probably the taskbar would be better off at the right of the screen, since there is seldom information one wants to scan immediately after restoring a window (at least I think so and can't think of counter-examples right now).
UPDATE (2008–11–08 13:56): Activating Aero seems to be a better option than I thought. The window thumbnail doesn't appear when restoring a window and the thumbnail only appears after the usual time, although after the click and not after hovering the mouse over the button as it does when the Windows Classic theme is active.
Yesterday, shortly after finally setting up my other machine again, I decided to give Winamp another try. I used it as my main audio player back when I still used Windows 2000 but since I switched to Vista I converted to Windows Media Player, because I liked the look and feel of having my music collection with cover images, etc. all in one place. It proved to be somewhat slow on my old Pentium 4 2.53 GHz, though.
Enter Winamp. On Windows Vista. First start, it displays a nice dialog with skin selection (I didn't install any skins, so why that part in the dialog), the possibility to select file associations and whether or not you want to send anonymous usage statistics.
Fun thing here is: After wading through that dialog Winamp requests administrative privileges. Twice! And once every time you start Winamp again. I just wonder why. Neither file associations or anything else I found in the options Winamp would do needs administrative privileges. Nothing. Granting the request once (as was needed for Eclipse 3.3 to work properly) didn't change anything, Winamp still pesters me every time I start it.
And since I only have one keyboard, one mouse and one monitor here I either have to switch input devices or use Remote Desktop Connection. I went for the latter, for the most part and I figured since some command line work and music playing doesn't need many colors I could well use 8 bit color depth.
Well, turns out that Winamp likes to crash with only 256 colors. I don't know whether the music if should play is that colorful, but it reproduceably died right at startup. Only when I changed to a higher color depth the problem went away. Weird.
And as a side note: Winamp's media library is (at least to me) much more confusing than the Windows Media Player one and not exactly faster, so maybe I drop Winamp again.
UPDATE (2008–09–04 18:24): The UAC thing is solved now. There is a well-hidden option “Restore file associations at Winamp start-up” that was responsible for that. Unticking the box solves the issue. However, I have to stress that maintaining file associations is something you can do without adminstrative privileges.
Aah, recursion, the favorite pet of every programmer. Surely it must be possible to recurse even in Windows batch files (I'm still trying to prove Turing-completeness, by the way :-)).
The first tentative test would be an infinite recursion:
And know what? It works. Well, kinda:
But that's ok, we didn't expect this to do anything useful except of causing a stack overflow. But as we can see, cmd has a stack of some sort and seemingly manages it well enough to allow for recursion.
Time for another test, this time something remotely practical: Factorials. Never mind that those are more easily done with iteration, we want to make sure that recursion works properly:
We need a temporary variable at the end, unfortunately, since cmd does not allow computations inline. But aside from that it looks pretty much how it should. The case for breaking the recursion is also provided in the form of an IF block (sorry, no functional programming niceties, like different function definitions).
But does it work? Oh, sure it does:
And my calculator tells me that those are actually correct. 12! is unfortunately the highest factorial we can compute with it, since we are limited to 32-bit signed integers. A minor bug is still present when using negative numbers, though (infinite recursion, again). This is corrected in the attached version (as well as giving a helpful hint when running the batch without arguments).
Just as a side note, a fun way to implement factorial calculation by leveraging cmd's own “calculator”:
We simply construct the complete term and evaluate that by using SET /A. Nothing fancy, but probably faster than the recursion.
Something weird occurred to me today. In German you can build compound words by joining them directly together (sometimes for clarity also with a hyphen): “Webseite” (web page) and “Web-Seite” are both examples of that. You can also refer to parts of compound words and reuse them in the same sentence with another compound word, this is always done with a hyphen: “Webseite und -auftritt” (web page and presence, short for web page and web presence).
That out of the way, my problem: The hyphen in the latter case belongs to the word it sticks to. So the following line breaking in Word 2007 kinda puzzles me:
I have no idea why the hyphen moves to the previous line, it should be on the same line as “analyse”, right left to it. As you can see, there is no space or other character between hyphen and word.
My poor timetable, horribly disfigured :-(
Seriously, I get some strange referrers from Google. Who the hell gets the idea to clear that from a batch file? I mean, most programs store that kind of stuff either in the registry or in some ugly binary files. The first option is the easier one, at least on Windows 5.1 onwards, since you could use reg.exe. The other part is trickier except the application doesn't mind a missing file.
As for Word 2007, the most recently use files reside underIt works, but reminds me a bit of How do I inflate a bicycle tire with a potato?.
I bet some know the ancient Norton Commander, or at least one of its numerous clones. I myself use Far frequently. Something that makes OFMs so useful is the integrated command line but arguably this works best in a text interface (Total Commander does a sloppy job here, in my eyes).
Wouldn't it be nice to have that same level of command-line integration also in Windows Explorer? A fellow student mentioned that idea to me and I immediately thought that it can and would be useful and quickly hacked together a small impression of how it could look (see attachment).
I found something that implements a command window as a shell extension in Explorer: Command Prompt Explorer Bar but it's written in C#. Remembering Raymond Chen who in turn quotes Jesse Kaplan, one of the CLR program managers: Do not write in-process shell extensions in managed code.
So using the project mentioned above won't be an option, not even as the base of a new one. So probably I will start to write that thing myself one day, using C++.