Archive for 2007

Text and path gotchas

PowerShell is now my default Windows shell, but every now and then, little things crop up that make me want to go back to CMD.exe, or better cygwin/zsh.

Someone gave me an example of filtering an ASCII text file, stripping out the first 3 characters of each line.

On a Mac/UNIX box, you’d simply do:

cut -c4- infile.txt > outfile.txt

With PowerShell, you do:

gc infile.txt | % { $_.remove(0,3) } | sc outfile.txt

As an asside, on my machine, the latter takes 80 times longer to do the job on a 8MB text file than the former , but we’ll skip over that :-) So, to the gotchas.

Gotcha 1 – text gets recoded

You might be tempted to do this instead:

gc infile.txt | % { $_.remove(0,3) } > outfile.txt

If you did, the resulting outfile.txt would be UTF16 and so be double the size of the original (less the cut 3 chars per line).

You might not notice this at first, as PS1 handles all this sort of thing transparently, but at some point, something might choke on it. You can be specific about output encoding, but that’s not something you might think about.

Gotcha 2 – path weirdness

My working area is: c:\Documents and Settings\adrian\My Documents\proj\top. That’s quite a lot to deal with, so I usually make it shorter by doing this:

new-psdrive -name doc: -psprovider filesystem -root "c:\Documents and Settings\adrian\My Documents"

so my working directory is actually doc:\proj\top. Much shorter, however, when I run the first command above, I get this:

PS doc:\\proj\\top> gc infile.txt | % { $_.remove(0,3) } | sc outfile.txt
Set-Content : The given path's format is not supported.
At line:1 char:42
+ gc infile.txt | % { $_.remove(0,3) } | sc  ﹤﹤﹤﹤ outfile.txt
The pipeline has been stopped.
At line:1 char:30
+ gc 100.txt | % { $_.remove( ﹤﹤﹤﹤ 0,3) } | sc outfile.txt
Set-Content : The given path's format is not supported.
At line:1 char:42

Odd that gc didn’t mind, but sc did.

You can’t even use resolve-path to fix it because if outfile.txt didn’t already exist, you’d get an error… maybe you need to use new-item -type file or something first?

To be honest, I gave up. PowerShell should really be making things easier, not throwing up barriers at every turn.

What colour is yours?

I noticed something very odd today.

My PowerShell console thinks that the default white text is actually “DarkYellow.”

doesn't look yellow to me

If I set it to “White” there is no visible difference.

What colour is your default console?

Update: I’ve found a use for “darkyellow” being white. When you run something like findstr bla *.* the filename match is brighter, and so becomes “yellow” and stands out nicely.

ConsistentlyWeirdly, in CMD.exe, color 6 (dark yellow) actually is dark yellow.

Lastly, why is the default background’s “darkmagenta” actually a somewhat de-saturated dark blue?

Moving to WordPress

I’ve been having problems with RapidWeaver as my blogging software, not limited to RSS links being broken, and no previous/next links for the blog, so I’ve decided to move it to WordPress.

It looks like it’s all ok now, but if you see anything broken, please let me know.

The blog’s RSS feed is also redirected, but if your RSS doesn’t understand redirects (http 30x) you can resubscribe here (atom) or here (rss).

Unfortunately, I was unable to move all the comments people left to WordPress, but I do still have them.

Convert images to text (ASCII art)

Recently, whilst messing with sprites and the Grrr framework, I got thinking about better graphics for games.

As PowerShell is very slow at doing console atomic write operations, a game should really have fewer, larger sprites. I then thought about ASCII art, and wouldn’t it be great if PowerShell could convert existing images (jpg, png) and produce lines of text for use with Grrr’s create-image function.

So my morning’s work is a PowerShell script that does just that.

You can download it here: convert-image2text.ps1 (as a text file)

(If you’re reading this from the RSS feed, the link may be broken – open the blog page if so)

Unfortunately, it’s only monochrome. I had a lot of trouble getting a reasonable conversion of RGB or HSV to the console’s limited colour palette and character range, so in the end, I removed it.

