Let's play a game: BASIC vs. Ruby vs. Python vs. PHP

In November I wrote about rediscovering BASIC Computer Games, a book I had when I was learning programming in the ’80s. Flipping through it recently I came across a simple game called “Reverse”:

The game of REVERSE requires you to arrange a list of numbers in numerical order from left to right. To move, you tell the computer how many numbers (counting from the left) to reverse. For example, if the current list is 2 3 4 5 1 6 7 8 9 and you reverse 4, the result will be 5 4 3 2 1 6 7 8 9. Now if you reverse 5, you win.

The original BASIC version, including instructions and comments, is about 60 lines. It seemed like a good candidate for a quick language comparison; a chance to learn a little more Ruby and to see how it felt compared to two languages I’m more familiar with, Python and PHP. (If I had any skill in Perl or Tcl or Scheme they’d be included as well. Javascript should probably be here too.)

I also wanted to see just how much shorter these new versions would be – the BASIC program takes about eight lines just to initialize the array of shuffled numbers.

The three programs are reproduced below; all were tested on my PowerBook running OS X 10.4.3, with Ruby 1.8.2, Python 2.4.1, and the PHP CLI 4.3.11. Their output looks identical in the shell. Here’s the end of a game:

...
3 1 2 4 5 6 7 8 9
Reverse how many? 3
2 1 3 4 5 6 7 8 9
Reverse how many? 2
Done! That took you 9 steps.

Here’s the code. I tried to be fair with the line and byte counts. I do think the counts represent the languages' respective verbosity levels in a general way.

Ruby (10 lines, 274 bytes)

numbers = (1..9).sort_by{ rand }
steps = 0

while numbers != numbers.sort
  puts numbers.join(" ")
  print "Reverse how many? "
  flipcount = gets.to_i
  numbers[0...flipcount] = numbers[0...flipcount].reverse
  steps += 1
end

print "Done! That took you #{steps} steps.\n"

Python (9 lines, 304 bytes)

import random

numbers = random.sample(range(1,10), 9)
steps = 0

while numbers != sorted(numbers):
    print " ".join(map(str, numbers))
    flipcount = int(raw_input("Reverse how many? "))
    numbers[:flipcount] = reversed(numbers[:flipcount])
    steps += 1

print "Done! That took you %d steps." % steps

PHP (12 lines, 381 bytes)

$numbers = range(1, 9);
shuffle($numbers);
$sorted = $numbers;
sort($sorted);
$steps = 0;

while ($numbers != $sorted)
    {
    print implode(" ", $numbers) . "\n";
    print "Reverse how many? ";
    $flipcount = (int)trim(fgets(STDIN));
    array_splice($numbers, 0, $flipcount, array_reverse(array_slice($numbers, 0, $flipcount)));
    $steps++;
    }

print "Done! That took you $steps steps.\n";

Observations

  • Ruby’s win on concision doesn’t, to my eyes, come at the expense of readability. There are some flavors of Ruby code that I find frighteningly Perl-like, but none of that emerged here.

  • I was surprised that PHP didn’t take more lines; it loses in the awkward initialization section, but nested functions allow the flip to happen in one line, albeit a long one.

  • Despite the warm feeling of cleverness I got from figuring out how to do the flip operation in one line of Python, the Ruby equivalent is inarguably easier to read.

  • PHP is just ugly-looking.

  • I am very tempted to actually learn Ruby. For simple things at least, it has a concision and consistency that remind me strangely of Forth. And I mean that in a nice way.

Update: Not knowing when to stop, I’ve since done versions in Logo and Io and Lua and Scheme. Readers have contributed versions in F-Script, False, Haskell, JavaScript, Lisp, Perl, Prolog, REBOL, Squeak, Tcl, and VBScript.
Another update: A scan of the original page is viewable at the Atari Archives.

metapundit commented on Mon Jan 16 02:48:19 2006:

Hmm. I’ve been meaning to really learn python for a while now and have been resisting the ruby bandwagon. That ruby code sure is readable tho…

You can see how Python’s strong typing adds a bit of verboseness with the explicit conversion to string in the join. I would’ve mapped tho (ie " “.join(map(str,numbers) seems more terse and more readable at the same time…)

Sadly, I write PHP full time for a living…


Erik Wilsher commented on Mon Jan 16 05:32:02 2006:

Some thing I would do differently in the python sample:

Initialization of data: numbers = random.sample(range(10),10)

Reversing the flip: numbers[:flipcount] = reversed(numbers[:flipcount])


Paul commented on Mon Jan 16 06:42:18 2006:

All good suggestions, thanks! I’ve updated the code to reflect them. I had actually played with reversed() but was tripped up while experimenting by the fact that r = reversed([1,2,3]) gets the iterator object; you need to assign to a slice (e.g. r[:] = reversed([1,2,3])) to get a reversed list.


Palo commented on Mon Jan 16 06:54:09 2006:

here is a way how to increase the number of lines in the python code:

numbers=range(1,10) random.shuffle(numbers)

(I find it a bit more readable than random.sample(range(1,10), 9))

Also, in python2.4 you can use

" “.join(str(n) for n in numbers)

in place of

" “.join([str(n) for n in numbers])

(saved 2 characters!). [to save even more characters, one could use

flipcount = input(“Reverse how many? “)

but I think that’s justly considered dangerous]


Dominic Fox commented on Mon Jan 16 07:40:45 2006:

My Haskell version is here:

http://codepoetics.com/poetix/index.php?p=213

There’s a certain amount of scaffolding that we have to put in ourselves, but the main loop’s tolerably concise.


masklinn commented on Mon Jan 16 07:53:09 2006:

Metapundit > Ruby’s type system is no weaker than Python’s, both are strongly dynamically typed languages.

The difference is that Ruby’s Array#join method calls to_s (string conversion) on every element of the array (which is explicitely stated in the documentation, check ri Array#join) while Python’s str.join doesn’t (here again, it’s explicitely stated in the documentation that join takes an array of strings).


Filip commented on Mon Jan 16 08:36:52 2006:

In the python version, you could do random.sample("123456789", 9) to get away with the cleaner " ".join(numbers) later on.

The initialization in the PHP version also looks a bit bulky, and could probably be cut down to something like:

$sorted = $numbers = range(1, 9);
shuffle($numbers);
$steps = 0;

Andrew Dalke commented on Mon Jan 16 10:54:25 2006:

More traditionally the way to reverse list elements in Python is

numbers[:flipcount] = numbers[flipcount-1::-1]

for example

>>> x=[1,2,3,4,5]
>>> i=2
>>> x[:i] = x[i-1::-1]
>>> x
[2, 1, 3, 4, 5]
>>> i=4
>>> x[:i] = x[i-1::-1]
>>> x
[4, 3, 1, 2, 5]
>>> 

Paul commented on Mon Jan 16 11:29:18 2006:

In Python, save some bytes with

print " ".join(map(str, numbers))

Bye …


Pat Maupin commented on Mon Jan 16 11:42:44 2006:

Python version could be somewhat shorter.

numbers[:flipcount] = numbers[flipcount-1::-1]

I find this actually clearer than reversed().


metapundit commented on Mon Jan 16 12:15:18 2006:

masklinn:

Ruby’s type system is no weaker than Python’s, both are strongly dynamically typed languages.

The difference is that Ruby’s Array#join method calls to_s (string conversion) on every element of the array (which is explicitely stated in the documentation, check ri Array#join) while Python’s str.join doesn’t (here again, it’s explicitely stated in the documentation that join takes an array of strings).

My mistake. I was thinking ruby was weakly dynamically typed (like PHP is) and python was strongly dynamically typed… Aside from the typing issues, does seem like python’s join should implicitly convert list elements to strings since join is a string only operation… Ruby definitely does the right thing here and I guess I have to chalk the terseness up to better library design rather than difference in typing…


metapundit commented on Mon Jan 16 12:22:27 2006:

Nobody buys the superiority of map over list comprehensions? I just see

print " ".join([str(n) for n in numbers])

as a little verbose to mentally unpack. I can’t help seeing for as looping construct so working from inmost construct I see “okay, loop over list, converting current item to string, making a new list of the result”, and join by a space.

" ".join(map(str,numbers))

I look at and think “map array to array of strings”, and join by a space.


Paul commented on Mon Jan 16 12:38:15 2006:

I buy it, and in fact I changed the code accordingly! (Somehow it didn’t make it in with the changes I made last night.)


Christophe commented on Mon Jan 16 14:32:40 2006:

I’ll have to say that the Ruby version isn’t a good idom. sort_by{ rand } isn’t a true random shuffle as done in Python.

http://eigenclass.org/hiki.rb?sort_by+rand+is+biased

Ruby loses points for an invalid program :) And on the point of ease of reading, the version : numbers = range(1,10) random.shuffle(numbers)

