100 doors: Difference between revisions
Line 960:
')dnl</lang>
=={{header|Mathematica}}==
'''unoptimized 1'''
<lang mathematica>n=100;
|
Revision as of 18:07, 4 February 2010
Problem: You have 100 doors in a row that are all initially closed. You make 100 passes by the doors. The first time through, you visit every door and toggle the door (if the door is closed, you open it; if it is open, you close it). The second time you only visit every 2nd door (door #2, #4, #6, ...). The third time, every 3rd door (door #3, #6, #9, ...), etc, until you only visit the 100th door.
Question: What state are the doors in after the last pass? Which are open, which are closed? [1]
Alternate: As noted in this page's discussion page, the only doors that remain open are whose numbers are perfect squares of integers. Opening only those doors is an optimization that may also be expressed.
8086 Assembly
Ada
unoptimized <lang ada>with Ada.Text_Io; use Ada.Text_Io;
procedure Doors is type Door_State is (Closed, Open); type Door_List is array(Positive range 1..100) of Door_State; The_Doors : Door_List := (others => Closed); begin for I in 1..100 loop for J in The_Doors'range loop if J mod I = 0 then if The_Doors(J) = Closed then The_Doors(J) := Open; else The_Doors(J) := Closed; end if; end if; end loop; end loop; for I in The_Doors'range loop Put_Line(Integer'Image(I) & " is " & Door_State'Image(The_Doors(I))); end loop; end Doors;</lang>
optimized <lang ada>with Ada.Text_Io; use Ada.Text_Io;
with Ada.Numerics.Elementary_Functions; use Ada.Numerics.Elementary_Functions; procedure Doors_Optimized is Num : Float; begin for I in 1..100 loop Num := Sqrt(Float(I)); Put(Integer'Image(I) & " is "); if Float'Floor(Num) = Num then Put_Line("Opened"); else Put_Line("Closed"); end if; end loop; end Doors_Optimized;</lang>
ALGOL 68
unoptimized <lang algol68># declare some constants # INT limit = 100;
PROC doors = VOID: (
MODE DOORSTATE = BOOL; BOOL closed = FALSE; BOOL open = NOT closed; MODE DOORLIST = [limit]DOORSTATE;
DOORLIST the doors; FOR i FROM LWB the doors TO UPB the doors DO the doors[i]:=closed OD;
FOR i FROM LWB the doors TO UPB the doors DO FOR j FROM LWB the doors TO UPB the doors DO IF j MOD i = 0 THEN the doors[j] := NOT the doors[j] FI OD OD; FOR i FROM LWB the doors TO UPB the doors DO printf(($g" is "gl$,i,(the doors[i]|"opened"|"closed"))) OD
); doors;</lang> optimized <lang algol68>PROC doors optimised = ( INT limit )VOID:
FOR i TO limit DO REAL num := sqrt(i); printf(($g" is "gl$,i,(ENTIER num = num |"opened"|"closed") )) OD
doors optimised(limit)</lang>
AmigaE
<lang amigae>PROC main()
DEF t[100]: ARRAY, pass, door FOR door := 0 TO 99 DO t[door] := FALSE FOR pass := 0 TO 99 door := pass WHILE door <= 99 t[door] := Not(t[door]) door := door + pass + 1 ENDWHILE ENDFOR FOR door := 0 TO 99 DO WriteF('\d is \s\n', door+1, IF t[door] THEN 'open' ELSE 'closed')
ENDPROC</lang>
AutoHotkey
<lang autohotkey>Loop, 100
Door%A_Index% := "closed"
Loop, 100 {
x := A_Index, y := A_Index While (x <= 100) { CurrentDoor := Door%x% If CurrentDoor contains closed { Door%x% := "open" x += y } else if CurrentDoor contains open { Door%x% := "closed" x += y } }
}
Loop, 100 {
CurrentDoor := Door%A_Index% If CurrentDoor contains open Res .= "Door " A_Index " is open`n"
} MsgBox % Res</lang>
AWK
unoptimized <lang awk>BEGIN {
for(i=1; i <= 100; i++) { doors[i] = 0 # close the doors } for(i=1; i <= 100; i++) { for(j=i; j <= 100; j += i) { doors[j] = (doors[j]+1) % 2 } } for(i=1; i <= 100; i++) { print i, doors[i] ? "open" : "close" }
}</lang> optimized <lang awk>BEGIN {
for(i=1; i <= 100; i++) { doors[i] = 0 # close the doors } for(i=1; i <= 100; i++) { if ( int(sqrt(i)) == sqrt(i) ) { doors[i] = 1 } } for(i=1; i <= 100; i++) { print i, doors[i] ? "open" : "close" }
}</lang>
BASIC
unoptimized <lang qbasic>DIM doors(0 TO 99) FOR pass = 0 TO 99 FOR door = pass TO 99 STEP pass + 1 PRINT doors(door) PRINT NOT doors(door) doors(door) = NOT doors(door) NEXT door NEXT pass FOR i = 0 TO 99 PRINT "Door #"; i + 1; " is "; IF NOT doors(i) THEN PRINT "closed" ELSE PRINT "open" END IF NEXT i</lang> optimized <lang qbasic>DIM doors(0 TO 99) FOR door = 0 TO 99 IF INT(SQR(door)) = SQR(door) THEN doors(door) = -1 NEXT door FOR i = 0 TO 99 PRINT "Door #"; i + 1; " is "; IF NOT doors(i) THEN PRINT "closed" ELSE PRINT "open" END IF NEXT i</lang>
C
unoptimized <lang c>#include <stdio.h>
int main() {
char is_open[100] = { 0 }; int pass, door;
// do the 100 passes for (pass = 0; pass < 100; ++pass) for (door = pass; door < 100; door += pass+1) is_open[door] = !is_open[door];
// output the result for (door = 0; door < 100; ++door) printf("door #%d is %s.\n", door+1, (is_open[door]? "open" : "closed"));
return 0;
}</lang>
optimized This optimized version makes use of the fact that finally only the doors with square index are open, as well as the fact that .
<lang c>#include <stdio.h>
int main() {
int square = 1, increment = 3, door; for (door = 1; door <= 100; ++door) { printf("door #%d", door); if (door == square) { printf(" is open.\n"); square += increment; increment += 2; } else printf(" is closed.\n"); } return 0;
}</lang>
The following ultra-short optimized version demonstrates the flexibility of C loops, but isn't really considered good C style:
<lang c>#include <stdio.h>
int main() {
int door, square, increment; for (door = 1, square = 1, increment = 1; door <= 100; door++ == square && (square += increment += 2)) printf("door #%d is %s.\n", door, (door == square? "open" : "closed")); return 0;
}</lang>
C++
unoptimized <lang cpp>#include <iostream>
int main() {
bool is_open[100] = { false };
// do the 100 passes for (int pass = 0; pass < 100; ++pass) for (int door = pass; door < 100; door += pass+1) is_open[door] = !is_open[door];
// output the result for (int door = 0; door < 100; ++door) std::cout << "door #" << door+1 << (is_open[door]? " is open." : " is closed.") << std::endl; return 0;
}</lang>
optimized This optimized version makes use of the fact that finally only the doors with square index are open, as well as the fact that .
<lang cpp>#include <iostream>
int main() {
int square = 1, increment = 3; for (int door = 1; door <= 100; ++door) { std::cout << "door #" << door; if (door == square) { std::cout << " is open." << std::endl; square += increment; increment += 2; } else std::cout << " is closed." << std::endl; } return 0;
}</lang>
The following ultra-short optimized version demonstrates the flexibility of C++ loops, but isn't really considered good C++ style:
<lang cpp>#include <iostream>
int main() {
for (int door = 1, square = 1, increment = 1; door <= 100; door++ == square && (square += increment += 2)) std::cout << "door #" << door << (door == square? " is open." : " is closed.") << std::endl; return 0;
}</lang>
C#
Unoptimized <lang csharp>using System; class Program {
static void Main() { //To simplify door numbers, uses indexes 1 to 100 (rather than 0 to 99) bool[] doors = new bool[101]; for (int pass = 1; pass <= 100; pass++) for (int current = pass; current <= 100; current += pass) doors[current] = !doors[current]; for (int i = 1; i <= 100; i++) Console.WriteLine("Door #{0} " + (doors[i] ? "Open" : "Closed"), i); }
}</lang> Optimized <lang csharp>using System; class Program {
static void Main() { int door = 1, inrementer = 0; for (int current = 1; current <= 100; current++) { Console.Write("Door #{0} ", current); if (current == door) { Console.WriteLine("Open"); inrementer++; door += 2 * inrementer + 1; } else Console.WriteLine("Closed"); } }
}</lang>
Common Lisp
Unoptimized / functional This is a very unoptimized version of the problem, using recursion and quite considerable list-copying. It emphatises the functional way of solving this problem
<lang lisp>(defun visit-door (doors doornum value1 value2)
"visits a door, swapping the value1 to value2 or vice-versa" (let ((d (copy-list doors)) (n (- doornum 1))) (if (eq (nth n d) value1) (setf (nth n d) value2) (setf (nth n d) value1)) d))
(defun visit-every (doors num iter value1 value2)
"visits every 'num' door in the list" (if (> (* iter num) (length doors)) doors (visit-every (visit-door doors (* num iter) value1 value2) num (+ 1 iter) value1 value2)))
(defun do-all-visits (doors cnt value1 value2)
"Visits all doors changing the values accordingly" (if (< cnt 1) doors (do-all-visits (visit-every doors cnt 1 value1 value2) (- cnt 1) value1 value2)))
(defun print-doors (doors)
"Pretty prints the doors list" (format T "~{~A ~A ~A ~A ~A ~A ~A ~A ~A ~A~%~}~%" doors))
(defun start (&optional (size 100))
"Start the program" (let* ((open "_") (shut "#") (doors (make-list size :initial-element shut))) (print-doors (do-all-visits doors size open shut))))</lang>
Optimized This is an optimized version of the above, using the perfect square algorithm (Note: This is non-functional as the state of the doors variable gets modified by a function call)
<lang lisp>(defun perfect-square-list (n)
"Generates a list of perfect squares from 0 up to n" (loop for i from 1 to (sqrt n) collect (expt i 2)))
(defun open-door (doors num open)
"Sets door at num to open" (setf (nth (- num 1) doors) open) doors)
(defun visit-all (doors vlist open)
"Visits and opens all the doors indicated in vlist" (if (null vlist) doors (visit-all (open-door doors (car vlist) open) (cdr vlist) open)))
(defun start2 (&optional (size 100))
"Start the program" (print-doors (visit-all (make-list size :initial-element "#") (perfect-square-list size) "_")))</lang>
Optimized (2) This version displays a much more functional solution through the use of (mapcar ...)
<lang lisp>(let ((i 0))
(mapcar (lambda (x) (if (zerop (mod (sqrt (incf i)) 1)) "_" x)) (make-list 100 :initial-element "#")))</lang>
Clojure
Unoptimized / mutable array <lang clojure>(defn doors []
(let [doors (into-array (repeat 100 false))] (doseq [pass (range 1 101) i (range (dec pass) 100 pass) :while (< i 100)] (aset doors i (not (aget doors i)))) doors))
(defn open-doors [] (for [[d n] (map vector (doors) (iterate inc 1)) :when d] n))
(defn print-open-doors []
(println "Open doors after 100 passes:" (apply str (interpose ", " (open-doors)))))</lang>
Unoptimized / functional <lang clojure>(defn doors []
(reduce (fn [doors toggle-idx] (update-in doors [toggle-idx] not)) (into [] (repeat 100 false)) (for [pass (range 1 101) i (range (dec pass) 100 pass) :while (< i 100)] i)))
(defn open-doors [] (for [[d n] (map vector (doors) (iterate inc 1)) :when d] n))
(defn print-open-doors []
(println "Open doors after 100 passes:" (apply str (interpose ", " (open-doors)))))</lang>
Optimized / functional <lang clojure>(defn doors [] (reduce (fn [doors idx] (assoc doors idx true)) (into [] (repeat 100 false)) (map #(dec (* % %)) (range 1 11))))
(defn open-doors [] (for [[d n] (map vector (doors) (iterate inc 1)) :when d] n))
(defn print-open-doors []
(println "Open doors after 100 passes:" (apply str (interpose ", " (open-doors)))))</lang>
D
<lang d>module l00door ; import std.stdio ;
alias char[] DOOR ; // or alias bool[] DOOR const char OPEN = 'O' ; // then OPEN = true const char CLOSE = 'x' ; // CLOSE = false</lang> unoptimized <lang d>DOOR flip_u(inout DOOR d) {
d[] = CLOSE ; for(int i= 0 ; i < d.length ; i++) for(int j = i ; j < d.length ; j += i + 1) if (d[j] == OPEN) d[j] = CLOSE ; else d[j] = OPEN ; return d ;
}</lang> optimized <lang d>DOOR flip_o(inout DOOR d) {
d[] = CLOSE ; for(int i= 1 ; i*i <= d.length ; i++) d[i*i-1] = OPEN ; return d ;
}</lang> test program: <lang d>void main() {
DOOR d ; d.length = 100 ; writefln(d.flip_u()) ; writefln(d.flip_o()) ;
}</lang>
E
Graphical
This version animates the changes of the doors (as checkboxes).
<lang e>#!/usr/bin/env rune
var toggles := [] var gets := []
- Set up GUI (and data model)
def frame := <swing:makeJFrame>("100 doors") frame.getContentPane().setLayout(<awt:makeGridLayout>(10, 10)) for i in 1..100 {
def component := <import:javax.swing.makeJCheckBox>(E.toString(i)) toggles with= fn { component.setSelected(!component.isSelected()) } gets with= fn { component.isSelected() } frame.getContentPane().add(component)
}
- Set up termination condition
def done frame.addWindowListener(def _ {
to windowClosing(event) { bind done := true } match _ {}
})
- Open and close doors
def loop(step, i) {
toggles[i] <- () def next := i + step timer.whenPast(timer.now() + 10, fn { if (next >= 100) { if (step >= 100) { # Done. } else { loop <- (step + 1, step) } } else { loop <- (step, i + step) } })
} loop(1, 0)
frame.pack() frame.show() interp.waitAtTop(done)</lang>
Erlang
optimized <lang erlang>doors() ->
F = fun(X) -> Root = math:pow(X,0.5), Root == trunc(Root) end, Out = fun(X, true) -> io:format("Door ~p: open~n",[X]); (X, false)-> io:format("Door ~p: close~n",[X]) end, [Out(X,F(X)) || X <- lists:seq(1,100)].</lang>
Factor
<lang Factor>USING: bit-arrays formatting fry kernel math math.ranges sequences ; IN: rosetta.doors
CONSTANT: number-of-doors 100
- multiples ( n -- range )
0 number-of-doors rot <range> ;
- toggle-multiples ( n doors -- )
[ multiples ] dip '[ _ [ not ] change-nth ] each ;
- toggle-all-multiples ( doors -- )
[ number-of-doors [1,b] ] dip '[ _ toggle-multiples ] each ;
- print-doors ( doors -- )
[ swap "open" "closed" ? "Door %d is %s\n" printf ] each-index ;
- main ( -- )
number-of-doors 1 + <bit-array> [ toggle-all-multiples ] [ print-doors ] bi ;</lang>
Falcon
Unoptimized code <lang falcon>doors = arrayBuffer( 101, false )
for pass in [ 0 : doors.len() ]
for door in [ 0 : doors.len() : pass+1 ] doors[ door ] = not doors[ door ] end
end
for door in [ 1 : doors.len() ] // Show Output
> "Door ", $door, " is: ", ( doors[ door ] ) ? "open" : "closed"
end </lang> Optimized code <lang falcon> for door in [ 1 : 101 ]: > "Door ", $door, " is: ", fract( door ** 0.5 ) ? "closed" : "open"</lang>
Forth
The problem with unfactored code is it's difficult to follow. The included example works, but to comprehend the code, you're mentally juggling items on the return stack (e.g., i, j) as well as items on the data stack, plus whatever is in dictionary space. Since people can only keep seven things in his or her mind, plus or minus two, this quickly becomes an intellectual burden. This style of coding typifies Forth software development in the mid-70s and -80s, which resulted in Forth's undeserved "write-only language" reputation.
The well-factored code works much better from a readability point of view (assuming familiarity with Forth's coding conventions), but without the aid of an optimizing compiler, can suffer from slower execution performance and somewhat larger memory consumption.
Of course, this size/speed tradeoff appears in many languages, not just Forth.
Factored <lang forth>100 constant /doors create 'doors
/doors allot
'doors /doors + constant <doors
- toggle 1 over c@ xor swap c! ;
- pass dup 1- 'doors + begin dup <doors < while dup toggle over + repeat 2drop ;
- passes /doors 1 begin 2dup >= while dup pass 1+ repeat 2drop ;
- .closed over c@ if over 'doors - 1+ . then ;
- report 'doors /doors begin dup while .closed 1 /string repeat cr 2drop ;
- open 'doors /doors erase ;
- doors open passes report ;</lang>
Unfactored <lang forth>: doors ( n -- )
here over erase \ open all doors dup 0 do here over + here i + do i c@ 1 xor i c! \ toggle j 1+ +loop loop ." Closed doors: " ( n ) 0 do here i + c@ if i 1+ . then loop cr ;
100 doors</lang>
Optimized <lang forth>: SQUARED DUP * ;
- DOORS 1 BEGIN 2DUP SQUARED >= WHILE DUP SQUARED . 1+ REPEAT 2DROP ;
100 DOORS</lang>
Fortran
unoptimized <lang fortran>PROGRAM DOORS
INTEGER, PARAMETER :: n = 100 ! Number of doors INTEGER :: i, j LOGICAL :: door(n) = .TRUE. ! Initially closed DO i = 1, n DO j = i, n, i door(j) = .NOT. door(j) END DO END DO
DO i = 1, n WRITE(*,"(A,I3,A)", ADVANCE="NO") "Door ", i, " is " IF (door(i)) THEN WRITE(*,"(A)") "closed" ELSE WRITE(*,"(A)") "open" END IF END DO
END PROGRAM DOORS</lang>
optimized <lang fortran>PROGRAM DOORS
INTEGER, PARAMETER :: n = 100 ! Number of doors INTEGER :: i LOGICAL :: door(n) = .TRUE. ! Initially closed DO i = 1, SQRT(REAL(n)) door(i*i) = .FALSE. END DO DO i = 1, n WRITE(*,"(A,I3,A)", ADVANCE="NO") "Door ", i, " is " IF (door(i)) THEN WRITE(*,"(A)") "closed" ELSE WRITE(*,"(A)") "open" END IF END DO
END PROGRAM DOORS</lang>
F#
Requires #light in versions of F# prior to 2010 beta. <lang fsharp>let answerDoors =
let ToggleNth n (lst:bool array) = // Toggle every n'th door [(n-1) .. n .. 99] // For each appropriate door |> Seq.iter (fun i -> lst.[i] <- not lst.[i]) // toggle it let doors = Array.create 100 false // Initialize all doors to closed Seq.iter (fun n -> ToggleNth n doors) [1..100] // toggle the appropriate doors for each pass doors // Initialize all doors to closed
</lang> Following is the solution using perfect squares. The coercions in PerfectSquare are, I believe, slightly different in versions prior to 2010 beta and, again, #light is required in those versions. <lang fsharp>open System let answer2 =
let PerfectSquare n = let sqrt = int(Math.Sqrt(float n)) n = sqrt * sqrt [| for i in 1..100 do yield PerfectSquare i |]</lang>
Go
unoptimized <lang go>package main
import ( . "fmt"; )
func main() { doors := make([]bool, 100);
for pass := 0; pass <= 100; pass++ { for door := pass; door < 100; door += pass + 1 { doors[door] = !doors[door] } }
for i, v := range doors { if v { Printf("1") } else { Printf("0") }
if i%10 == 9 { Printf("\n") } else { Printf(" ") }
} }</lang>
Groovy
unoptimized <lang groovy>doors = [false] * 100 (0..99).each {
it.step(100, it + 1) { doors[it] ^= true }
} (0..99).each {
println("Door #${it + 1} is ${doors[it] ? 'open' : 'closed'}.")
}</lang>
optimized a Using square roots
<lang groovy>(1..100).each {
println("Door #${it} is ${Math.sqrt(it).with{it==(int)it} ? 'open' : 'closed'}.")
}</lang>
optimized b Without using square roots <lang groovy>doors = ['closed'] * 100 (1..10).each { doors[it**2 - 1] = 'open' } (0..99).each {
println("Door #${it + 1} is ${doors[it]}.")
}</lang>
Haskell
unoptimized <lang haskell>data Door = Open | Closed deriving Show
toggle Open = Closed toggle Closed = Open
pass k = zipWith ($) (cycle $ replicate k id ++ [toggle])
run n = foldl (flip pass) (replicate n Closed) [0..n]</lang>
optimized (without using square roots) <lang haskell>gate :: Eq a => [a] -> [a] -> [Door] gate (x:xs) (y:ys) | x == y = Open : gate xs ys gate (x:xs) ys = Closed : gate xs ys gate [] _ = []
run n = gate [1..n] [k*k | k <- [1..]]</lang>
alternatively, returning a list of all open gates, it's a one-liner:
<lang haskell>run n = takeWhile (< n) [k*k | k <- [1..]]</lang>
haXe
<lang haxe>class RosettaDemo {
static public function main() { findOpenLockers(100); }
static function findOpenLockers(n : Int) { var i = 1;
while((i*i) <= n) { neko.Lib.print(i*i + "\n"); i++; } }
}</lang>
J
unoptimized <lang j> ~:/ (100 $ - {. 1:)"0 >:i.100 1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 ...</lang> optimized <lang j> (>:i.100) e. *: i.11 1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 ...
1 (<:*:i.10)} 100$0 NB. alternative
1 0 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 ...</lang>
Java
unoptimized <lang java>public class Doors { public static void main(String[] args) { boolean[] doors = new boolean[100]; for(int pass = 0; pass < 100; pass++){ for(int door = pass; door < 100; door += pass + 1){ doors[door] = !doors[door]; } } for(int i = 0; i < 100; i++){ System.out.println("Door #" + (i + 1) + " is " + (doors[i] ? "open." : "closed.")); } } }</lang>
optimized <lang java>public class Doors { public static void main(String[] args) { boolean[] doors = new boolean[100]; for(int pass = 0; pass < 10; pass++){ doors[(pass + 1) * (pass + 1) - 1] = true; } for(int i = 0; i < 100; i++){ System.out.println("Door #" + (i + 1) + " is " + (doors[i] ? "open." : "closed.")); } } }</lang>
JavaScript
for the print()
statement.
<lang javascript>var CLOSED = 0; var OPEN = 1; var n = 100; var doors = new Array(n);
// initialize doors for (var i = 0; i < n; i++)
doors[i] = CLOSED;
// now, start opening and closing for (var step = 1; step < n; step ++)
for (var idx = step; idx < n; idx += step) // toggle state of door doors[idx] = (doors[idx] == OPEN ? CLOSED : OPEN)
// find out which doors are open for (i = 0; i < n; i++)
if (doors[i] == OPEN) print("door " + i + " is open.");</lang>
outputs
door 1 is open. door 4 is open. door 9 is open. door 16 is open. door 25 is open. door 36 is open. door 49 is open. door 64 is open. door 81 is open.
Using features of JavaScript 1.6, this
<lang javascript>var n = 100; var doors = new Array(n); doors.forEach(function(val, idx, ary) {ary[idx] = 0});
// now, start opening and closing for (var step = 1; step < n; step ++)
for (var idx = step; idx < n; idx += step) // toggle state of door doors[idx] = !doors[idx];
// find out which doors are open var open = doors.reduce(function(open, val, idx) {if (val) open.push(idx); return open}, []) print("these doors are open: " + open.join(','));</lang> outputs
these doors are open: 1,4,9,16,25,36,49,64,81
Logo
<lang Logo>to doors
- Problem 100 Doors
- FMSLogo
make "door (vector 100 1) for [p 1 100][setitem :p :door 0]
for [a 1 100 1][for [b :a 100 :a][make "x item :b :door ifelse :x = 0 [setitem :b :door 1][setitem :b :door 0] ] ]
for [c 1 100][make "y item :c :door ifelse :y = 0 [pr (list :c "Close)] [pr (list :c "Open)] ] end</lang>
Lua
<lang lua>is_open = {}
for door = 1,100 do is_open[door] = false end
for pass = 1,100 do
for door = pass,100,pass do is_open[door] = not is_open[door] end
end
for i,v in next,is_open do
if v then print ('Door '..i..':','open') else print ('Door '..i..':', 'close') end
end</lang>
M4
<lang m4>define(`_set', `define(`$1[$2]', `$3')')dnl define(`_get', `defn(`$1[$2]')')dnl define(`for',`ifelse($#,0,``$0,`ifelse(eval($2<=$3),1, `pushdef(`$1',$2)$5`'popdef(`$1')$0(`$1',eval($2+$4),$3,$4,`$5')')')')dnl define(`opposite',`_set(`door',$1,ifelse(_get(`door',$1),`closed',`open',`closed'))')dnl define(`upper',`100')dnl for(`x',`1',upper,`1',`_set(`door',x,`closed')')dnl for(`x',`1',upper,`1',`for(`y',x,upper,x,`opposite(y)')')dnl for(`x',`1',upper,`1',`door x is _get(`door',x) ')dnl</lang>
Mathematica
unoptimized 1 <lang mathematica>n=100; tmp=ConstantArray[-1,n]; Do[tmpi;;;;i*=-1;,{i,n}]; Do[Print["door ",i," is ",If[tmpi==-1,"closed","open"]],{i,1,Length[tmp]}]</lang>
optimized 1 <lang mathematica>Do[Print["door ",i," is ",If[IntegerQ[Sqrt[i]],"open","closed"]],{i,100}]</lang>
optimized 2 <lang mathematica>n=100; a=Range[1,Sqrt[n]]^2 Do[Print["door ",i," is ",If[MemberQ[a,i],"open","closed"]],{i,100}]</lang>
optimized 3 <lang mathematica>n=100 nn=1 a=0 For[i=1,i<=n,i++,
If[i==nn, Print["door ",i," is open"]; a++; nn+=2a+1; , Print["door ",i," is closed"]; ];
]</lang>
These will only give the indices for the open doors: unoptimized 2 <lang mathematica>Pick[Range[100], Xor@@@Array[Divisible[#1,#2]&, {100,100}]]</lang>
optimized 4 <lang mathematica>Range[Sqrt[100]]^2</lang>
MAXScript
unoptimized <lang maxscript>doorsOpen = for i in 1 to 100 collect false
for pass in 1 to 100 do (
for door in pass to 100 by pass do ( doorsOpen[door] = not doorsOpen[door] )
)
for i in 1 to doorsOpen.count do (
format ("Door % is open?: %\n") i doorsOpen[i]
)</lang> optimized <lang maxscript>for i in 1 to 100 do (
root = pow i 0.5 format ("Door % is open?: %\n") i (root == (root as integer))
)</lang>
Metafont
<lang metafont>boolean doors[]; for i = 1 upto 100: doors[i] := false; endfor for i = 1 upto 100:
for j = 1 step i until 100: doors[j] := not doors[j]; endfor
endfor for i = 1 upto 100:
message decimal(i) & " " & if doors[i]: "open" else: "close" fi;
endfor end</lang>
MMIX
See 100 doors/MMIX
Modula-3
unoptimized <lang modula3>MODULE Doors EXPORTS Main;
IMPORT IO, Fmt;
TYPE State = {Closed, Open}; TYPE List = ARRAY [1..100] OF State;
VAR doors := List{State.Closed, ..};
BEGIN
FOR i := 1 TO 100 DO FOR j := FIRST(doors) TO LAST(doors) DO IF j MOD i = 0 THEN IF doors[j] = State.Closed THEN doors[j] := State.Open; ELSE doors[j] := State.Closed; END; END; END; END;
FOR i := FIRST(doors) TO LAST(doors) DO IO.Put(Fmt.Int(i) & " is "); IF doors[i] = State.Closed THEN IO.Put("Closed.\n"); ELSE IO.Put("Open.\n"); END; END;
END Doors.</lang>
optimized
<lang modula3>MODULE DoorsOpt EXPORTS Main;
IMPORT IO, Fmt;
TYPE State = {Closed, Open}; TYPE List = ARRAY [1..100] OF State;
VAR doors := List{State.Closed, ..};
BEGIN
FOR i := 1 TO 10 DO doors[i * i] := State.Open; END;
FOR i := FIRST(doors) TO LAST(doors) DO IO.Put(Fmt.Int(i) & " is "); IF doors[i] = State.Closed THEN IO.Put("Closed.\n"); ELSE IO.Put("Open.\n"); END; END;
END DoorsOpt.</lang>
MOO
<lang moo>is_open = make(100); for pass in [1..100]
for door in [pass..100] if (door % pass) continue; endif is_open[door] = !is_open[door]; endfor
endfor
"output the result"; for door in [1..100]
player:tell("door #", door, " is ", (is_open[door] ? "open" : "closed"), ".");
endfor</lang>
OCaml
unoptimized <lang ocaml>let max_doors = 100
let show_doors =
Array.iteri (fun i x -> Printf.printf "Door %d is %s\n" (i+1) (if x then "open" else "closed"))
let flip_doors doors =
for i = 1 to max_doors do let rec flip idx = if idx < max_doors then begin doors.(idx) <- not doors.(idx); flip (idx + i) end in flip (i - 1) done; doors
let () =
show_doors (flip_doors (Array.make max_doors false))</lang>
optimized <lang ocaml>let optimised_flip_doors doors =
for i = 1 to int_of_float (sqrt (float_of_int max_doors)) do doors.(i*i - 1) <- true done; doors
let () =
show_doors (optimised_flip_doors (Array.make max_doors false))</lang>
Octave
<lang octave>doors = false(100,1); for i = 1:100
for j = i:i:100 doors(j) = !doors(j); endfor
endfor for i = 1:100
if ( doors(i) ) s = "open"; else s = "closed"; endif printf("%d %s\n", i, s);
endfor</lang>
Oz
<lang oz>declare
NumDoors = 100 NumPasses = 100
fun {NewDoor} closed end
fun {Toggle Door} case Door of closed then open [] open then closed end end
fun {Pass Doors I} {List.mapInd Doors fun {$ Index Door} if Index mod I == 0 then {Toggle Door} else Door end end} end Doors0 = {MakeList NumDoors} {ForAll Doors0 NewDoor}
DoorsN = {FoldL {List.number 1 NumPasses 1} Pass Doors0}
in
%% print open doors {List.forAllInd DoorsN proc {$ Index Door} if Door == open then
{System.showInfo "Door "#Index#" is open."}
end end }</lang>
Output:
Door 1 is open. Door 4 is open. Door 9 is open. Door 16 is open. Door 25 is open. Door 36 is open. Door 49 is open. Door 64 is open. Door 81 is open. Door 100 is open.
Pascal
<lang pascal>Program OneHundredDoors;
var
doors : Array[1..100] of Boolean; i, j : Integer;
begin
for i := 1 to 100 do doors[i] := False; for i := 1 to 100 do begin j := i; while j <= 100 do begin
doors[j] := not doors[j]; j := j + i
end end; for i := 1 to 100 do begin Write(i, ' '); if doors[i] then
WriteLn('open')
else
WriteLn('closed');
end
end.</lang>
PHP
optimized <lang php><?php for ($i = 1; $i <= 100; $i++) { $root = sqrt($i); $state = ($root == ceil($root)) ? "open" : "closed"; echo "Door $i: $state"; } ?></lang>
Perl
unoptimized
<lang perl>my @doors; for my $pass (1 .. 100) {
for (1 .. 100) { if (0 == $_ % $pass) { $doors[$_] = not $doors[$_]; }; };
};
print "Door $_ is", $doors[$_] ? "open" : "closed", "\n" for 1 .. 100;</lang>
optimized
<lang perl>print "Door $_ is ", qw"closed open"[int sqrt == sqrt], "\n" for 1..100;</lang> <lang perl>while( ++$i <= 100 ) {
$root = sqrt($i); if ( int( $root ) == $root ) { print "Door $i is open\n"; } else { print "Door $i is closed\n"; }
}</lang>
Perl 6
unoptimized
<lang perl6>sub doors (Int $doors) {
my @doors = False xx $doors; ($_ = !$_ for @doors[$_ - 1 ... { $^x + $_ }, $doors - 1]) for 1 .. $doors;
say "Door { .key + 1 } is { <closed open>[.value] }." for pairs @doors;
}
doors 100;</lang>
optimized
<lang perl6>sub doors (Int $doors) {
my @squares = map * ** 2, 1 .. sqrt $doors;
for @squares Z @squares[1 .. @squares.end], $doors + 1 -> $a, $b { say "Door $a is open."; say "Door $_ is closed." for $a ^..^ $b; }
}
doors 100;</lang>
Pop11
unoptimized <lang pop11>lvars i; lvars doors = {% for i from 1 to 100 do false endfor %}; for i from 1 to 100 do
for j from i by i to 100 do not(doors(j)) -> doors(j); endfor;
endfor;
- Print state
for i from 1 to 100 do
printf('Door ' >< i >< ' is ' >< if doors(i) then 'open' else 'closed' endif, '%s\n');
endfor;</lang>
optimized <lang pop11>for i to 100 do
lvars root = sqrt(i); i; if root = round(root) then ' open' ><; else ' closed' ><; endif; =>
endfor;</lang>
PowerShell
unoptimized <lang powershell>$doors = @(0..99) for($i=0; $i -lt 100; $i++) {
$doors[$i] = 0 # start with all doors closed
} for($i=0; $i -lt 100; $i++) {
$step = $i + 1 for($j=$i; $j -lt 100; $j = $j + $step) { $doors[$j] = ($doors[$j] + 1) % 2 }
} foreach($doornum in 1..100) {
if($doors[($doornum-1)] -eq $true) {"$doornum open"} else {"$doornum closed"}
}</lang>
Python
unoptimized <lang python>close = 0 open = 1 doors = [close] * 100
for i in range(100):
for j in range(i, 100, i+1): doors[j] = open if doors[j] is close else close print "Door %d:" % (i+1), 'open' if doors[i] else 'close'
for k, door in enumerate(doors):
print "Door %d:" % (k+1), 'open' if door else 'close'</lang>
optimized
A version that only visits each door once:
<lang python>for i in xrange(1, 101):
root = i ** 0.5 print "Door %d:" % i, 'open' if root == int(root) else 'close'</lang>
Q
unoptimized <lang q>`closed`open mod[;2]count each 0_group raze where each 0=t mod\:/:t:til 101</lang>
R
unoptimized <lang r>doors_puzzle <- function(ndoors=100,passes=100) {
doors <- rep(FALSE,ndoors) for (ii in seq(1,passes)) { mask <- seq(0,ndoors,ii) doors[mask] <- !doors[mask] } return (which(doors == TRUE))
}
doors_puzzle()</lang>
optimized <lang r>## optimized version... we only have to to up to the square root of 100 seq(1,sqrt(100))**2</lang>
REBOL
<lang rebol>doors: array/initial 100 'open forskip doors 2 [ change next doors 'closed ] if error? try [
forskip doors 3 [ state: third doors poke doors 3 either state = 'open [ 'closed ] [ 'open ] ]
] [ doors: head doors ]</lang>
Ruby
unoptimized <lang ruby>n = 100 Open = "open" Closed = "closed" def Open.f
Closed
end def Closed.f
Open
end doors = [Closed] * (n+1) for mul in 1..n
for x in 1..n doors[mul*x] = (doors[mul*x] || break).f end
end doors.each_with_index {
|b, i| puts "Door #{i} is #{b}" if i>0
}</lang>
optimized <lang ruby>n = 100 doors = ["closed"] * (n+1) for x in 1..n
doors[x**2] = (doors[x**2] || break) && "open"
end doors.each_with_index {
|b, i| puts "Door #{i} is #{b}" if i>0
}</lang>
SAS
<lang sas>data _null_;
open=1; close=0; array Door{100}; do Pass = 1 to 100; do Current = 1 to 100 by Pass; if Door{Current} ne open then Door{Current} = open; else Door{Current} = close; end; end; NumberOfOpenDoors = sum(of Door{*}); put "Number of Open Doors: " NumberOfOpenDoors;
run;</lang>
Scala
Both optimized and non-optimized versions follow. Both are fully functional.
<lang scala>object HundredDoors {
sealed abstract class DoorState { def toggle: DoorState } case object Opened extends DoorState { def toggle = Closed } case object Closed extends DoorState { def toggle = Opened }
case class Door(number: Int, state: DoorState = Closed) { override def toString = "Door "+number+" is "+state
def toggle = this.copy(state = state.toggle) }
def unoptimized { val doors = 1 to 100 map (Door(_)) (1 to 100).foldLeft(doors)((doors, pass) => doors map (door => if (door.number % pass == 0) door.toggle else door ) ) foreach println }
def optimized { val openedDoorNumbers = Set(1 to 10 map (n => n * n): _*) 1 to 100 map (n => if (openedDoorNumbers contains n) Door(n, Opened) else Door(n)) foreach println }
}</lang>
Scheme
unoptimized <lang scheme>(define *max-doors* 100)
(define (show-doors doors)
(let door ((i 0) (l (vector-length doors))) (cond ((= i l) (newline)) (else (printf "~nDoor ~a is ~a" (+ i 1) (if (vector-ref doors i) "open" "closed")) (door (+ i 1) l)))))
(define (flip-doors doors)
(define (flip-all i) (cond ((> i *max-doors*) doors) (else (let flip ((idx (- i 1))) (cond ((>= idx *max-doors*) (flip-all (+ i 1))) (else (vector-set! doors idx (not (vector-ref doors idx))) (flip (+ idx i)))))))) (flip-all 1))
(show-doors (flip-doors (make-vector *max-doors* #f)))</lang>
optimized <lang scheme>(define (optimised-flip-doors doors)
(define (flip-all i) (cond ((> i (floor (sqrt *max-doors*))) doors) (else (vector-set! doors (- (* i i) 1) #t) (flip-all (+ i 1))))) (flip-all 1))
(show-doors (optimised-flip-doors (make-vector *max-doors* #f)))</lang>
Slate
Unoptimized <lang slate>define: #a -> (Array newSize: 100). a infect: [| :_ | False].
a keysDo: [| :pass |
pass to: a indexLast by: pass do: [| :door | a at: door infect: #not `er]].
a keysAndValuesDo: [| :door :isOpen |
inform: 'door #' ; door ; ' is ' ; (isOpen ifTrue: ['open'] ifFalse: ['closed'])].</lang>
Optimized <lang slate>define: #a -> (Array newSize: 100). a infect: [| :_ | False].
0 below: 10 do: [| :door | a at: door squared put: True]. a keysAndValuesDo: [| :door :isOpen |
inform: 'door #' ; door ; ' is ' ; (isOpen ifTrue: ['open'] ifFalse: ['closed'])].</lang>
Smalltalk
Unoptimized <lang smalltalk>|a| a := Array new: 100 . 1 to: 100 do: [ :i | a at: i put: false ].
1 to: 100 do: [ :pass |
pass to: 100 by: pass do: [ :door | a at: door put: (a at: door) not . ]
].
"output" 1 to: 100 do: [ :door |
( 'door #%1 is %2' % { door . (a at: door) ifTrue: [ 'open' ] ifFalse: [ 'closed' ] } ) displayNl
]</lang> Optimized
<lang smalltalk>|a| a := (1 to: 100) collect: [ :x | false ]. 1 to: 10 do: [ :i | a at: (i squared) put: true ]. 1 to: 100 do: [ :i |
( 'door #%1 is %2' % { i . (a at: i) ifTrue: [ 'open' ] ifFalse: [ 'closed' ] } ) displayNl
]</lang>
SETL
Unoptimized <lang setl>program hundred_doors;
const toggle := {['open', 'closed'], ['closed', 'open']};
doorStates := ['closed'] * 100;
(for interval in [1..100])
doorStates := [if i mod interval = 0 then toggle(prevState) else prevState end: prevState = doorStates(i)];
end;
(for finalState = doorStates(i))
print('door', i, 'is', finalState);
end;
end program;</lang> If 'open' weren't a reserved word, we could omit the single quotes around it.
Optimized Exploits the fact that squares are separated by successive odd numbers. Use array replication to insert the correct number of closed doors in between the open ones. <lang setl>program hundred_doors;
doorStates := (+/ [['closed'] * oddNum with 'open': oddNum in [1,3..17]]);
(for finalState = doorStates(i))
print('door', i, 'is', finalState);
end;
end program;</lang>
Tcl
unoptimized
<lang tcl>package require Tcl 8.5 set n 100 set doors [concat - [lrepeat $n 0]] for {set step 1} {$step <= $n} {incr step} {
for {set i $step} {$i <= $n} {incr i $step} { lset doors $i [expr { ! [lindex $doors $i]}] }
} for {set i 1} {$i <= $n} {incr i} {
puts [format "door %d is %s" $i [expr {[lindex $doors $i] ? "open" : "closed"}]]
}</lang>
optimized
<lang tcl>package require Tcl 8.5 set doors [lrepeat [expr {$n + 1}] closed] for {set i 1} {$i <= sqrt($n)} {incr i} {
lset doors [expr {$i ** 2}] open
} for {set i 1} {$i <= $n} {incr i} {
puts [format "door %d is %s" $i [lindex $doors $i]]
}</lang>
graphical
Inspired by the E solution, here's a visual representation <lang tcl>package require Tcl 8.5 package require Tk
array set door_status {}
- create the gui
set doors [list x] for {set i 0} {$i < 10} {incr i} {
for {set j 0} {$j < 10} {incr j} { set k [expr {1 + $j + 10*$i}] lappend doors [radiobutton .d_$k -text $k -variable door_status($k) \ -indicatoron no -offrelief flat -width 3 -value open] grid [lindex $doors $k] -column $j -row $i }
}
- create the controls
button .start -command go -text Start label .i_label -text " door:" entry .i -textvariable i -width 4 label .step_label -text " step:" entry .step -textvariable step -width 4 grid .start - .i_label - .i - .step_label - .step - -row $i grid configure .start -sticky ew grid configure .i_label .step_label -sticky e grid configure .i .step -sticky w
proc go {} {
global doors door_status i step
# initialize the door_status (all closed) for {set d 1} {$d <= 100} {incr d} { set door_status($d) closed } # now, begin opening and closing for {set step 1} {$step <= 100} {incr step} { for {set i 1} {$i <= 100} {incr i} { if {$i % $step == 0} { [lindex $doors $i] [expr {$door_status($i) eq "open" ? "deselect" : "select"}] update after 50 } } }
}</lang>
TI-89 BASIC
<lang ti89b>Define doors(fast) = Func
Local doors,i,j seq(false,x,1,100) → doors If fast Then For i,1,10,1 true → doors[i^2] EndFor Else For i,1,100,1 For j,i,100,i not doors[j] → doors[j] EndFor EndFor EndIf Return doors
EndFunc</lang>
UNIX Shell
<lang bash>#! /bin/bash
declare -a doors for((i=1; i <= 100; i++)); do
doors[$i]=0
done
for((i=1; i <= 100; i++)); do
for((j=i; j <= 100; j += i)); do
echo $i $j doors[$j]=$(( doors[j] ^ 1 ))
done
done
for((i=1; i <= 100; i++)); do
if [[ ${doors[$i]} -eq 0 ]]; then
op="closed"
else
op="open"
fi echo $i $op
done</lang>
Vedit macro language
Unoptimized
This implementation uses a free edit buffer as data array and for displaying the results.
A closed door is represented by a character '-' and an open door by character 'O'.
<lang vedit>Buf_Switch(Buf_Free)
Ins_Char('-', COUNT, 100) // All doors closed
for (#1 = 1; #1 <= 100; #1++) {
for (#2 = #1; #2 <= 100; #2 += #1) { Goto_Col(#2) Ins_Char((Cur_Char^0x62), OVERWRITE) // Toggle between '-' and 'O' }
}</lang>
Optimized <lang vedit>Buf_Switch(Buf_Free) Ins_Char('-', COUNT, 100) for (#1=1; #1 <= 10; #1++) {
Goto_Col(#1*#1) Ins_Char('O', OVERWRITE)
}</lang>
Output:
O--O----O------O--------O----------O------------O--------------O----------------O------------------O
Visual Basic .NET
unoptimized <lang vbnet>Module Module1
Sub Main() Dim doors(100) As Boolean 'Door 1 is at index 0
For pass = 1 To 100 For door = pass - 1 To 99 Step pass doors(door) = Not doors(door) Next Next
For door = 0 To 99 Console.WriteLine("Door # " & (door + 1) & " is " & If(doors(door), "Open", "Closed")) Next
Console.ReadLine() End Sub
End Module</lang> optimized <lang vbnet>Module Module1
Sub Main() Dim doors(100) As Boolean 'Door 1 is at index 0
For i = 1 To 10 doors(i ^ 2 - 1) = True Next
For door = 0 To 99 Console.WriteLine("Door # " & (door + 1) & " is " & If(doors(door), "Open", "Closed")) Next
Console.ReadLine() End Sub
End Module</lang>
- Programming Tasks
- Puzzles
- 8086 Assembly
- Ada
- ALGOL 68
- AmigaE
- AutoHotkey
- AWK
- BASIC
- C
- C++
- C sharp
- Common Lisp
- Clojure
- D
- E
- Erlang
- Factor
- Falcon
- Forth
- Fortran
- F Sharp
- Go
- Groovy
- Haskell
- HaXe
- J
- Java
- JavaScript
- Logo
- Lua
- M4
- Mathematica
- MAXScript
- Metafont
- MMIX
- Modula-3
- MOO
- OCaml
- Octave
- Oz
- Pascal
- PHP
- Perl
- Perl 6
- Pop11
- PowerShell
- Python
- Q
- R
- REBOL
- Ruby
- SAS
- Scala
- Scheme
- Slate
- Smalltalk
- SETL
- Tcl
- Tk
- TI-89 BASIC
- UNIX Shell
- Vedit macro language
- Visual Basic .NET