The script uses System.Drawing and demonstrates one (a good?) way of adding an assembly to PowerShell.

Usage:

./convert-image2text.ps1 imagefile 
      [ -maxwidth nchars ] [-palette ascii | shade | bw ]

Here’s an example using the default -palette ascii option:

monolisa-ascii.gif

Here’s the same with the -palette shade option:

monolisa-shade.gif
Both are from this source image (click to see full size):


monalisa-small

Console screen grabs in html

[Updated 25 Jan 2007, well rewritten :-) ]

Something I find myself doing a lot is getting a screen shot of a PowerShell console window and posting it some place. Unfortunately, its always a bitmap, and occasionally, I want it as formatted text.

Now, the console is readable via $host.ui.rawui.GetBufferContents, so I wrote a small(ish) script to do just that, outputting lines of html.

You can download the script here get-bufferhtml.ps1.

Put the script somewhere so you can run it by name.

By default, the script will grab lines from the top of the buffer up to, but not including the current line, so if you type in this sequence:

PS> get-bufferhtml > out.html
PS> get-date
PS> asdasda
PS> get-bufferhtml > out.html

You end up with this:

PS> get-bufferhtml > out.html
WARNING: There must be one or more lines to get
PS> get-date                                                            

25 January 2007 14:17:42                                                

PS> asdasda
The term 'asdasda' is not recognized as a cmdlet, function, operable pr
ogram, or script file. Verify the term and try again.
At line:1 char:7
+ asdasda < < < <  

Note that the first line produced a warning, the second showed the date, the third produced an error and the last command (not shown) produce the above.

That output was then just pasted into this blog entry.

Read on »

Sudoku

Some time ago, I wrote a Sudoku solver in Java, along with an editor, interactive hint mode, puzzle generator etc, but the project never got finished because of feature creep and I generally got a bit bored of it all.

This morning, I resurrected the project and implemented the solver in PowerShell.

It’s not the shortest solver in history as it has gone through some performance improvements, but it does work and unless you’ve got a really hard puzzle, it’s quite quick too.

Download the script from here: sudoku.ps1

There are sample puzzles here (simple) and here (very hard). They are simple text files with numbers separated by white space. A zero indicates a blank in the puzzle.

You run the script like this:

PS > ./sudoku.ps1 sample-puzzle.txt
Going to to try to solve this puzzle:
7 . 5  . 3 .  8 . 2
. . 2  8 . 1  4 . .
8 1 .  . . .  . 5 6

. 3 .  1 . 8  . 2 .
. . 1  . 7 .  9 . .
. 9 .  3 . 2  . 4 .

9 8 .  . . .  . 3 7
. . 3  9 . 4  5 . .
2 . 6  . 8 .  1 . 4

Solved!
Guesses 53 (9 were wrong)
Elapsed time 00:00:00.4850316
Result:
7 4 5  6 3 9  8 1 2

3 6 2  8 5 1  4 7 9
8 1 9  2 4 7  3 5 6

4 3 7  1 9 8  6 2 5
6 2 1  4 7 5  9 8 3
5 9 8  3 6 2  7 4 1

9 8 4  5 1 6  2 3 7
1 7 3  9 2 4  5 6 8
2 5 6  7 8 3  1 9 4

I welcome any hints on performance or algorithmic improvements. No C# inlining please, it’s a PowerShell project :-)

The very hard puzzle above takes a very long time to solve. So long, in fact, that I gave up waiting for it. If there is anyone out there with space time and cpu cycles, please run it and let me know how long it takes :-)

Update: I’ve heard from one person that it takes approx 1.2 days to solve. My original Java app, in contrast takes 4.1 seconds.

Update 2: It looks like I inspired Mark Sheppard to do a better job (ie, not brute force). His PowerShell script solves the hard puzzle in 12 seconds (9.3 seconds on my Mac). Well done!

Minor gripes

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 //

Grrr!

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.

grrr-test_thumb

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.

grrr-demo-scramble_thumb

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.

Space Invaders

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 ;-)

PNG and Internet Explorer

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.