is the best in my opinion. Not everything needs to be a one liner.


Krys commented on Mon Jan 16 17:26:35 2006:

In the Python code you can save 2 more lines at the expense of readability. Python can so several assignments on the same line so you could have

numbers, steps = random.sample(range(1,10), 9), 0

and

numbers[:flipcount], steps = reversed(numbers[:flipcount]), steps + 1

I don’t know anyone who would do that in “real” code, however. :-)


Filip commented on Mon Jan 16 17:54:58 2006:

From another angle, all three programs would benefit from being a few lines longer. Based on pure principles, if nothing else.


anonymous commented on Mon Jan 16 18:13:50 2006:

raw_input returns strings, input() returns whatever python thinks is appropriate; i.e. converting to int implicitly.

flipcount = input(“Reverse how many? “)

Gets python below 300bytes.


Paul commented on Mon Jan 16 20:31:43 2006:

Filip, I agree with you, at least on the Python and PHP – when working on short little programs like this it’s easy to get carried away with condensing things.

I’m not sure that I’d get much out of breaking down the Ruby version further, but I suppose the real test would be to see what I think of it in six months.


Sebastian commented on Tue Jan 17 03:22:02 2006:

A variation of the Python one, more easy to follow, but a bit more verbose. And the reverse, while easy to guess what it does, not so easy to see why.

import random
reverse = -1

numbers = random.sample(range(1,9+1), 9)
steps = 0

while numbers != sorted(numbers):
    print " ".join(map(str, numbers))
    flipcount = input("Reverse how many? ")
    numbers[:flipcount] = numbers[flipcount-1::reverse]
    steps += 1

print "Done! That took you %d steps." % steps

Sebastian commented on Tue Jan 17 03:24:25 2006:

Oops, the first two lines went into the paragraph there. Maybe there should be a preview function, if not even an edit function?


Paul commented on Tue Jan 17 06:23:36 2006:

Fixed it for you – but yes, preview is on my to-do list…


Asokan Pichai commented on Wed Jan 18 20:31:13 2006:

Again some more explicitness - adding to length seems to me to be a nice thing here

import random
base = range( 1, 10 )

numbers = random.sample( base, 9 )
steps = 0

while numbers != base: 

I also like the avoiding of sorting to produce a constant list.


Terry commented on Thu Jan 19 14:16:56 2006:

The Python version could get its byte count down - and be cleaner at the same time - by using flipcount = input(“Reverse how many? “)

instead of

flipcount = int(raw_input(“Reverse how many? “))


Pascal commented on Mon Feb 13 04:21:22 2006:

Funny game, here is a REBOL version of this game. An interesting thing is its readability.

numbers: random ordered: [1 2 3 4 5 6 7 8 9]
count: 0

while [numbers  ordered][
	reverse/part probe numbers to-integer ask "Reverse how many? "
	count: count + 1
]

print reform ["Done! That took you" count "steps."]

Pascal commented on Mon Feb 13 04:28:10 2006:

Markdown ate the “different” operator in the “while” statement, which is a less-than followed by a greater-than

