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.

100 doors is a programming puzzle. It lays out a problem which Rosetta Code users are encouraged to solve, using languages and techniques they know. Multiple approaches are not discouraged, so long as the puzzle guidelines are followed. For other Puzzles, see Category:Puzzles.

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.

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

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

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

Works with: QuickBasic version 4.5

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

Works with: GCC version 4.1.2 20061115 (prerelease) (SUSE Linux)

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

Works with: E-on-Java

This version animates the changes of the doors (as checkboxes).

<lang e>#!/usr/bin/env rune

var toggles := [] var gets := []

  1. 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)

}

  1. Set up termination condition

def done frame.addWindowListener(def _ {

 to windowClosing(event) {
   bind done := true
 }
 match _ {}

})

  1. 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>

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

Fortran

Works with: Fortran version ISO 90 and later

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>

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 f []          = []
toggle f (Open:xs)   = Closed : f xs
toggle f (Closed:xs) = Open   : f xs

pass k [] = []
pass k xs = ys ++ toggle (pass k) zs where (ys,zs) = splitAt k xs

run n = snd $ (!! n) $ 
  iterate (\(k,xs) -> (k+1, pass k xs)) $ (0, replicate n Closed)</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

   ~:/ (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 ...

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

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>

M4

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

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

This will only give the indices for the open doors: optimized 4 <lang Mathematica >

Range[Sqrt[100]]^2

</lang>

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

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>

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>

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

Works with: Perl version 5.x
my @doors;
foreach my $pass (1 .. 100) {
    foreach (1 .. 100) {
        if (0 == $_ % $pass) {
            if (1 == $doors[$_]) {
                $doors[$_] = 0;
            } else {
                $doors[$_] = 1;
            };
        };
    };
};

print "$_\t$doors[$_]\n" foreach 1 .. 100;

optimized

Works with: Perl version 5.x
while( ++$i <= 100 )
{
        $root = sqrt($i);
        if ( int( $root ) == $root )
        {
                print "Door $i is open\n";
        }
        else
        {
                print "Door $i is closed\n";
        }
}

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>

Python

Note: both versions require Python 2.5 for the ternary syntax.

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>


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>

    1. optimized version... we only have to to up to the square root of 100

seq(1,sqrt(100))**2 </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>

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

Works with: GNU 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

Library: Tk

Inspired by the E solution, here's a visual representation <lang tcl>package require Tcl 8.5 package require Tk

array set door_status {}

  1. 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
   }

}

  1. 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>

UNIX Shell

Works with: Bourne Again 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

Platform: .NET

Language 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