Archive for
January 2007
04 Jan 2007 12:09 pm//
Rant
A number of little things bother me about PowerShell, and I’d just like to outline them here.
Adding to arrays
According to get-help about_array :
“You can append an element to an existing array by using the += operator. When the operator is used on the array itself, it appends the value.”
This isn’t completely true. If the right hand side of the += is also an array, then the elements of that array are added, not the array itself. This makes it very difficult to build up an array of arrays:
$a = @() # start with an empty array
$a += 1,2 # this doesn't work - it adds 1 and 2
so you need to do:
$a += 1
$a[-1] = 1,2
I think that either a) the documentation be updated to make this clear or b) fix += so it really does add the RHS as a new element. Otherwise, I’m going to have to use something like this, which is a bit ugly (but actually much more efficient):
$a = new-object collections.ArrayList
$a.add( @(1,2) )
Update: I’ve since discovered you can do this instead with the unary comma operator followed by a parenthesised list. The syntax is a bit weird (and hard to guess) but I believe the next version of PowerShell will get better documentation in this area.
$a=@()
$a += ,(1,2)
Integer division
Many languages support integer division, yielding an integer result. Many languages compliment this by offering a modulus division aswell. This is great, because one often has an index into a pseudo-2d array and you want to get the row and column values. Notionally:
width=10
offset = 17
row = offset DIV width
column = offset MOD width
This should yield row=1, column=7
In PowerShell:
[int]$width = 10
[int]$offset = 17
[int]$row = $offset / $width
[int]$column = $offset % $width
This yields a row of 2. The division, even though both sides are [int] is done using floating point and rounded up.
To work around it, we have to do this:
[int]$row = [Math]::Floor($offset/$width)
Not sure of a sensible fix for this… maybe a new operator like -idiv ? or the pythonesque //
Despite the title, this is not a rant
Grrr is a pet project of mine that came after the exploratory work with psinvaders. I was somewhat dissatisfied with myself for doing so much without seeing how else it could be done, especially with respect to drawing of images, animation, etc.
So what is Grrr? Grrr is a set of functions written in pure PowerShell that let you create playfields with scrolling viewports, draw lines and images, animate and move sprites, and generally be an inappropriate use of the technology.
The version of Grrr discussed in this article can be downloaded from here. Updated versions will appear on the downloads page.
To use, you write a script of your own and source it with a dot/period, like this:
. ./grrr.ps1
I suppose you could do this in your $profile, but I prefer to keep things self contained as PowerShell’s global scope can get very cluttered very fast.
Testing
In the Grrr distribution, there is a very mini unit test framework called psunit.ps1.
The script grrr-test.ps1 uses this to unit test grrr.ps1. Hurrah for test-driven development! The picture shows it in action. Click on it to see the full thing.
To run the test your self, type ./grrr-test.ps1 in the directory where this is unzipped.
Example scripts
There are three example scripts. Run them like he unit test script.
They are:
⁃ grrr-test-clock.ps1 – a simple script that shows back buffering and drawing lines
⁃ grrr-test-sprite.ps1 – shows animation of sprites… some controlled semi-manually, and one by a motion path
⁃ grrr-test-scramble.ps1 – show the use of tilemaps to produce the effect of paralax scrolling.
The latter is very slow and really shows up how poor PowerShell by itself performs.
Have a look at the code, play around with it, tell me it’s rubbish if you like
The next steps for this project are adding a proper game loop controller, with key event handling, fps throttling and a few more motion handlers and behaviours – I’d like for sprites to be able to look after themselves, eg respond to proximity of others, shoot things, detect walls, etc.
I also want to make it faster. Maybe with C# inlining, maybe by making these things cmdlets, maybe by doing it all in C# in a custom host application. Who knows.
In a previous post I said that I always like to try to write space invaders in every language that I learn. Well, PowerShell in the standard Windows console window looked like a great candidate so I set about the task in my spare time. My colleagues Richy King, Nik Crabtree and Brian Long joined in the efforts and between us, after 37 revisions, we came up with something that was:
a) Silly
b) Inappropriate use of PowerShell
c) Quite a bit of fun.
Download it here: psinvaders r94 Update: this version now includes sound.
Unpack the zip file, then from the directory where psinvaders.ps1 is, type ./psinvaders.ps1. Enjoy!
Any future updates may appear on the downloads page.
Here are screen shots of the play screen and the score advance table.
How it works
All the drawing is based on drawing ‘sprites’ on the console screen. No back buffering takes place, so when a sprite is drawn, it erases itself from its most recent position, updates the x,y value, the draws itself in the new position.
The drawing itself is done using [Console]::Write. Since writing this we discovered the joys of BufferCells, and one of the reasons for taking this project no further.
Reading the key events proved to be quite simple: we just check if a key event is available, then consume all the event types, maintaining the down/up state for movement keys and just observing down events for firing and putting in new credits.
The game is quite playable, speed-wise, because very few sprites are moved in the inner loop: the base, one space invader, and any bombs and missiles. This means that:
a) The game moves at a reasonable pace.
b) The alien block gets quicker as more are killed
c) An alien bomb will overdraw an lower alien until next time.
The rest of it is fairly basic game loop logic.
What’s next?
I’m done with psinvaders now. I’ve started working on a better framework for doing back-buffered drawing of sprites, images, tiled backgrounds and lines/points.
Currently, it’s pure PowerShell and unusably slow, but I may start doing some C# or JScript inlining to speed it up. Thanks for Lee Holmes for that inspiration.
Or maybe I’ll just wait for the anticipated performance inprovements in PowerShell 1.1
Oh dear, it seems that even though this is 2007, the most popular web browser on the planet (IE
Will change it over to olde worlde JPEGs later, but in the mean time, if you’re using Windows, do yourself a favour and install Firefox or IE7.
Update: I’m not entirely sure what the problem is here… this site looks fine with IE6 on Win2k, but not on IE6 on my Wife’s XP. IE7 looks fine. There appear to be known problems with IE and PNG alpha, and overlapping PNGs, but I don’t know.
I was going to start the new year with a positive note, but then I thought, lets get a PS1 pet hate out of the way first.
PowerShell is slow.
There are many ways to demonstrate this, but for this case I’m going to use a small snippet of code I found to render the mandelbrot set to the console window. It’s not my code and don’t know where it came from, but algorithm is fairly well known.
The code to demonstrate this is in a zip file here.
If you run ./mandel2.ps1 you get this pretty picture.
There is a Windows Scripting Host version. Run this with cscript mandel2.wsf.
There is a JScript.NET version. Compile it with JSC and or run the supplied one with ./mandel2.js.exe.
There is even a javascript-embedded-in-a-HTML-page version, just click on mandel2.html.
Now on my machine (a 2.66ghz quad core MacPro running XP in Parallels Desktop), I get these results:
| PowerShell |
1510 ms |
| Windows Scripting Host |
90 ms |
| JScript.NET |
160 ms |
| HTML (IE7) |
110 ms |
| HTML (Firefox 2) |
140 ms |
| HTML (Safari on OSX) |
103 ms |
OK, so the existing javascript engine in Windows (used by IE and WSF) are pretty good at this. Safari’s is pretty good (using KJS). So why is this brand spanking new language, PowerShell, so very poor?
It’s more than an order of magnitude slower than Microsoft’s previous attempt at a scripting environment!
This tardiness really shows itself in other inappropriate projects I’m working on in PS1. I really hope the PowerShell team at Microsoft address this for version 1.1 – maybe they should go speak to the jscript team.