100 doors
From Rosetta Code
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.
[edit] 6502 Assembly
Works with: [6502asm.com] version 1.2
optimized (Largely inspired by the optimized C implementation)
;assume all memory is initially set to 0
inc $1 ;start out with a delta of 1
openloop: inc $200,X ;open a door at X
inc $1 ;add 2 to delta
inc $1
txa ;add delta to X
adc $1
tax
cpx #$65 ;check to see if we're at the 100th door
bmi openloop ;jump back to openloop if less than 100
[edit] 8086 Assembly
[edit] ActionScript
Works with: ActionScript version 3.0 unoptimized
package {
import flash.display.Sprite;
public class Doors extends Sprite {
public function Doors() {
// Initialize the array
var doors:Array = new Array(100);
for (var i:Number = 0; i < 100; i++) {
doors[i] = false;
// Do the work
for (var pass:Number = 0; pass < 100; pass++) {
for (var j:Number = pass; j < 100; j += (pass+1)) {
doors[j] = !doors[j];
}
}
trace(doors);
}
}
}
[edit] Ada
unoptimized
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;
optimized
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;
[edit] Aikido
var doors = new int [100]
foreach pass 100 {
for (var door = pass ; door < 100 ; door += pass+1) {
doors[door] = !doors[door]
}
}
var d = 1
foreach door doors {
println ("door " + d++ + " is " + (door ? "open" : "closed"))
}
[edit] ALGOL 68
unoptimized
# 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;
optimized
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)
[edit] 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
[edit] Argile
use std, array
close all doors
for each pass from 1 to 100
for (door = pass) (door <= 100) (door += pass)
toggle door
let int pass, door.
.: close all doors :. {memset doors 0 size of doors}
.:toggle <int door>:. { !!(doors[door - 1]) }
let doors be an array of 100 bool
for each door from 1 to 100
printf "#%.3d %s\n" door (doors[door - 1]) ? "[ ]", "[X]"
[edit] AutoHotkey
[edit] Standard Approach
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
[edit] Alternative Approach
Making use of the identity:
increment := 3, square := 1
Loop, 100
If (A_Index = square)
outstring .= "`nDoor " A_Index " is open"
,square += increment, increment += 2
MsgBox,, Succesfull, % SubStr(outstring, 2)
[edit] Optimized
While (Door := A_Index ** 2) <= 100
Result .= "Door " Door " is open`n"
MsgBox, %Result%
[edit] AWK
unoptimized
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"
}
}
optimized
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"
}
}
[edit] Batch File
unoptimized
@echo off
setlocal enabledelayedexpansion
for /l %%p in (1,1,100) do (
for /l %%d in (%%p,%%p,100) do (
if not defined door%%d (
set door%%d=closed
) else (
call :toggle door%%d
)
)
)
for /l %%d in (1,1,100) do (
echo door%%d=!door%% class="re2">d!
)
goto :eof
:toggle
if !% class="re2">1! equ open (
set %1=closed
) else (
set %1=open
)
goto :eof
[edit] BASIC
Works with: QuickBasic version 4.5
unoptimized
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
optimized
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
[edit] Befunge
Works with: CCBI version 2.1
108p0>:18p;;>:9g!18g9p08g]
*`!0\|+relet|-1`*aap81::+]
;::+1<r]!g9;>$08g1+:08paa[
*`#@_^._aa
[edit] C
unoptimized
#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;
}
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
.
#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;
}
The following ultra-short optimized version demonstrates the flexibility of C loops, but isn't really considered good C style:
#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;
}
[edit] C++
Works with: GCC version 4.1.2 20061115 (prerelease) (SUSE Linux)
unoptimized
#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;
}
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
.
#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;
}
The following ultra-short optimized version demonstrates the flexibility of C++ loops, but isn't really considered good C++ style:
#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;
}
[edit] C#
Unoptimized
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);
}
}
Optimized
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");
}
}
}
[edit] ColdFusion
Basic Solution: Returns List of 100 values: 1=open 0=closed
doorCount = 1;
doorList = "";
// create all doors and set all doors to open
while (doorCount LTE 100) {
doorList = ListAppend(doorList,"1");
doorCount = doorCount + 1;
}
loopCount = 2;
doorListLen = ListLen(doorList);
while (loopCount LTE 100) {
loopDoorListCount = 1;
while (loopDoorListCount LTE 100) {
testDoor = loopDoorListCount / loopCount;
if (testDoor EQ Int(testDoor)) {
checkOpen = ListGetAt(doorList,loopDoorListCount);
if (checkOpen EQ 1) {
doorList = ListSetAt(doorList,loopDoorListCount,"0");
} else {
doorList = ListSetAt(doorList,loopDoorListCount,"1");
}
}
loopDoorListCount = loopDoorListCount + 1;
}
loopCount = loopCount + 1;
}
Squares of Integers Solution: Returns List of 100 values: 1=open 0=closed
doorCount = 1;
doorList = "";
loopCount = 1;
while (loopCount LTE 100) {
if (Sqr(loopCount) NEQ Int(Sqr(loopCount))) {
doorList = ListAppend(doorList,0);
} else {
doorList = ListAppend(doorList,1);
}
loopCount = loopCount + 1;
}
Display only
// Display all doors
<cfloop from="1" to="100" index="x">
Door #x# Open: #YesNoFormat(ListGetAt(doorList,x))#<br />
</cfloop>
// Output only open doors
<cfloop from="1" to="100" index="x">
<cfif ListGetAt(doorList,x) EQ 1>
#x#<br />
</cfif>
</cfloop>
[edit] 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
(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))))
Unoptimized / imperative This is a version that closely follows the problem description and is still quite short.
(define-modify-macro toggle () not)
(defun 100-doors ()
(let ((doors (make-array 100 :initial-element nil)))
(dotimes (i 100)
(loop for j from i below 100 by (1+ i)
do (toggle (svref doors j))))
(dotimes (i 100)
(format t "door ~a: ~:[closed~;open~]~%" (1+ i) (svref doors i)))))
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)
(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) "_")))
Optimized (2) This version displays a much more functional solution through the use of (mapcar ...)
(let ((i 0))
(mapcar (lambda (x)
(if (zerop (mod (sqrt (incf i)) 1))
"_" "#"))
(make-list 100)))
[edit] Clojure
Unoptimized / mutable array
(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)))))
Unoptimized / functional
(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)))))
Optimized / functional
(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)))))
[edit] D
import std.stdio: write, writeln;
enum DoorState : uint { Closed, Open }
alias DoorState[] Doors;
Doors flipUnoptimized(Doors doors) {
doors[] = DoorState.Closed;
foreach (i; 0 .. doors.length)
for (int j = i; j < doors.length; j += i+1)
if (doors[j] == DoorState.Open)
doors[j] = DoorState.Closed;
else
doors[j] = DoorState.Open;
return doors;
}
Doors flipOptimized(Doors doors) {
doors[] = DoorState.Closed;
for (int i = 1; i*i <= doors.length; i++)
doors[i*i - 1] = DoorState.Open;
return doors;
}
// test program
void main() {
auto doors = new Doors(100);
foreach (i, door; flipUnoptimized(doors))
if (door == DoorState.Open)
write(i+1, " ");
writeln();
foreach (i, door; flipOptimized(doors))
if (door == DoorState.Open)
write(i+1, " ");
writeln();
}
[edit] Dylan
Unoptimized
define method doors()
let doors = make(<array>, fill: #f, size: 100);
for (x from 0 below 100)
for (y from x below 100 by x + 1)
doors[y] := ~doors[y]
end
end;
for (x from 1 to 100)
if (doors[x - 1])
format-out("door %d open\n", x)
end
end
end
[edit] E
Graphical Works with: E-on-Java
This version animates the changes of the doors (as checkboxes).
#!/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)
[edit] Emacs Lisp
Unoptimized
(defun create-doors ()
"Returns a list of closed doors
Each door only has two status: open or closed.
If a door is closed it has the value 0, if it's open it has the value 1."
(let ((return_value '(0))
;; There is already a door in the return_value, so k starts at 1
;; otherwise we would need to compare k against 99 and not 100 in
;; the while loop
(k 1))
(while (< k 100)
(setq return_value (cons 0 return_value))
(setq k (+ 1 k)))
return_value))
(defun toggle-single-door (doors)
"Toggle the stat of the door at the `car' position of the DOORS list
DOORS is a list of integers with either the value 0 or 1 and it represents
a row of doors.
Returns a list where the `car' of the list has it's value toggled (if open
it becomes closed, if closed it becomes open)."
(if (= (car doors) 1)
(cons 0 (cdr doors))
(cons 1 (cdr doors))))
(defun toggle-doors (doors step original-step)
"Step through all elements of the doors' list and toggle a door when step is 1
DOORS is a list of integers with either the value 0 or 1 and it represents
a row of doors.
STEP is the number of doors we still need to transverse before we arrive
at a door that has to be toggled.
ORIGINAL-STEP is the value of the argument step when this function is
called for the first time.
Returns a list of doors"
(cond ((null doors)
'())
((= step 1)
(cons (car (toggle-single-door doors))
(toggle-doors (cdr doors) original-step original-step)))
(t
(cons (car doors)
(toggle-doors (cdr doors) (- step 1) original-step)))))
(defun main-program ()
"The main loop for the program"
(let ((doors_list (create-doors))
(k 1)
;; We need to define max-specpdl-size and max-specpdl-size to big
;; numbers otherwise the loop reaches the max recursion depth and
;; throws an error.
;; If you want more information about these variables, press Ctrl
;; and h at the same time and then press v and then type the name
;; of the variable that you want to read the documentation.
(max-specpdl-size 5000)
(max-lisp-eval-depth 2000))
(while (< k 101)
(setq doors_list (toggle-doors doors_list k k))
(setq k (+ 1 k)))
doors_list))
(defun print-doors (doors)
"This function prints the values of the doors into the current buffer.
DOORS is a list of integers with either the value 0 or 1 and it represents
a row of doors.
"
;; As in the main-program function, we need to set the variable
;; max-lisp-eval-depth to a big number so it doesn't reach max recursion
;; depth.
(let ((max-lisp-eval-depth 5000))
(unless (null doors)
(insert (int-to-string (car doors)))
(print-doors (cdr doors)))))
;; Returns a list with the final solution
(main-program)
;; Print the final solution on the buffer
(print-doors (main-program))
[edit] Erlang
optimized
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)].
[edit] 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 ;
[edit] Falcon
Unoptimized code
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
Optimized code
for door in [ 1 : 101 ]: > "Door ", $door, " is: ", fract( door ** 0.5 ) ? "closed" : "open"
[edit] 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
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 ;
Unfactored
: 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
Optimized
: SQUARED DUP * ;
: DOORS 1 BEGIN 2DUP SQUARED >= WHILE DUP SQUARED . 1+ REPEAT 2DROP ;
100 DOORS
[edit] Fortran
Works with: Fortran version ISO 90 and later unoptimized
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
optimized
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
[edit] F#
Requires #light in versions of F# prior to 2010 beta.
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
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.
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 |]
[edit] Go
unoptimized
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(" ")
}
}
}
optimized
package main
import (
. "fmt"
)
func main() {
var door int = 1
var incrementer = 0
for current := 1; current <= 100; current++ {
Printf("Door %d ", current)
if current == door {
Printf("Open\n")
incrementer++
door += 2 * incrementer + 1
} else {
Printf("Closed\n")
}
}
}
[edit] Groovy
unoptimized
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'}.")
}
optimized a Using square roots
(1..100).each {
println("Door #${it} is ${Math.sqrt(it).with{it==(int)it} ? 'open' : 'closed'}.")
}
optimized b Without using square roots
doors = ['closed'] * 100
(1..10).each { doors[it**2 - 1] = 'open' }
(0..99).each {
println("Door #${it + 1} is ${doors[it]}.")
}
[edit] Haskell
unoptimized
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]
optimized (without using square roots)
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..]]
alternatively, returning a list of all open gates, it's a one-liner:
run n = takeWhile (< n) [k*k | k <- [1..]]
[edit] 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++;
}
}
}
[edit] HicEst
Unoptimized
REAL :: n=100, open=1, door(n)
door = 1 - open ! = closed
DO i = 1, n
DO j = i, n, i
door(j) = open - door(j)
ENDDO
ENDDO
DLG(Text=door, TItle=SUM(door)//" doors open")
Optimized
door = 1 - open ! = closed
DO i = 1, n^0.5
door(i*i) = open
ENDDO
DLG(Text=door, TItle=SUM(door)//" doors open")
[edit] Icon and Unicon
[edit] Icon
Unoptimized solution.
procedure main()
door := table(0) # default value of entries is 0
every pass := 1 to 100 do
every door[i := pass to 100 by pass] := 1 - door[i]
every write("Door ", i := 1 to 100, " is ", if door[i] = 1 then "open" else "closed")
end
Optimized solution.
procedure main()
every write("Door ", i := 1 to 100, " is ", if integer(sqrt(i)) = sqrt(i) then "open" else "closed")
end
or
procedure main(args)
dMap := table("closed")
every dMap[(1 to sqrt(100))^2] := "open"
every write("Door ",i := 1 to 100," is ",dMap[i])
end
[edit] Unicon
The Icon solutions also work in Unicon.
Notes:
- Icon and Unicon don't have a boolean type because most often, logic is expressed in terms of success or failure, which affects flow at runtime.
[edit] Io
simple boolean list solution:
doors := List clone
for(i,1,100, doors append(false))
for(i,1,100,
for(x,i,100, i, doors atPut(x - 1, doors at(x - 1) not))
)
doors foreach(i, x, if(x, "Door #{i + 1} is open" interpolate println))
[edit] Ioke
Unoptimized Object Oriented solution.
NDoors = Origin mimic
NDoors Toggle = Origin mimic do(
initialize = method(toggled?, @toggled? = toggled?)
toggle! = method(@toggled? = !toggled?. self)
)
NDoors Doors = Origin mimic do(
initialize = method(n,
@n = n
@doors = {} addKeysAndValues(1..n, (1..n) map(_, NDoors Toggle mimic(false)))
)
numsToToggle = method(n, for(x <- (1..@n), (x % n) zero?, x))
toggleThese = method(nums, nums each(x, @doors[x] = @doors at(x) toggle))
show = method(@doors filter:dict(value toggled?) keys sort println)
)
; Test code
x = NDoors Doors mimic(100)
(1..100) each(n, x toggleThese(x numsToToggle(n)))
x show
[edit] J
unoptimized
~:/ (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 ...
~:/ 0=|/~ >:i.100 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 ...
optimized
(>: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 ...
[edit] Java
unoptimized
public class Door {
private boolean open = false;
private final int index;
public Door(int index) {
this.index = index;
}
public int getIndex() {
return index;
}
public String getState() {
return open ? "open" : "closed";
}
public void toggle() {
open = !open;
}
public static void main(String[] args) {
final int N = 100;
Door[] doors = new Door[N];
for (int i = 0; i < N; i++) {
doors[i] = new Door(i + 1);
}
for (int pass = 1; pass <= N; pass++) {
for (Door door : doors) {
if (door.getIndex() % pass == 0) {
door.toggle();
}
}
}
for (Door door : doors) {
System.out.println("Door #" + door.getIndex() + " is " + door.getState() + ".");
}
}
}
optimized
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."));
}
}
}
[edit] JavaScript
Works with: SpiderMonkey for the print() statement.
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.");
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 Works with: Firefox version 1.5
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(','));
outputs
these doors are open: 1,4,9,16,25,36,49,64,81
[edit] K
unoptimized / converted from Q .
`closed `open ![ ; 2 ] @ #:' 1 _ = ,/ &:' 0 = t !\:/: t : ! 101
optimized / 1 origin indices
( 1 + ! 10 ) ^ 2
/ As parameterized function :
{ ( 1 + ! _ x ^ % 2 ) ^ 2 } 100
[edit] Logo
to doors
;Problem 100 Doors
;FMSLogo
;lrcvs 2010
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
[edit] 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
[edit] 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
[edit] Mathematica
unoptimized 1
n=100;
tmp=ConstantArray[-1,n];
Do[tmp[[i;;;;i]]*=-1;,{i,n}];
Do[Print["door ",i," is ",If[tmp[[i]]==-1,"closed","open"]],{i,1,Length[tmp]}]
optimized 1
Do[Print["door ",i," is ",If[IntegerQ[Sqrt[i]],"open","closed"]],{i,100}]
optimized 2
n=100;
a=Range[1,Sqrt[n]]^2
Do[Print["door ",i," is ",If[MemberQ[a,i],"open","closed"]],{i,100}]
optimized 3
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"];
];
]
These will only give the indices for the open doors: unoptimized 2
Pick[Range[100], Xor@@@Array[Divisible[#1,#2]&, {100,100}]]
optimized 4
Range[Sqrt[100]]^2
[edit] MATLAB
[edit] Iterative Method
Unoptimized
a=zeros(1,100);
for b=1:100;
for i=b:b:100;
if a(i)==1
a(i)=0;
else
a(i)=1;
end
end
end
a
Optimized
for x=1:100;
if sqrt(x) == floor(sqrt(x))
a(i)=1;
end
end
a
[edit] Vectorized Method
function [doors,opened,closed] = hundredDoors()
%Initialize the doors, make them booleans for easy vectorization
doors = logical( (1:1:100) );
%Go through the flipping process, ignore the 1 case because the doors
%array is already initialized to all open
for initialPosition = (2:100)
doors(initialPosition:initialPosition:100) = not( doors(initialPosition:initialPosition:100) );
end
opened = find(doors); %Stores the numbers of the open doors
closed = find( not(doors) ); %Stores the numbers of the closed doors
end
[edit] MAXScript
unoptimized
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]
)
optimized
for i in 1 to 100 do
(
root = pow i 0.5
format ("Door % is open?: %\n") i (root == (root as integer))
)
[edit] 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
[edit] MMIX
See 100 doors/MMIX
[edit] Modula-3
unoptimized
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.
optimized
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.
[edit] 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
[edit] MUMPS
doors new door,pass
For door=1:1:100 Set door(door)=0
For pass=1:1:100 For door=pass:pass:100 Set door(door)='door(door)
For door=1:1:100 If door(door) Write !,"Door",$j(door,4)," is open"
Write !,"All other doors are closed."
Quit
Do doors
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
All other doors are closed.
[edit] Objeck
optimized
bundle Default {
class Doors {
function : Main(args : String[]) ~ Nil {
doors := Bool->New[100];
for(pass := 0; pass < 10; pass += 1;) {
doors[(pass + 1) * (pass + 1) - 1] := true;
};
for(i := 0; i < 100; i += 1;) {
IO.Console->GetInstance()->Print("Door #")->Print(i + 1)->Print(" is ");
if(doors[i]) {
"open."->PrintLine();
}
else {
"closed."->PrintLine();
};
};
}
}
}
[edit] OCaml
unoptimized
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))
optimized
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))
[edit] 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
[edit] 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
}
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.
[edit] 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.
[edit] PHP
optimized
<?php
for ($i = 1; $i <= 100; $i++) {
$root = sqrt($i);
$state = ($root == ceil($root)) ? "open" : "closed";
echo "Door $i: $state";
}
?>
[edit] Perl
unoptimized Works with: Perl version 5.x
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;
optimized Works with: Perl version 5.x
print "Door $_ is ", qw"closed open"[int sqrt == sqrt], "\n" for 1..100;
while( ++$i <= 100 )
{
$root = sqrt($i);
if ( int( $root ) == $root )
{
print "Door $i is open\n";
}
else
{
print "Door $i is closed\n";
}
}
[edit] Perl 6
unoptimized Works with: Rakudo version #25 "Minneapolis"
my @doors = False xx 101;
($_ = !$_ for @doors[0 ... *+$_, 100]) for 1..100;
say "Door $_ is ", <closed open>[ @doors[$_] ] for 1..100;
optimized Works with: Rakudo version #25 "Minneapolis"
say "Door $_ is open" for map * ** 2, 1..10;
or printing both opened and closed doors:
say "Door $_ is ", <closed open>[.sqrt == .sqrt.floor] for 1..100;
[edit] PicoLisp
unoptimized
(let Doors (need 100)
(for I 100
(for (D (nth Doors I) D (cdr (nth D I)))
(set D (not (car D))) ) )
(println Doors) )
optimized
(let Doors (need 100)
(for I (sqrt 100)
(set (nth Doors (* I I)) T) )
(println Doors) )
Output in both cases:
(T NIL NIL T NIL NIL NIL NIL T NIL NIL NIL NIL NIL NIL T NIL NIL NIL NIL NIL NIL NIL NIL T NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL T NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL T NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL T NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL T NIL NIL NIL N IL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL NIL T)
[edit] PL/I
declare door(100) bit (1);
declare closed bit (1) static initial ('0'b),
open bit (1) static initial ('1'b);
declare (i, inc) fixed binary;
door = closed;
inc = 1;
do until (inc >= 100);
do i = inc to 100 by inc;
door(i) = ^door(i); /* close door if open; open it if closed. */
end;
inc = inc+1;
end;
do i = 1 to 100;
put skip edit ('Door ', trim(i), ' is ') (a);
if door(i) then put edit (' open.') (a);
else put edit (' closed.') (a);
end;
[edit] Pop11
unoptimized
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;
optimized
for i to 100 do
lvars root = sqrt(i);
i; if root = round(root) then ' open' ><; else ' closed' ><; endif; =>
endfor;
[edit] PowerShell
unoptimized
$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"}
}
[edit] PureBasic
unoptimized
Dim doors.b(100)
For x = 1 To 100
y = x
While y <= 100
If doors(y)
doors(y) = 0
Else
doors(y) = 1
EndIf
y + x
Wend
Next
OpenConsole()
PrintN("Following Doors are open:")
For x = 1 To 100
If doors(x)
Print(Str(x)+", ")
EndIf
Next
Input()
optimized
OpenConsole()
PrintN("Following Doors are open:")
For i = 1 To 100
root.f = Pow(i,0.5)
If root = Int(root)
Print (Str(i) + ", ")
EndIf
Next
Input()
Output:
Following Doors are open: 1, 4, 9, 16, 25, 36, 49, 64, 81, 100,
[edit] Python
Works with: Python version 2.5+ unoptimized
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'
optimized
A version that only visits each door once:
for i in xrange(1, 101):
root = i ** 0.5
print "Door %d:" % i, 'open' if root == int(root) else 'close'
[edit] Q
unoptimized
`closed`open mod[;2]count each 1 _ group raze where each 0=t mod\:/:t:til 101
[edit] R
unoptimized
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()
optimized
## optimized version... we only have to to up to the square root of 100
seq(1,sqrt(100))**2
[edit] 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 ]
[edit] REXX
door. = 0
do inc = 1 to 100
do d = inc to 100 by inc
door.d = \door.d
end
end
say "The open doors after 100 passes:"
do i = 1 to 100
if door.i = 1 then say i
end
[edit] Ruby
unoptimized
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
}
optimized
n = 100
(1..n).each do |i|
puts "Door #{i} is #{i**0.5 == (i**0.5).round ? "open" : "closed"}"
end
[edit] Sather
class MAIN is
main is
pass, door :INT;
doors :ARRAY{BOOL} := #(100);
loop
doors[0.upto!(99)] := false;
end;
pass := 0;
loop while!(pass < 100);
door := pass;
loop while! (door < 100);
doors[door] := ~doors[door];
door := door + pass + 1
end;
pass := pass + 1;
end;
loop
door := 0.upto!(99);
#OUT + (door+1) + " " + doors[door] + "\n";
end;
end;
end;
[edit] 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;
[edit] Scala
Both optimized and non-optimized versions follow. Both are fully functional.
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
}
}
[edit] Scheme
unoptimized
(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)))
optimized
(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)))
[edit] Slate
Unoptimized
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'])].
Optimized
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'])].
[edit] Smalltalk
Works with: GNU Smalltalk Unoptimized
|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
]
Optimized
|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
]
Works with: Squeak Smalltalk Unoptimized, using Morphs
| m w h smh smw delay closedDoor border subMorphList |
closedDoor := Color black.
border := Color veryLightGray.
delay := Delay forMilliseconds: 50.
w := World bounds corner x.
h := (World bounds corner y) / 2.
smw := w/100.
smh := h/2.
m := BorderedMorph new position: 0@h.
m height: smh; width: w; borderColor: border.
m color: Color veryLightGray.
1 to: 100 do: [ :pos || sm |
sm := BorderedMorph new height: smh ; width: smw ;
borderColor: border; color: closedDoor;
position: (smw*pos)@h.
m addMorph: sm asElementNumber: pos].
m openInWorld.
delay wait.
subMorphList := m submorphs.
"display every step"
[1 to: 100 do: [ :step |
step to: 100 by: step do: [ :pos | | subMorph |
subMorph := subMorphList at: pos.
subMorph color: subMorph color negated.
delay wait]]] fork.
[edit] SETL
Unoptimized
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;
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.
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;
[edit] Tcl
unoptimized
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"}]]
}
optimized
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]]
}
graphical
Library: Tk Inspired by the E solution, here's a visual representation
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
}
}
}
}
[edit] TI-89 BASIC
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
[edit] UNIX Shell
Works with: Bourne Again SHell
#! /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
[edit] Ursala
The doors are represented as a list of 100 booleans initialized to false. The pass function takes a number and a door list to a door list with doors toggled at indices that are multiples of the number. The main program folds the pass function (to the right) over the list of pass numbers from 100 down to 1, numbers the result, and filters out the numbers of the open doors.
#import std
#import nat
doors = 0!* iota 100
pass("n","d") = remainder\"n"?l(~&r,not ~&r)* num "d"
#cast %nL
main = ~&rFlS num pass=>doors nrange(100,1)
optimized version:
#import nat
#cast %nL
main = product*tiiXS iota10
output:
<1,4,9,16,25,36,49,64,81>
[edit] VBScript
Works with: Windows Script Host version 5.7 Unoptimized
Dim doorIsOpen(100), pass, currentDoor, text
For currentDoor = 0 To 99
doorIsOpen(currentDoor) = False
Next
For pass = 0 To 99
For currentDoor = pass To 99 Step pass + 1
doorIsOpen(currentDoor) = Not doorIsOpen(currentDoor)
Next
Next
For currentDoor = 0 To 99
text = "Door #" & currentDoor + 1 & " is "
If doorIsOpen(currentDoor) Then
text = text & "open."
Else
text = text & "closed."
End If
WScript.Echo(text)
Next
[edit] 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'.
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'
}
}
Optimized
Buf_Switch(Buf_Free)
Ins_Char('-', COUNT, 100)
for (#1=1; #1 <= 10; #1++) {
Goto_Col(#1*#1)
Ins_Char('O', OVERWRITE)
}
Output:
O--O----O------O--------O----------O------------O--------------O----------------O------------------O
[edit] Visual Basic .NET
Works with: Visual Basic .NET version 9.0+ unoptimized
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
optimized
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