Try again: while [numbers < > ordered][

Or you can also use this: while [not-equal? numbers ordered][

Cheers


Paul commented on Mon Feb 13 09:01:06 2006:

I love the REBOL version, thanks!

(The dropped angle brackets were due to some crude HTML-stripping I do for anti-spam and anti-XSS purposes, actually – not Markdown’s fault. I need to either clean it up or clarify my instructions.)


Arun commented on Mon Feb 20 05:07:40 2006:

Hi,

Thanks for inspiring me to write a javascript version of REVERSE. You can play it online at:

http://www.arunrocks.com/blog/archives/2006/02/15/reverse-a-javascript-game-in-24-hours/


Paul commented on Mon Feb 20 08:09:09 2006:

That’s excellent!


quag commented on Mon Feb 20 18:31:08 2006:

Here is a slightly tweaked Io version.

numbers := list(1,2,3,4,5,6,7,8,9) shuffle
count := 0
while (numbers != numbers clone sort,
    count = count + 1
    writeln(numbers join(" "))
    "How many to swap? " print
    howMany := File standardInput readLine asNumber
    numbers = numbers slice(0, howMany - 1) reverse appendSeq(numbers slice(howMany))
)
writeln("Done! That took you ", count, " steps.")

Paul commented on Mon Feb 20 18:52:17 2006:

Cool, thanks. (I took the liberty of combining your two comments, hope that’s OK.)

I like the anonymous object trick there: “numbers clone sort”.

I considered the one-line swap but found it a bit harder to read. Is it generally more, er, “Ionic” to leave long message chains unbroken?


Olivier Ansaldi commented on Tue Feb 21 07:54:06 2006:

Paul, here’s a LISP version. I’m a bit rusty on the ol' LISP so I’m pretty sure someone out there will find a short/cleaner version.

(defun shuffle (l)
  (loop for i below (length l) do (rotatef (elt l i) (elt l (random (length l)))))
  l)

(defun prompt (l)
  (format t "~{~a~^, ~}~%How many to swap? " l)
  (read))

(defun playgame (n)
  (let ((goal (loop for i from 1 to n collect i)))
    (do ((count 0 (1+ count))
     (state (shuffle (copy-list goal))
            (let ((howmany (prompt state)))
              (append (reverse (subseq state 0 howmany)) (subseq state howmany)))))
        ((equal state goal) (format t "Done! that took ~d steps.~%" count)))))

Olivier Ansaldi commented on Tue Feb 21 20:58:52 2006:

Here’s my Prolog implementation. Check out: http://ozone.wordpress.com/2006/02/22/little-prolog-challenge/

Prolog “standard library” lacks the depth of languages like Ruby so a good part of the code is there to implement support predicates (shuffle, split). Prolog really shines for the game loop.


Paul commented on Fri Feb 24 12:24:00 2006:

Olivier, thanks for those. I’m envious that you got to Prolog before I did!

Compared to my hacky Scheme version (link posted in update notice up top), your Lisp looks quite compact.


tim bates commented on Thu Mar 2 07:21:38 2006:

php in 9 lines…

$sorted  = $numbers = range(1, 9);
shuffle($numbers);
$steps = 0;
while ($numbers != $sorted) {
    print implode(" ", $numbers) . "\n Reverse how many? ";
    $flipcount = (int)trim(fgets(STDIN));
    array_splice($numbers, 0, $flipcount, array_reverse(array_slice($numbers, 0, $flipcount)));
    $steps++;
}
print "Done! That took you $steps steps.\n";

Philippe Mougin commented on Tue Mar 28 16:18:45 2006:

Here is an implementation in F-Script:

http://www.fscript.org/reverseGame.htm

This page also shows the implementation of a program that plays to the game.


Paul commented on Tue Mar 28 17:16:26 2006:

Beautiful, Philippe, thanks!


Nick commented on Wed Mar 29 11:37:44 2006:

As awesome as that DHTML version is, here’s a simpler javascript that fits the original format (type ‘cscript whateverYouNamedIt.js’ to run):

// inordinate amounts of scaffolding

Array.prototype.dupe = function() { return this.slice(0); } // hacky
Array.prototype.empty = function() { while (this.length > 0) this.pop(); return this; }

Array.prototype.equals = function(that) {
    if (this.length != that.length) return false;
    for (var i = 0; i < this.length; ++i) {
        if (this[i] != that[i]) return false;
    }
    return true;
}

Array.prototype.appendAry = function(ary) {
    var result = this.dupe();
    for (var i = 0; i < ary.length; ++i) {
        result.push(ary[i]);
    }
    return result;
}

Array.prototype.shuffle = function() {
    var source = this.dupe();
    this.empty();
    while (source.length > 0) {
        var idx = Math.floor(Math.random() * source.length);
        this.push(source.splice(idx, 1));
    }
    return this;
}

Array.prototype.reverseLeft = function(count) {
    return this.slice(0, count).reverse().appendAry(this.slice(count));
}

// main code

var solved = new Array(1,2,3,4,5,6,7,8,9);
var numbers = solved.dupe().shuffle();
var steps = 0;

while (!numbers.equals(solved)) {
    WScript.StdOut.Write(numbers.join(" ") + "\nHow many numbers to swap? ");
    var howMany = +(WScript.StdIn.ReadLine());
    numbers = numbers.reverseLeft(howMany);
    steps++;
}

WScript.Echo("Done! That took you " + steps + " steps!");

Nick commented on Wed Mar 29 15:31:35 2006:

Meh. I decided it was a pinch too long, so I nixed appendAry() and reimplemented reverseLeft() like so:

Array.prototype.reverseLeft = function(count) {
    var left = this.slice(0, count).reverse();
    var right = this.slice(count);
    while (right.length > 0) left.push(right.shift());
    return left;
}

Nick commented on Sun Apr 2 10:29:28 2006:

Triple post! I had some free time this weekend, so I decided to torture myself, er, that is, implement a false version. False doesn’t provide a randomization faciility, so the ordering is hard-coded. It was the best I could do. You may now officially ph34r me:

0 3 1 4 2 5 9 7 8 6
0[$1+[$O@1-$][@]#%\%]d:s:
[10d;!1_1[@$][\$@=@&\1+]#%%~]
[9d;!.9[1-$][" "\.]#%
 10,"How many to swap? "B^^B%'0-$1>
 [$2>~[%\0]?$3=[%\@0]?$3>
  [$c:[$1>][\10*\1-@@+\]#
   c;[$1>][\10*\1-]#%[$1>]
   [$@$@/@@\$@$@/@$@*@\-\10/]#
  ]?1s;+s:]?%]#[][]#s;
"Done! That took you "." steps!"

You gotta admit. It looks gorgeous. Oh, and I second comment previews.


Paul commented on Sun Apr 2 10:34:37 2006:

Wow.


Eric commented on Thu Apr 27 15:45:53 2006:

Here’s a perl version.

@array = (1..9); $steps = 0; shuffle( @array ); while (@array != sort {$a $b} @array){print join(” “, @array) . “\nReverse how many?\n”; $num = ; splice(@array, 0, $num, reverse(@array[0..($num-1)])); $steps++; } print “Done! That took you $steps steps.\n”; sub shuffle {my $array = shift; my $i; for ($i = @$array; –$i; ) {my $j = int rand ($i+1); next if $i == $j; @$array[$i,$j] = @$array[$j,$i];}}


Eric commented on Thu Apr 27 16:01:02 2006:

Sorry I was being lazy, now it’s even better (just take everything between the lines):


@y=(1..9);f(@y);while(@y!=sort{$a$b}@y){print join(” “,@y)."\nReverse how many?\n”;$m=;splice(@y,0,$m,reverse(@y[0..($m-1)]));$n++;};print “Done! That took you $n steps.\n”;sub f{my $y=shift;for($i=@$y;–$i;){$j=int rand($i+1);next if$i==$j;@$y[$i,$j]=@$y[$j,$i];}}



Eric commented on Thu Apr 27 16:01:59 2006:

BTW- that’s all one line, so that means perl wins!


Eric commented on Thu Apr 27 16:14:17 2006:

Dangit!

I didn’t actually test it, the last two had a flawed loop condition, this one actually works (tested it), still one line though, (would be smaller but I had to created a decent shuffle function).


@y=(1..9);f(@y);while((join('',@y))!=(join('',sort{$a$b}@y))){print join(” “,@y)."\nReverse how many?\n”;$m=;splice(@y,0,$m,reverse(@y[0..($m-1)]));$n++;};print “Done! That took you $n steps.\n”;sub f{my $y=shift;for($i=@$y;–$i;){$j=int rand($i+1);next if$i==$j;@$y[$i,$j]=@$y[$j,$i];}}



Eric commented on Thu Apr 27 16:27:29 2006:

Just keeps getting better, now it will tell you how long it took you as well as how many steps!


@y=(1..9);f(@y);while((join('',@y))!=(join('',sort{$a$b}@y))){print join(” “,@y)."\nReverse how many?\n”;$m=;splice(@y,0,$m,reverse(@y[0..($m-1)]));$n++;};print “Done! That took you $n steps and “.(time-$^T).” seconds.\n”;sub f{my $y=shift;for($i=@$y;–$i;){$j=int rand($i+1);next if$i==$j;@$y[$i,$j]=@$y[$j,$i];}}



Paul commented on Thu Apr 27 18:31:49 2006:

Thanks for the contribution. It’s simplicity itself!


Eric commented on Fri Apr 28 13:17:16 2006:

Here’s another one. This one is for vbscript. Just put this into a file and give it an extension of .vbs (on a windows machine of course) and it should work on most new windows machines (uses wscript host).

I had a heck of a time with the shuffle on this one, I don’t know vbscript that well.


Dim wshShell
Dim s
Dim vtt
Dim vst
Dim vs
Dim myArray(8)
Dim sarray

Set wshShell = Wscript.Createobject("Wscript.shell")
If InStr(Ucase(wscript.FullName), "CSCRIPT") = 0 Then
 wshShell.Run "cscript.exe //nologo " & Chr(34) & WScript.ScriptFullName & Chr(34)
 Wscript.Quit
End If

do until (s = "q")
 wscript.stdout.writeline "Press Enter to play!"
 wscript.stdout.write "(Type 'q' at any time to quit the game)"
 s = wscript.stdin.readline
 if (s = "q") then
  wscript.quit
 end if

 vs = time
 vst = 0

 for a=0 to 8
  myArray(a)=(a+1)
 next

 randomize
 do until (myarray(0)  1 and myarray(1)  2 and myarray(2)  3 and myarray(3)  4 and myarray(4)  5 and myarray(5)  6 and myarray(6)  7 and myarray(7)  8 and myarray(8)  9)
  for b=8 to 0 step -1
   randomize
   c = Int((b+1)*Rnd)
   if bc then
    d=myarray(c)
    myarray(c)=myarray(b)
    myarray(b)=d
   end if
  next
 loop

 do until (myarray(0) = 1 and myarray(1) = 2 and myarray(2) = 3 and myarray(3) = 4 and myarray(4) = 5 and myarray(5) = 6 and myarray(6) = 7 and myarray(7) = 8 and myarray(8) = 9)
  vst = vst + 1
  for each e in myarray
   wscript.stdout.write e & " "
  next

  wscript.stdout.writeline
  wscript.stdout.writeline "Reverse how many?"
  f = wscript.stdin.readline

  if IsNumeric(f) = False then
   if (f = "q") then
    wscript.quit
   end if
   wscript.stdout.writeline "Pick a NUMBER!!!"
  elseif f = 1 then
   wscript.stdout.writeline "That's pointless, pick again!"
  elseif f < 1 then
   wscript.stdout.writeline "Ok, you know you can't do that!"
   wscript.stdout.writeline "Pick again you fool!"
  elseif f > 9 then
   wscript.stdout.writeline "Ok, stop messing around!"
  end if

  if (IsNumeric(f) = False) then
   f = 0
  end if

  if (f > 1 and f < 10) then
   redim sarray(f-1)
   for g = 0 to (f-1)
    sarray(g)=myArray((f-1)-g)
   next
   for g = 0 to (f-1)
    myArray(g)=sarray(g)
   next
  end if
 loop

 vtt = datediff("s",vs,time)

 wscript.stdout.writeline "Congratulations, you have won!"
 wscript.stdout.writeline "It only took you " & vst & " steps and " & vtt & " seconds!"
 wscript.stdout.writeline
loop


Avi commented on Wed Aug 9 09:05:35 2006:

Here is Tcl version (tcllib needed)

package require math
package require struct::list

set input {1 2 3 4 5 6 7 8 9}
set base $input
set steps 0
for {set i 0} {$i < [llength $base]} {incr i} {
    set index [::math::random 0 [llength $input]]
    lappend myarray [lindex $input $index]
    set input [lreplace $input $index $index]
}
while {[::struct::list equal $myarray $base]==0} {
    incr steps
    puts -nonewline "$myarray \n($steps) How Many? "
    flush stdout
    set howmany [gets stdin]
    set myarray [concat [::struct::list reverse [lrange $myarray 0 [expr $howmany-1]]] [lrange $myarray $howmany end]]
}
puts "$myarray \nDone in $steps steps"

Paul commented on Wed Aug 9 14:32:02 2006:

Markus Gaelli offers a Squeak (Smalltalk) version:

steps := 0.
numbers := (1 to: 9) asArray shuffled.
[numbers isSorted] whileFalse:
        [flipCount:= numbers indexOf: ((SelectionMenu selections: numbers)startUpWithCaption: \ 
            'Revert up to which number?' at: Display center  ).
        1 to: flipCount//2 do: [:i | numbers swap: i with: flipCount-i+1].
        steps := steps + 1].PopUpMenu inform: 'You needed ', steps asString,' \
            steps to sort the list.'

He’s also created a more elaborate eToys version (screenshot) that you can run in your browser if you’ve got the Squeak plugin.


BlueSun commented on Thu Aug 17 18:32:36 2006:

PHP in 7 lines:

$sorted  = $numbers = range(1, 9);
shuffle($numbers);

for ($steps = 0; $numbers != $sorted; $steps++) {
    print implode(" ", $numbers) . "\n Reverse how many? ";
    $flipcount = (int)trim(fgets(STDIN));
    array_splice($numbers, 0, $flipcount, array_reverse(array_slice($numbers, 0, $flipcount)));
}

print "Done! That took you $steps steps.\n";

Cannavaro commented on Tue Aug 22 15:14:36 2006:

When you mentioned Forth, I took it for a challenge ^___^ I have seen the language just for a brief time back in school years, so the following code almost certainly sucks, but at least it works (under gForth).

I wrote in a simple PRNG (shamelessly lifted from the language manual) but you should update the seed variable at first if you don’t want to play always the same game… For the “line count” part, line breaks and indentation are there for readability only; they don’t matter in Forth.

Anyway, I just can’t understand why that little neat piece of Ruby reminded you of this! o___O

=========================================================

hex
ff800000 constant ROL9MASK
decimal

variable seed

: ROL9 ( u1 -- u2 | rotate u1 left by 9 bits )
    dup ROL9MASK and 23 rshift swap 9 lshift or ;     
: RANDOM ( -- u ) seed @ 107465 * 234567 + rol9 dup seed ! ;
: RAND RANDOM abs swap mod ;

: NEWLINE 13 emit 10 emit ;

create workset 10 cells allot

: FILLNUMS
	workset
	10 0 DO
        dup i dup cells rot + !
	LOOP drop ;

: PRINTNUMS
	workset
	10 0 DO
        dup i cells + @ .
	LOOP NEWLINE drop ;

: MIXARRAY
	1 9 -DO
        workset i cells + dup @
        workset i RAND cells + dup @
        rot rot ! swap !
	1 -LOOP ;

: REVERSE
	dup 2 / 0
	?DO
        1 - dup cells workset + dup @
        workset i cells + dup @
        rot rot ! swap !
	LOOP drop ;

: CHECK
	1
	9 0 DO
        workset i cells + dup cell +
        @ swap @ - 
        1  IF <> 1- unloop exit THEN
	LOOP ;

: MESSAGE s" How many numbers do you want to reverse? (press 0 for 10) " type
  key dup emit NEWLINE 48 -
  dup 0= IF drop 10 THEN dup 2 11 within invert IF drop 0 THEN ;

: PLAY 0 NEWLINE FILLNUMS MIXARRAY
  BEGIN PRINTNUMS MESSAGE REVERSE 1+ CHECK UNTIL
  s" You solved the game in " type . s"  steps" type ;

Cannavaro commented on Tue Aug 22 16:21:58 2006:

Well, I wrote the “unequal” operator and had it stripped just like another reader before… the last line of “check” was similar to this

1 < > IF 1- unloop exit THEN


Paul commented on Tue Aug 22 18:31:21 2006:

Fixed – sorry about that! It’s a vestigal anti-comment-spam measure. Akismet is working pretty well so I may change my anti-angle-bracket policy.


Thorsten commented on Sat Sep 2 21:47:56 2006:

Finally, which language is the winner?


Paul commented on Sun Sep 3 00:18:44 2006:

In the words of David Letterman: It’s an exhibition, not a competition!


Jessica commented on Fri Sep 8 16:38:07 2006:

$sorted = range(1, 9);
$numbers = $sorted;
shuffle($numbers);
$steps = 0;

You can cut a line out of the PHP code if I understand the range() function correctly. Why shuffle it and resort it?


Paul commented on Fri Sep 8 17:08:16 2006:

No good reason that I can see now. I think that sequence is an artifact of an earlier version.


Bill commented on Sat Sep 16 23:17:15 2006:

Here’s a readable perl version (9 lines, 365 chars):

use FreezeThaw qw(cmpStr);
my @sorted  = (1 .. 9);
my @numbers = sort {rand(10) > $a} @sorted;
for (my $steps = 0; cmpStr(\@numbers, \@sorted) != 0; ++$steps) {
    print join(" ", @numbers), "\nReverse how many? ";
    my $flipcount = ;
    splice(@numbers,0,$flipcount,reverse( @numbers[0..($flipcount-1)]));
}
print "Done! That took you $steps steps.\n";

Olivier Mengué commented on Tue Oct 3 11:13:16 2006:

More Perl 5 and Perl 6 versions (including Larry’s) in the perl.perl6.users newgroup thread.


Mike commented on Tue Oct 10 15:57:13 2006:

Anyone willing to post an assembler version? :)


Coaching commented on Wed Oct 18 16:41:25 2006:

PHP looks really ugly, the python code seems to be the slimmest…


Olivier Mengué commented on Fri Oct 27 12:57:46 2006:

Here is one version in the Microsoft Command Processor, better known as the “DOS prompt”.

@echo off

verify other 2>nul
setlocal enabledelayedexpansion
if errorlevel 1 echo Windows 2000/XP required.& goto :EOF

set sorted=%2
set sorted=%sorted:"=%
if "%sorted%"=="" (
    set sorted=123456789
    rem set sorted=ABCDE
)


set current=%1
set current=%current:"=%
if "%current%"=="" (
    set current=%sorted%
    call :Shuffle current
)

set steps=0

:Play
echo.%current%
if "%current%"=="%sorted%" goto Done
set /P flipcount=Reverse how many? 
if /I "%flipcount:~0,1%"=="q" goto :EOF

set left=!current:~0,%flipcount%!
set right=!current:~%flipcount%!
call :Reverse left
set current=%left%%right%

set /A steps+=1
goto Play


:Done
:: The only way to print '!' is to disable DelayedExpansion.
:: Yes, cmd.exe is really flawed: there is no escape char for '!' in
:: DelayedExpansion mode.
setlocal disabledelayedexpansion
echo Done! That took you %steps% steps.
endlocal
goto :EOF


:: ======= FUNCTIONS =======

:: Compute number of characters of variable named %1
:: Result is returned in both %errorlevel% and %Length%
:Length
setlocal enabledelayedexpansion
set l=0
:LengthLoop
set _=!%1:~%l%,1!
if not "%_%"=="" set /A l+=1& goto LengthLoop
endlocal & set Length=%l%
:: Set errorlevel and return
exit /B %Length%


:: Reverse characters of variable named %1
:Reverse
setlocal enabledelayedexpansion
call :Length %1
set /A p=Length/2
set r=!%1:~%p%,-%p%!
:ReverseLoop
set /A q=p-1
set r=!%1:~-%p%,1!%r%!%1:~%q%,1!
set p=%q%
if not %p%==0 goto ReverseLoop
endlocal & set %1=%r%
goto :EOF


:: Shuffle characters in variable named %1
:Shuffle
setlocal enabledelayedexpansion
call :Length %1
set /A count=5*Length
set d=!%1!
for /L %%i in (1,1,%count%) do call :ShuffleSub d
endlocal & set %1=%d%
goto :EOF
:ShuffleSub
set /A n=^(Length * %RANDOM%^) / 32768
set right=!%1:~%n%!
set %1=!right:~1!!%1:~%n%,1!!%1:~0,%n%!
::echo.!%1!
goto :EOF

Paul commented on Fri Oct 27 13:46:27 2006:

Thanks for that. Pretty funny to see, especially the workaround for the exclamation point!


cormullion commented on Sat Nov 25 07:24:29 2006:

This is a very nice post and I enjoyed the good-natured comments. It’s been interesting looking at all the different solutions.

Here’s my newLISP version (is newLISP - diabolus in programmatica - allowed? ;-))

(define (rev-slice n lst)
     (append (reverse (0 n lst)) (n lst)))

(set 'steps 0 'goal (sequence 1 10) 'state (randomize goal))

(until (= goal state)
    (println state "\nReverse how many?")
    (inc 'steps)
    (set 'state (rev-slice (int (read-line)) state)))
(string "\\nDone! That took you " steps " steps!")

newLISP is concise but not too terse (if there’s a difference). A bit less punctuation and fewer abbreviations (but plenty of parentheses, of course) make it high on bytes but low on lines.


cormullion commented on Sat Nov 25 09:05:54 2006:

PS: i thought I had indented that code so that a Markdown pass would keep it formatted correctly, but I obviously goofed somewhere. I don’t normally put every statement on a single line…! ;-) As originally written, there are 7 lines.


Paul commented on Sun Nov 26 06:50:33 2006:

Neat, thanks – I didn’t know about newLISP.

I took the liberty of fixing the code formatting (Markdown wants four spaces at the beginning of a code line).


halabuda commented on Thu Nov 30 13:31:22 2006:

In regards to the PHP version (and probably other languages as well) the initialization line: $steps=0; is unnecessary in terms of minimizing code because the increment operator will assume a value of 0 for undefined variables. The error suppression operator can be used to ignore any PHP notices about undefined variables. ie: @$steps++;


Paul commented on Thu Nov 30 13:49:56 2006:

Spoken like a true codegolfer!


Nick commented on Fri Dec 1 15:20:35 2006:

Hello again! I’m the nut-job responsible for that awful False version above. I decided to give Haskell a shot:

module Reverse where
import System.Random

prompt q = catch (putStr q >> readLn) $ const $ prompt q

play s [1,2,3,4,5,6,7,8,9] =
 putStrLn $ "Done! That took you " ++ show s ++ " steps!"
play s xs = do
 putStrLn $ unwords $ map show xs
 n <- prompt "Reverse how many? "
 play (s + 1) $ reverse (take n xs) ++ drop n xs

shuffle [] = return []
shuffle xs = do
 i <- randomRIO (0, length xs - 1)
 rest <- shuffle $ take i xs ++ drop (i + 1) xs
 return $ xs !! i : rest

main = play 0 =<< shuffle [1..9]

I like the shuffle function. It basically yanks a random element out of the list, sticks it in front, and shuffles the remainder recursively. I took a look at Dominic’s version; his effectively pairs each element with a random number, sorts the list by that random number, and strips them off. I smooshed together his shuffle and shuffleWith functions, then yanked the stateful IO up into main:

module Reverse where
import System.Random
import Data.List

prompt q = catch (putStr q >> readLn) $ const $ prompt q

play s [1,2,3,4,5,6,7,8,9] =
 putStrLn $ "Done! That took you " ++ show s ++ " steps!"
play s xs = do
 putStrLn $ unwords $ map show xs
 n <- prompt "Reverse how many? "
 play (s + 1) $ reverse (take n xs) ++ drop n xs

shuffle xs gen = map snd $ sort $ zip (randoms gen :: [Int]) xs

main = play 0 . shuffle [1..9] . mkStdGen =<< randomIO

The only differences here are shuffle, main, and the addition of import Data.List (for sort).


Paul commented on Fri Dec 1 15:26:18 2006:

Nice. I think Haskell’s next for me.

(I fixed the “<” problem for you – my tag-tripping code, an old antispam measure which I just removed, was getting in your way there.)


Nick commented on Sat Dec 2 03:47:38 2006:

And I highly recommend it! It was one of the most painful, brain-breaking experiences I’ve had learning a new language, but I know I’m better for it. The type system alone is worth the headache. It’s magic. Haskell.org has a great Getting Started guide. I used Hugs at first, and it’s alright, but GHC’s error messages are much friendlier. Unfortunately, it practically installs a Linux distro on my Windows box. *cries*

Work your way through Yet Another Haskell Tutorial until you have a loose grasp on the type system, before you try your hand at Monads. At some point, everyone seems to grumble about Monads in general and IO in particular. Writing Monad tutorials is a rite of passage for the Haskell newbie. The clearest that I’ve seen is You Could Have Invented Monads.

Dive in, and don’t give up! Good luck!

(Oh, and you missed a few &lt;’s in my code there. The first snippet has 3 lines that start n &lt;-, i &lt;-, and rest &lt;-, the second snippet has a n &lt;-. Could you please fix ‘em?)


Internetfirma Köln commented on Sat Dec 2 13:39:08 2006:

(define (rev-slice n lst) (append (reverse (0 n lst)) (n lst)))

(set ‘steps 0 ‘goal (sequence 1 10) ‘state (randomize goal))

(until (= goal state) (println state “\nReverse how many?") (inc ‘steps) (set ‘state (rev-slice (int (read-line)) state))) (string “\nDone! That took you " steps " steps!")

This code don’t work to me, something is wrong but i can’t understand what :( Help me pls!


cormullion commented on Sat Dec 2 15:33:36 2006:

Works fine for me. MacOS X 10.4.8, newLISP v 9.0.4.

Best to take this discussion to rather than here!


cormullion commented on Sat Dec 2 15:35:57 2006:

:-) oops it swallowed the url (where’s that preview? :-)

I meant ‘take this discussion to http://www.alh.net/newlisp/phpbb/'

sorry Paul


Nick commented on Sun Dec 3 03:58:01 2006:

Hee-hee. I think you’ll like this, Paul.


Paul commented on Wed Dec 20 15:20:28 2006:

What?

Why do I get so many inscrutable comments with German URLs?

Note: It may be hard to understand what I’m saying here since I’ve deleted dozens of spam comments in this thread. They’re typically almost-relevant sounding short sentences like “thank you for sharing this script”, with a username that doesn’t match the name given in the comment body, and a URL pointing to a .de (German) domain – never an internal page, always the top level. Weird.


cormullion commented on Wed Dec 20 15:34:56 2006:

I wonder whether someone is paying them to get their URL on other people’s web pages… I presume that’s what’s behind it. Perhaps its a German thing…?


Marc Hansen commented on Sun Dec 24 03:18:42 2006:

PHP is the best for me. In other words: The other script languages I don’t understand ;-)


Blogger commented on Sun Dec 24 03:20:18 2006:

My professor told me: Many futurists would agree that, had it not been for symmetric encryption, the refinement of suffix trees might never have occurred. Here, we verify the analysis of spreadsheets, which embodies the important principles of algorithms. We explore an ambimorphic tool for studying wide-area networks, which we call TidEffort. This is an important point to understand.


morris commented on Wed Dec 27 02:02:09 2006:

Paul: The “german” links are spam comments - link farming. Someone has obviously written a bot that can reasonably reliably read captcha texts.

Looks to be the same bot that was spamming my site (I recognise the cableguy link, and the patterns used for the comment text).

I replaced my captcha with a simple question and haven’t had any more spam comments.


Morris commented on Wed Dec 27 03:29:48 2006:

A tidier Javascript implementation. Javascript doesn’t have a standard console, so windows wsh is used. Save the code to reverse.js and then from the windows command shell run: cscript reverse.js

function flip(ar,n) { return ar.slice(0,n).reverse().concat(ar.slice(n,ar.length)); }

var goal = [1,2,3,4,5,6,7,8,9]; var numbers = goal; var steps = 0;

for (var i = 0; i < goal.length; ++i) { numbers = flip(numbers, Math.ceil(Math.random() * goal.length) ); }

while (numbers.join('') != goal.join('')) { WScript.StdOut.Write(numbers.join(’ ‘) + ‘\nHow many numbers to swap? ‘); numbers = flip(numbers, WScript.StdIn.ReadLine()); steps++; }

WScript.StdOut.WriteLine(‘Done! That took you ' + steps + ' steps!');


Morris commented on Wed Dec 27 03:33:03 2006:

Sorry, using proper markdown (I hope!):

function flip(ar,n) {
  return ar.slice(0,n).reverse().concat(ar.slice(n,ar.length));
}

var goal = [1,2,3,4,5,6,7,8,9];
var numbers = goal;
var steps = 0;

for (var i = 0; i < goal.length; ++i) {
  numbers = flip(numbers, Math.ceil(Math.random() * goal.length) );
}

while (numbers.join('') != goal.join('')) {
  WScript.StdOut.Write(numbers.join(' ') + '\nHow many numbers to swap? ');
  numbers = flip(numbers, WScript.StdIn.ReadLine());
  steps++;
}

WScript.StdOut.WriteLine('Done! That took you ' + steps + ' steps!');

Olivier Mengué commented on Sat Jan 27 20:00:16 2007:

I just blogged about my implementation of Reverse in Cmd.exe (see the code above).


Köln commented on Tue Jan 30 16:55:46 2007:

Very interesting, but it dont work.. Dominik, have you already found something?


js commented on Thu Feb 8 14:22:04 2007:

There are other worlds …. 3 lines solution in k (www.kx.com) explanation: sequence unsorted if not every number is greater than its predecessor n _draw -p generates n random numbers from 0..p-1 without repeated elems (|n#x),n _ x = (reverse n take x) concat (n drop x) c m\x = while c(x) is true, new x is m(x) unsorted(try)\x = while unsorted(x), new x is try x

unsorted:~&/>': try:{0:(5:x; "Reverse how many? "); n:0$0:; (|n#x),n _ x} `0:“Done! That took you “,($-1+#unsorted(try)\1+9_draw -9),” steps”


js commented on Thu Feb 8 14:26:06 2007:

bad formatting.. The code is

unsorted:~&/>’:

try:{0:(5:x; “Reverse how many? “); n:0$0:; (|n#x),n _ x}

`0:”Done! That took you “,($-1+#unsorted(try)\1+9_draw -9),” steps”


Sven commented on Thu Feb 22 15:54:08 2007:

Hi, please can you add a summary next time, so that your visitors can get an overview of the end-length of every code? Thank you.


Online Versicherungsvergleiche commented on Sun Feb 25 05:51:02 2007:

I prefer the code in JavaScript (like morris tidier Javascript implementation). That works good and sure.


Internetmarketing commented on Thu Mar 8 05:41:20 2007:

I really like PHP and don´t understand nothing about the snake (python) but in my childhood i programmed with Basic too i enjoyed it much it was so easy but today the computerlanguages are so much more powerfull but also complicated. i´m looking back to the good old “Basic”-times.


Paul commented on Fri Mar 16 22:58:58 2007:

I generally think of myself as too jaded to spend much time trying to understand the chaotic patterns of spam, but I have got to know why this post is the only one out of the 300+ posts on my blog that gets these German/Eastern-European one-liners with links to big boring German/Eastern-European company websites.

Again, this may seem like a bit of a non-sequitur since I’ve deleted most of the comments that appeared to be spam. The mystery remains, though.


Dan commented on Fri Mar 30 08:09:11 2007:

hi paul, i think it´s because of the most are just lazy. one have found a good way to become a backlink from your good blog. the others just look in “backlinkcheckers” of good ranking pages and find the backlink from this article and try to do the same. but maybe one have just searched for backlinks and made a list which he sell over eBay. its crazy at all the most time i think twice if i add a comment i don´t want that it seems i spam too. but i know u can delete comments and thats the reason i added this here.

head up, i think in future it will be better, the software is gonna be much better to prevent spam. i hope so :-)


Paul commented on Fri Mar 30 10:11:18 2007:

Hey, a non-spam comment from Germany! Thanks, Dan!

I suspect you’re right about the backlink business.


Martin Hamann commented on Fri Mar 30 10:31:55 2007:

genius: “From another angle, all three programs would benefit from being a few lines longer. Based on pure principles, if nothing else.”

i am a webmaster…Lol


Mediation Bernadette commented on Sat Apr 7 14:27:19 2007:

Hey, a non-spam comment from Germany! Thanks, Dan! LOL

PS. Don’t forget Poland, Paul :)


Paul commented on Sun Apr 8 17:30:43 2007:

I always get Poland and Perl confused.


Tomek commented on Tue Apr 17 07:29:40 2007:

Hey, a non-spam comment from Poland! Thanks for article. I don’t think that all comments from poland are spam! And not all comments from other country. It’s bigger problem people from USA buy .pl domains and spam people from DE buy .pl domains and spam … So please don’t write that people from poland spam here.


Joe commented on Mon May 21 10:35:26 2007:

thaaanks!! i’ve been searching for 2h for such a scribt.


Gabe commented on Tue May 22 23:24:42 2007:

Another VBScript implementation. Needed two custom procedures since VBScript does not have a Sort() method, or a way to reverse elements of an array (I compensated by converting array to string and reversing).

Randomize

Dim numbers(8)
For i = 0 To 8
    numbers(i) = Int((9 * Rnd) + 1)
Next

steps = 0

Do While Join(numbers) <> Join(Sort(numbers))
    WScript.Echo Join(numbers) & vbCrLf & "Reverse how many? "
    flipcount = WScript.StdIn.ReadLine
    ArrReverse numbers, flipcount
    steps = steps + 1
Loop

WScript.Echo "Done! That took you " & steps & " steps." & vbCrLf

Sub ArrReverse(array, intCount)

    str = Join(array)
    tmp = Split(StrReverse(Mid(str, 1, intCount * 2 - 1)) & Mid(str, intCount * 2))

    For i = 0 To 8
        array(i) = tmp(i)
    Next

End Sub

Function Sort(ByVal array)

    For i = UBound(array) - 1 To LBound(array) Step -1
    For j = 0 To i
        If array(j) > array(j + 1) Then
            temp = array(j)
            array(j) = array(j + 1)
            array(j + 1) = temp
        End If
    Next
    Next

    Sort = array

End Function

witze commented on Sun May 27 04:32:39 2007:

very interesting comparison!


Leba commented on Wed May 30 13:06:53 2007:

The big advantage of Perl is that you can write almost everything in only few lines. But after few weeks it is very hard to read. I wrote one project (using GoogleAPI) at my university, it takes 20 lines of code. But when 3 weeks later I was presenting this program to my professor, it took me some time to understand, what I have wriiten :D So…I don’t recommend so short programs :D


Warsow commented on Thu Jun 7 15:49:23 2007:

That oncemore shows that Ruby and Python is better than PHP :) thanks for one more proof. nice test


nitro commented on Wed Jun 13 15:57:33 2007:

@Warsow one task shows you which language is the best? oh no…..


Darmowa bramka sms commented on Thu Jun 14 07:28:45 2007:

Python version could be somewhat shorter.

numbers[:flipcount] = numbers[flipcount-1::-1]

I find this actually clearer than reversed()..


Wyniki na żywo commented on Sun Jun 17 05:10:54 2007:

Hello, very interesting comparison!!!


Markus commented on Tue Jun 19 03:34:41 2007:

Yes i think to that this is a vera interesting comparison.


Conti Correnti commented on Wed Jun 27 14:11:56 2007:

Good job! I like the game, found it from another post with it written in a few different languages. Yours is by far the most complete and enjoyable.

Thanks!

Jeremy


Vit commented on Sun Jul 1 16:33:14 2007:

“Ruby. For simple things at least!”

and PHP vs Ruby i think Ruby ist very " Speed” ;-)


Spiele commented on Tue Jul 3 09:59:20 2007:

Good comparison. I saw something similar but with C, C++ and Ruby. I’ll have to blog about it


jjkim commented on Wed Jul 4 04:44:52 2007:

You can save 3 more characters in Python like this.

exec"print “+numbers[1:-1]

Looks ugly but it works. :)


jjkim commented on Wed Jul 4 04:47:17 2007:

You can save 3 more characters in Python like this.

exec"print"+`numbers`[1:-1]

Looks ugly but it works. :)

Ignore my upper comment.


the spamer-hater commented on Sun Jul 8 11:10:19 2007:

BIG LOOOOOOOLLLLLLLLL @ TOMEK!!!!!

TOMEK WRITE: “Hey, a non-spam comment from Poland! Thanks for article. I don’t think that all comments from poland are spam! And not all comments from other country. It’s bigger problem people from USA buy .pl domains and spam people from DE buy .pl domains and spam … So please don’t write that people from poland spam here.”

That are the Words of the biggest SPAMER from POLAND!

TOMEK = www.blog.noclegi-lubuskie.pl = www.profesjonalna-reklama.pl = many more ……

he SPAM everywhere - if you wanna laugh just get his profesjonalna-reklama domain and look in a backlink-checker. i think there is no blog and no wiki out there without spam from him.

TOMEK: “…So please don’t write that people from poland spam here.”

LOL sorry Paul for this off-topic-post, as i read that from tomek i must write it :-) and for his great work i spend my backlink from this post for him too :-)


Thomas , Zauberer commented on Wed Jul 18 08:23:19 2007:

Hi, thanks a lot for all the useful hints and pieces of advice, kind reetings


Steve commented on Thu Jul 26 08:46:13 2007:

Don’t know if this is an active topic, but I used it as an excuse to learn Groovy. Here’s a groovy version of the app:

  list = [*0..9]
  Collections.shuffle(list, new Random())
  count = 0
  sortedList = new ArrayList(list).sort()
  while (list != sortedList) {
    print list.join(" ") + " - How many to flip: "
  flipCount = System.in.readLine().toInteger()
  list[0..flipCount-1] = list[0..flipCount-1].reverse()
  count++
  }
  println "It took you $count tries."

Paul commented on Thu Jul 26 12:17:07 2007:

Hi Steve,

This thread seems to be evergreen. Thanks for posting!


Noosa Accommodation commented on Wed Aug 8 08:03:44 2007:

Yet again proving that python and Ruby are better than PHP. Keep up the great work.


Noosa commented on Wed Aug 8 08:05:23 2007:

Yet again proving that python and Ruby are better than PHP. Keep up the great work.


Noosa commented on Sun Aug 12 22:24:43 2007:

Great game. I have now bookmarked it. thanks


Poland Spammer commented on Mon Aug 20 04:20:23 2007:

Tomek AKA Tomekg. Do a google search, you’ll see how good he spams over the net. Just wondering how many hours he spends a day for spamming.

LOL –> esw.w3.org/topic/tomekg swik.net/User:tomekg

This guy is BIG spammer!


Spammer commented on Fri Aug 24 10:43:11 2007:

Noosa - is spammer 3 comments of spam!


Paul commented on Fri Aug 24 11:27:19 2007:

Maybe I should just block comments on this post that don’t contain code.


Avi commented on Mon Aug 27 10:29:08 2007:

Tcllib needed

Make the script a little smaller from previous version by using permutations for shuffle 2nd try to make this horrible markdown look OK…

package require math
package require struct::list

set input {1 2 3 4 5 6 7 8 9}
set perms [::struct::list permutations $input]
set myarray [lindex $perms [::math::random 0 [llength $perms]] ]
for {set steps 1}  {[::struct::list equal $myarray $input]==0} {incr steps} {
    puts -nonewline "$myarray \n($steps) How Many? "
    set howmany [gets stdin]
    set myarray [concat [::struct::list reverse [lrange $myarray 0 [expr $howmany-1]]] [lrange $myarray $howmany end]]
}
puts "$myarray \nDone in [expr $steps-1] steps"

Christopher Brown commented on Sun Sep 9 12:56:10 2007:

Here’s another Common Lisp example:

(defun play (n)
  (let* ((ordered-numbers (loop for i from 1 to n collect i))
         (numbers (sort (copy-seq ordered-numbers) #'(lambda (x y) (elt '(nil 0) (random 2))))))
    (loop for steps from 0 
          do
          (format t "~{~a~^, ~} : Reverse how many? " numbers)
          (let ((how-many (read)))
            (replace numbers (nreverse (subseq numbers 0 how-many)) :start1 0 :end1 how-many))
          until (equal numbers ordered-numbers) 
          finally (format t "Done in ~a steps!" steps))))

Leon commented on Sun Sep 9 15:57:31 2007:

I made a bash version that, like the BASIC version, also takes several lines to randomize and reverse the prefix. I am a bash novice so maybe there are some built-in ways to shorten these parts. I’m almost afraid to know because I find the language so unlike what I’m used to. Here is a link because it’s 42 lines and I don’t trust my first try at Markdown to not screw it up: http://eloptoof.net/reverse.html

Some highlights:

Printing an array:

echo "${numbers[*]}"

(This also makes comparing two arrays a string compare.)

Prompting and reading a variable in one line:

read -p "Reverse how many? " rev

Array size:

n=${#numbers[@]}

I find most of the modern languages generally much easier to figure out. I am constantly checking the bash man page.


Graham J commented on Wed Sep 12 21:17:04 2007:

PHP in 5 lines ;)

for($sorted=$numbers=range(1,9), shuffle($numbers), $steps=0; $numbers!=$sorted; $steps++) { echo implode(’ ‘, $numbers)."\nReverse how many? “; array_splice($numbers, 0, $flipcount=(int)trim(fgets(STDIN)), array_reverse(array_slice($numbers,0,$flipcount))); } print “Done! That took you $steps steps.\n”;


Graham J commented on Wed Sep 12 21:18:37 2007:

PHP in 5 lines, Markdown version:

for($sorted=$numbers=range(1,9), shuffle($numbers), $steps=0; $numbers!=$sorted; $steps++) {
	echo implode(' ', $numbers)."\nReverse how many? ";
	array_splice($numbers, 0, $flipcount=(int)trim(fgets(STDIN)), array_reverse(array_slice($numbers,0,$flipcount)));
}
print "Done! That took you $steps steps.\n";

Sven commented on Mon Sep 17 16:20:28 2007:

I prefer the code in Java-Script. That works good and sure.


Kre Alkalyn commented on Wed Sep 19 20:38:49 2007:

Yes i think to that this is a very interesting comparison. Thx


Peter commented on Wed Sep 26 06:25:04 2007:

Im learning a bit of Ruby after some hard PHP Lessons. As someone said above i would, at my actual point of knowledge, prefer Ruby rather than python…


Dan commented :

Here’s a Python hack: 6 lines and 311 bytes.

import random
def guesses(numbers):
    if numbers != sorted(numbers):
        flipcount = int(raw_input("%s\nReverse how many? " % (numbers,)))
        yield 1 + sum(guesses(numbers[flipcount - 1::-1] + numbers[flipcount:]))
print "Done! that took you %d steps." % sum(guesses(random.sample(range(1, 10), 9)))

Only works in Python 2.4 and later.


Paddy3118 commented :

It seems that most implementations might be defective in that your initial randomization routines could produce a sorted list. the test on the outer while loop is on if the list is not sorted which would then fail, causing the programs to not ask for a reversal at all!

You would need to scramble the initial list of numbers until they are not sorted, then go on to the while loop.

  • Paddy.

rugs commented :

No way, I remember coding in BASIC back when I was a kid with my brother. We used to love it. I think we did some pretty cool stuff back in those days as well, and almost got a full game working or something. It was great and so easy that even kids could do it – if Ruby and Python is the same (in terms of ease) I really wonder why I haven’t actually gotten into it and seen what I can do. Heck, if I could program my own applications for my Linux system, that would super sweet!


gutscheine commented :

Hi,

i don’t think that php looks ugly. it’s just where you came from.

i started coding with C … so i’m familiar with the C-style and for me every language that doesn’t use c-style bracketc etc. looks ugly :)


Max commented :

And the winner is:

REBOL


Jeremy commented :

Here is a version in Euphoria (8 lines, 317 bytes):

include std/console.e include std/sequence.e

object steps=1, gboard={1,2,3,4,5,6,7,8,9}, board=shuffle(gboard)

while not equal(gboard, board) do board = reverse(board, 1, prompt_number(join(board+48) & “\nReverse how many? “, {1,9})) steps += 1 end while

puts(1, sprintf(“Done! That took you %d steps.”, steps))

Euphoria is at: http://openeuphoria.org


Quady Trojmiasto commented :

Heh, what a brain wash:)but the comparision is stunning, everybody good job in commitment;)


spiele commented :

Great games, by the way this was a question in the college exam, I wish i saw this page before.


Phil Conrod commented :

Below is the REVERSE game re-written in Microsoft Small Basic. It is from the New 2010 BASIC COMPUTER GAMES - SMALL BASIC EDITION which was recently republished by David H. Ahl and BIBLEBYTE BOOKS. And yes, David H. Ahl is still alive and kicking!

TextWindow.CursorLeft = 32 TextWindow.WriteLine(“REVERSE”) TextWindow.CursorLeft = 15 TextWindow.WriteLine("") TextWindow.WriteLine("") TextWindow.WriteLine("") TextWindow.WriteLine(“REVERSE – A GAME OF SKILL”) TextWindow.WriteLine("") ' *** N=NUMBER OF NUMBERS N=9 TextWindow.Write(“DO YOU WANT THE RULES? “) AD = TextWindow.Read() If AD=“NO” Then Goto LN210 EndIf Sub710() ' *** MAKE A RANDOM LIST Array[1) TO Array[N) LN210: Array1=Math.Floor((N-1)Math.GetRandomNumber(999)/1000+2) For K=2 To N LN230: Array[K]=Math.Floor(NMath.GetRandomNumber(999)/1000+1) For J=1 To K-1 If Array[K]=Array[J] Then Goto LN230 EndIf EndFor EndFor ' PRINT ORIGINAL LIST AND START GAME) TextWindow.WriteLine("") TextWindow.WriteLine(“HERE WE GO … THE LIST IS: “) T=0 Sub610() LN330: TextWindow.Write(“HOW MANY SHALL I REVERSE? “) R = TextWindow.ReadNumber() If R=0 Then Goto LN520 EndIf If R<=N Then Goto LN390 EndIf TextWindow.WriteLine(“OOPS! TOO MANY! I CAN REVERSE AT MOST “+N) Goto LN330 LN390: T=T+1 ' REVERSE R NUMBERS AND PRINT NEW LIST) For K=1 To Math.Floor(R/2) Z=Array[K] Array[K]=Array[R-K+1] Array[R-K+1]=Z EndFor Sub610() ' *** CHECK FOR A WIN For K=1 To N If Array[K]<>K Then Goto LN330 EndIf EndFor TextWindow.WriteLine(“YOU WON IT IN “+T+” MOVES!!!") TextWindow.WriteLine("") LN520: TextWindow.WriteLine("") TextWindow.Write(“TRY AGAIN (YES OR NO)? “) AD = TextWindow.Read() If AD=“YES” Then Goto LN210 EndIf TextWindow.WriteLine("") TextWindow.WriteLine(“O.K. HOPE YOU HAD FUN!!") Goto LN999 ' SUBROUTINE TO PRINT LIST) Sub Sub610 TextWindow.WriteLine("") For K=1 To N TextWindow.Write(text.Append(” “,Array[K])) EndFor TextWindow.WriteLine("") TextWindow.WriteLine("") EndSub ' SUBROUTINE TO PRINT THE RULES) Sub Sub710 TextWindow.WriteLine("") TextWindow.WriteLine(“THIS IS THE GAME OF ‘REVERSE’. TO WIN, ALL YOU HAVE”) TextWindow.WriteLine(“TO DO IS ARRANGE A LIST OF NUMBERS (1 THROUGH “+N+")") TextWindow.WriteLine(“IN NUMERICAL ORDER FROM LEFT TO RIGHT. TO MOVE, YOU”) TextWindow.WriteLine(“TELL ME HOW MANY NUMBERS (COUNTING FROM THE LEFT) TO”) TextWindow.WriteLine(“REVERSE. FOR EXAMPLE, IF THE CURRENT LIST IS:") TextWindow.WriteLine("") TextWindow.WriteLine(“2 3 4 5 1 6 7 8 9”) TextWindow.WriteLine("") TextWindow.WriteLine(“AND YOU REVERSE 4, THE RESULT WILL BE:") TextWindow.WriteLine("") TextWindow.WriteLine(“5 4 3 2 1 6 7 8 9”) TextWindow.WriteLine("") TextWindow.WriteLine(“NOW IF YOU REVERSE 5, YOU WIN!") TextWindow.WriteLine("") TextWindow.WriteLine(“1 2 3 4 5 6 7 8 9”) TextWindow.WriteLine("") TextWindow.WriteLine(“NO DOUBT YOU WILL LIKE THIS GAME, BUT”) TextWindow.WriteLine(“IF YOU WANT TO QUIT, REVERSE 0 (ZERO).") TextWindow.WriteLine("") EndSub LN999:

Source: http://computerscienceforkids.com/SmallBasicComputerGames.aspx


Fotograf Düsseldorf commented :

More traditionally the way to reverse list elements in Python is

numbers[:flipcount] = numbers[flipcount-1::-1]

for example

x=[1,2,3,4,5] i=2 x[:i] = x[i-1::-1] x [2, 1, 3, 4, 5] i=4 x[:i] = x[i-1::-1] x [4, 3, 1, 2, 5]


Web_Design Hamburg commented :

to understand good post, but not simply


paul commented :

i don’t think that php looks ugly. it’s just where you came from.


Zauberer NRW commented :

My favorite code is the Code in the Java Script. It works eccellent and very save


Nick commented :

Somehow I find myself back here five years later.

I consider myself a wiser Javascripter than I was, so I wrote it again in Javascript for fun, because there clearly are not enough Javascript implementations. I’m not even sure if this blog is still active, but in any case:

Javascript has no array shuffle, so I had to write that, and it also has no notion of array elementwise equality, so rather than writing that I just wrote an isSorted predicate function, obviating the need for a presorted goal array.

http://thelivegameshq.com/public/the-site/revgame-sync.html

Use “view source” to check it out. It’s a polyglot HTML-slash-plain-Javascript file and uses environment sniffing to enable it to work both in a browser and via Windows’ builtin JScript interpreter, which I used to test it.

It weighs in just north of a kilobyte but you could reduce that by 30% by taking away the comments and sniffing and using alert and prompt directly.

I then turned the game() function inside out to fit an async model so it could have a fancy HTML UI and also work in node.js (theoretically that is, I haven’t tested it, which is as good as saying it doesn’t):

http://thelivegameshq.com/public/the-site/revgame-async.html

About three kilobytes, but a third of that is the HTML and another third is the extended environment sniffing as well as a mock event loop because I didn’t want to drop support for WSH. :) The actual game code that’s left isn’t changed much.

Cheers.


Nick commented :

And then I notice Morris’ years-old cute little way to compare arrays: by converting to strings.

Oh well.


medaids commented :

This is working

x=[1,2,3,4,5] i=2 x[:i] = x[i-1::-1] x [2, 1, 3, 4, 5] i=4 x[:i] = x[i-1::-1] x [4, 3, 1, 2, 5]


hosplan commented :

try this one. (defun play (n) (let* ((ordered-numbers (loop for i from 1 to n collect i)) (numbers (sort (copy-seq ordered-numbers) #'(lambda (x y) (elt ‘(nil 0) (random 2)))))) (loop for steps from 0 do (format t “~{~a~^, ~} : Reverse how many? " numbers) (let ((how-many (read))) (replace numbers (nreverse (subseq numbers 0 how-many)) :start1 0 :end1 how-many)) until (equal numbers ordered-numbers) finally (format t “Done in ~a steps!” steps))))


centurion commented :

for($sorted=$numbers=range(1,9), shuffle($numbers), $steps=0;

If you use php it is easy as this

$numbers!=$sorted; $steps++) { echo implode(’ ‘, $numbers)."\nReverse how many? “; array_splice($numbers, 0, $flipcount=(int)trim(fgets(STDIN)), array_reverse(array_slice($numbers,0,$flipcount))); } print “Done! That took you $steps steps.\n”;


roman balick commented :

interesting comparison between codes and very useful codes, thanks


furni Remo commented :

Use “view source” to check it out. It’s a polyglot HTML-slash-plain-Javascript file and uses environment sniffing to enable it to work both in a browser and via Windows’ builtin JScript interpreter, which I used to test it.

It weighs in just north of a kilobyte but you could reduce that by 30% by taking away the comments and sniffing and using alert and prompt directly.

I then turned the game() function inside out to fit an async model so it could have a fancy HTML UI and also work in node.js (theoretically that is, I haven’t tested it, which is as good as saying it doesn’t):


Gett Taller commented :

Just to enter below and check.

TextWindow.CursorLeft = 32 TextWindow.WriteLine(“REVERSE”) TextWindow.CursorLeft = 15 TextWindow.WriteLine("") TextWindow.WriteLine("") TextWindow.WriteLine("") TextWindow.WriteLine(“REVERSE – A GAME OF SKILL”) TextWindow.WriteLine("") ' *** N=NUMBER OF NUMBERS


Smok Cigs commented :

Regarding the codes above it is very easy to use this one below. nclude std/console.e include std/sequence.e

object steps=1, gboard={1,2,3,4,5,6,7,8,9}, board=shuffle(gboard)

while not equal(gboard, board) do board = reverse(board, 1, prompt_number(join(board+48) & “\nReverse how many? “, {1,9})) steps += 1 end while

puts(1, sprintf(“Done! That took you %d steps.”, steps))

Share: