100 doors
You are encouraged to solve this task according to the task description, using any language you may know.
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.
6502 Assembly
optimized (Largely inspired by the optimized C implementation) <lang 6502asm>
;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</lang>
8086 Assembly
ABAP
unoptimized <lang ABAP>form open_doors_unopt.
data: lv_door type i, lv_count type i value 1. data: lt_doors type standard table of c initial size 100. field-symbols: <wa_door> type c. do 100 times. append initial line to lt_doors assigning <wa_door>. <wa_door> = 'X'. enddo.
while lv_count < 100. lv_count = lv_count + 1. lv_door = lv_count. while lv_door < 100. read table lt_doors index lv_door assigning <wa_door>. if <wa_door> = ' '. <wa_door> = 'X'. else. <wa_door> = ' '. endif. add lv_count to lv_door. endwhile. endwhile.
loop at lt_doors assigning <wa_door>. if <wa_door> = 'X'. write : / 'Door', (4) sy-tabix right-justified, 'is open' no-gap. endif. endloop.
endform.</lang>
optimized
Using <lang ABAP>form open_doors_opt.
data: lv_square type i value 1, lv_inc type i value 3. data: lt_doors type standard table of c initial size 100. field-symbols: <wa_door> type c. do 100 times. append initial line to lt_doors assigning <wa_door>. if sy-index = lv_square. <wa_door> = 'X'. add: lv_inc to lv_square, 2 to lv_inc. write : / 'Door', (4) sy-index right-justified, 'is open' no-gap. endif. enddo.
endform.</lang>
ActionScript
unoptimized <lang actionscript>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); } }
}</lang>
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>
Aikido
<lang 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"))
}
</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>
AppleScript
<lang AppleScript>set is_open to {} repeat 100 times
set end of is_open to false
end repeat with pass from 1 to 100
repeat with door from pass to 100 by pass set item door of is_open to not item door of is_open end
end set open_doors to {} repeat with door from 1 to 100
if item door of is_open then set end of open_doors to door end
end set text item delimiters to ", " display dialog "Open doors: " & open_doors</lang>
Argile
<lang 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]"</lang>
AutoHotkey
Standard Approach
<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>
Alternative Approach
Making use of the identity:
<lang autohotkey>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)</lang>
Optimized
<lang autohotkey>While (Door := A_Index ** 2) <= 100
Result .= "Door " Door " is open`n"
MsgBox, %Result%</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>
Batch File
unoptimized <lang dos>@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%%d! ) goto :eof
- toggle
if !%1! equ open ( set %1=closed ) else ( set %1=open ) goto :eof</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>
Befunge
<lang befunge>108p0>:18p;;>:9g!18g9p08g]
- `!0\|+relet|-1`*aap81::+]
- +1<r]!g9;>$08g1+
- 08paa[
- `#@_^._aa</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> //compiled with "Dev-C++" , from RaptorOne
int main() {
for(int i=1; i*i<=100; i++) std::cout<<"Door "<<i*i<<" is open!"<<std::endl;
}</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>
CLIPS
Unoptimized
<lang clips>(deffacts initial-state
(door-count 100)
)
(deffunction toggle
(?state) (switch ?state (case "open" then "closed") (case "closed" then "open") )
)
(defrule create-doors-and-visits
(door-count ?count) => (loop-for-count (?num 1 ?count) do (assert (door ?num "closed")) (assert (visit-from ?num ?num)) ) (assert (doors initialized))
)
(defrule visit
(door-count ?max) ?visit <- (visit-from ?num ?step) ?door <- (door ?num ?state) => (retract ?visit) (retract ?door) (assert (door ?num (toggle ?state))) (if (<= (+ ?num ?step) ?max) then (assert (visit-from (+ ?num ?step) ?step)) )
)
(defrule start-printing
(doors initialized) (not (visit-from ? ?)) => (printout t "These doors are open:" crlf) (assert (print-from 1))
)
(defrule print-door
(door-count ?max) ?pf <- (print-from ?num) (door ?num ?state) => (retract ?pf) (if (= 0 (str-compare "open" ?state)) then (printout t ?num " ") ) (if (< ?num ?max) then (assert (print-from (+ ?num 1))) else (printout t crlf "All other doors are closed." crlf) )
)</lang>
Optimized
<lang clips>(deffacts initial-state
(door-count 100)
)
(deffunction is-square
(?num) (= (sqrt ?num) (integer (sqrt ?num)))
)
(defrule check-doors
(door-count ?count) => (printout t "These doors are open:" crlf) (loop-for-count (?num 1 ?count) do (if (is-square ?num) then (printout t ?num " ") ) ) (printout t crlf "All other doors are closed." crlf)
)</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>
COBOL
<lang cobol> IDENTIFICATION DIVISION.
PROGRAM-ID. 100Doors.
DATA DIVISION. WORKING-STORAGE SECTION. 01 Current PIC 9(3) VALUE ZEROES. 01 StepSize PIC 9(3) VALUE ZEROES. 01 DoorTable. 02 Doors PIC 9(1) OCCURS 100 TIMES. 01 Idx PIC 9(3).
PROCEDURE DIVISION. Begin. MOVE 1 TO StepSize PERFORM 100 TIMES MOVE StepSize TO Current PERFORM UNTIL Current > 100 SUBTRACT Doors(Current) FROM 1 GIVING Doors(Current) ADD StepSize TO Current GIVING Current END-PERFORM ADD 1 TO StepSize GIVING StepSize END-PERFORM PERFORM VARYING Idx FROM 1 BY 1 UNTIL Idx > 100 IF Doors(Idx) = 0 DISPLAY Idx " is closed." ELSE DISPLAY Idx " is open." END-IF END-PERFORM STOP RUN.</lang>
CoffeeScript
<lang coffeescript>open = (false for door in [1..100])
for pass in [1..100]
for door in [pass..100] by pass open[door] = if open[door] then false else true
openDoors = [] for door in [1..100]
openDoors.push(door) if open[door]
alert "Doors #{openDoors.join ', '} are open."</lang>
ColdFusion
Basic Solution: Returns List of 100 values: 1=open 0=closed <lang coldfusion> 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; } </lang>
Squares of Integers Solution: Returns List of 100 values: 1=open 0=closed <lang coldfusion> 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; } </lang>
Display only <lang coldfusion>
// Display all doors <cfloop from="1" to="100" index="x"> Door #x# Open: #YesNoFormat(ListGetAt(doorList,x))#
</cfloop>
// Output only open doors <cfloop from="1" to="100" index="x"> <cfif ListGetAt(doorList,x) EQ 1> #x#
</cfif> </cfloop>
</lang>
Common Lisp
Unoptimized / functional This is a very unoptimized version of the problem, using recursion and quite considerable list-copying. It emphasizes 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>
Unoptimized / imperative This is a version that closely follows the problem description and is still quite short.
<lang lisp>(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)))))</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)) "_" "#")) (make-list 100)))</lang>
D
<lang 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();
}</lang>
Dylan
Unoptimized <lang dylan>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</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>
Ela
Standard Approach
<lang ela>let gate (x::xs) (y::ys) | x == y = Open :: gate xs ys
gate (x::xs) ys = Closed :: gate xs ys gate [] _ = []
let run n = gate [1..n] [& k*k \\ k <- [1..]]</lang>
Alternate Approach <lang ela>open Core let run n = takeWhile (<n) [& k*k \\ k <- [1..]]</lang>
Emacs Lisp
Unoptimized
<lang lisp>(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))</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>
Euphoria
unoptimised <lang Euphoria>-- doors.ex include std/console.e sequence doors doors = repeat( 0, 100 ) -- 1 to 100, initialised to false
for pass = 1 to 100 do for door = pass to 100 by pass do --printf( 1, "%d", doors[door] ) --printf( 1, "%d", not doors[door] ) doors[door] = not doors[door] end for end for
sequence oc
for i = 1 to 100 do if doors[i] then oc = "open" else oc = "closed" end if
printf( 1, "door %d is %s\n", { i, oc } )
end for </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>
Fantom
Unoptimized <lang fantom>
states := (1..100).toList 100.times |i| { states = states.map |state| { state % (i+1) == 0 ? -state : +state } } echo("Open doors are " + states.findAll { it < 0 }.map { -it })
</lang> Optimized <lang fantom>
echo("Open doors are " + (1..100).toList.findAll { it.toFloat.pow(0.5f).toInt.pow(2) == it})
</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 (plus or minus two) in their minds at a time, 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>
GAP
<lang gap>doors := function(n)
local a,j,s; a := [ ]; for j in [1 .. n] do a[j] := 0; od; for s in [1 .. n] do j := s; while j <= n do a[j] := 1 - a[j]; j := j + s; od; od; return Filtered([1 .. n], j -> a[j] = 1);
end;
doors(100);
- [ 1, 4, 9, 16, 25, 36, 49, 64, 81, 100 ]</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 { fmt.Printf("1") } else { fmt.Printf("0") }
if i%10 == 9 { fmt.Printf("\n") } else { fmt.Printf(" ") }
}
}</lang>
optimized
<lang go>package main
import "fmt"
func main() {
var door int = 1 var incrementer = 0
for current := 1; current <= 100; current++ { fmt.Printf("Door %d ", current)
if current == door { fmt.Printf("Open\n") incrementer++ door += 2*incrementer + 1 } else { fmt.Printf("Closed\n") } }
}</lang>
Golfscript
<lang golfscript>100:c;[{0}c*]:d; c,{.c,>\)%{.d<\.d=1^\)d>++:d;}/}/ [c,{)"door "\+" is"+}%d{{"open"}{"closed"}if}%]zip {" "*puts}/</lang>
optimized with sqrt (Original version of GolfScript has no sqrt operator, but it can be added easily; the code was tested using a work-in-progress C interpreter for a language compatible enough with Golfscript) <lang golfscript>100,{)}% {:d.sqrt 2?= {"open"}{"close"}if"door "d+" is "+\+puts}/</lang>
optimized without sqrt <lang golfscript>[{"close"}100*]:d; 10,{)2?(.d<\["open"]\)d>++:d;}/ [100,{)"door "\+" is"+}%d]zip {" "*puts}/</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>
HicEst
Unoptimized <lang hicest>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") </lang> Optimized <lang hicest>door = 1 - open ! = closed DO i = 1, n^0.5
door(i*i) = open
ENDDO DLG(Text=door, TItle=SUM(door)//" doors open") </lang>
Icon and Unicon
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 run time.
Unoptimized solution. <lang icon> 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 </lang>
Optimized solution. <lang icon> procedure main()
every write("Door ", i := 1 to 100, " is ", if integer(sqrt(i)) = sqrt(i) then "open" else "closed")
end </lang>
or
<lang icon>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</lang>
Inform 7
<lang inform7>Hallway is a room.
A toggle door is a kind of thing. A toggle door can be open or closed. It is usually closed. A toggle door has a number called the door number. Understand the door number property as referring to a toggle door. Rule for printing the name of a toggle door: say "door #[door number]".
There are 100 toggle doors.
When play begins (this is the initialize doors rule): let the next door number be 1; repeat with D running through toggle doors: now the door number of D is the next door number; increment the next door number.
To toggle (D - open toggle door): now D is closed. To toggle (D - closed toggle door): now D is open.
When play begins (this is the solve puzzle rule): let the door list be the list of toggle doors; let the door count be the number of entries in the door list; repeat with iteration running from 1 to 100: let N be the iteration; while N is less than the door count: toggle entry N in the door list; increase N by the iteration; say "Doors left open: [list of open toggle doors]."; end the story.</lang>
Informix 4GL
<lang Informix 4GL> MAIN
DEFINE i, pass SMALLINT, doors ARRAY[100] OF SMALLINT FOR i = 1 TO 100 LET doors[i] = FALSE END FOR FOR pass = 1 TO 100 FOR i = pass TO 100 STEP pass LET doors[i] = NOT doors[i] END FOR END FOR FOR i = 1 TO 100 IF doors[i] THEN DISPLAY i USING "Door <<& is open" ELSE DISPLAY i USING "Door <<& is closed" END IF END FOR
END MAIN </lang>
Io
simple boolean list solution: <lang io> 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)) </lang>
Ioke
Unoptimized Object Oriented solution. <lang ioke>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</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 ...
~:/ 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 ...</lang> optimized <lang j> (e. *:) 1+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 ...
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>
with formatting <lang j> 'these doors are open' ; >: I. (>:i.100) e. *: i.11 ┌────────────────────┬───────────────────────────┐ │these doors are open│1 4 9 16 25 36 49 64 81 100│ └────────────────────┴───────────────────────────┘
</lang>
Java
unoptimized <lang java5> public class Door {
private boolean open = false; private final int index;
public Door(final 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(final 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() + "."); }
} </lang>
optimized <lang java>public class Doors {
public static void main(final 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> optimized 2 <lang java>public class Doors {
public static void main(final String[] args) { StringBuilder sb = new StringBuilder();
for (int i = 1; i <= 10; i++) sb.append("Door #").append(i*i).append(" is open\n");
System.out.println(sb.toString()); }
}</lang>
JavaScript
<lang javascript>var
doors = [], n = 100, i, j;
for (i = 1; i <= n; i += 1)
for (j = i; j <= n; j += i) doors[j] = !doors[j];
for (i = 1; i <= n; i += 1)
if (doors[i]) document.write("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. door 100 is open.
Using features of JavaScript 1.6, this
<lang javascript>var
n = 100, doors = [n], step, idx;
// now, start opening and closing for (step = 1; step <= n; step += 1)
for (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;
}, []); document.write("These doors are open: " + open.join(', '));</lang> outputs
these doors are open: 1, 4, 9, 16, 25, 36, 49, 64, 81, 100
K
unoptimized / converted from Q . <lang k> `closed `open ![ ; 2 ] @ #:' 1 _ = ,/ &:' 0 = t !\:/: t : ! 101</lang>
optimized / 1 origin indices <lang k> ( 1 + ! 10 ) ^ 2</lang>
/ As parameterized function : <lang k> { ( 1 + ! _ x ^ % 2 ) ^ 2 } 100 </lang>
Liberty BASIC
<lang lb>dim doors(100) for pass = 1 to 100
for door = pass to 100 step pass doors(door) = not(doors(door)) next door
next pass print "open doors "; for door = 1 to 100
if doors(door) then print door;" ";
next door</lang>
Logo
<lang 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</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>
unoptimized 2 <lang mathematica>f[n_] = "Closed"; Do[Do[If[f[n] == "Closed", f[n] = "Open", f[n] = "Closed"], {n, k, 100, k}], {k, 1, 100}]; Table[f[n], {n, 1, 100}]</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>
MATLAB
Iterative Method
Unoptimized <lang MATLAB> 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 </lang> Optimized <lang MATLAB> for x=1:100;
if sqrt(x) == floor(sqrt(x)) a(i)=1; end
end a </lang>
Vectorized Method
<lang MATLAB>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</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>
MIPS Assembly
<lang mips>.data
doors: .space 100 num_str: .asciiz "Number " comma_gap: .asciiz " is " newline: .asciiz "\n"
.text main:
- Clear all the cells to zero
li $t1, 100 la $t2, doors
clear_loop:
sb $0, ($t2) add $t2, $t2, 1 sub $t1, $t1, 1 bnez $t1, clear_loop
- Now start the loops
li $t0, 1 # This will the the step size li $t4, 1 # just an arbitrary 1
loop1:
move $t1, $t0 # Counter la $t2, doors # Current pointer add $t2, $t2, $t0 addi $t2, $t2, -1
loop2:
lb $t3, ($t2) sub $t3, $t4, $t3 sb $t3, ($t2) add $t1, $t1, $t0 add $t2, $t2, $t0 ble $t1, 100, loop2
addi $t0, $t0, 1 ble $t0, 100, loop1
# Now display everything la $t0, doors li $t1, 1
loop3:
li $v0, 4 la $a0, num_str syscall li $v0, 1 move $a0, $t1 syscall
li $v0, 4 la $a0, comma_gap syscall
li $v0, 1 lb $a0, ($t0) syscall
li $v0, 4, la $a0, newline syscall
addi $t0, $t0, 1 addi $t1, $t1, 1 bne $t1, 101 loop3
</lang>
MMIX
See 100 doors/MMIX
Modula-2
unoptimized <lang modula2>MODULE Doors; IMPORT InOut;
TYPE State = (Closed, Open); TYPE List = ARRAY [1 .. 100] OF State;
VAR
Doors: List; I, J: CARDINAL;
BEGIN
FOR I := 1 TO 100 DO FOR J := 1 TO 100 DO IF J MOD I = 0 THEN IF Doors[J] = Closed THEN Doors[J] := Open ELSE Doors[J] := Closed END END END END;
FOR I := 1 TO 100 DO InOut.WriteCard(I, 3); InOut.WriteString(' is ');
IF Doors[I] = Closed THEN InOut.WriteString('Closed.') ELSE InOut.WriteString('Open.') END;
InOut.WriteLn END
END Doors.</lang>
optimized <lang modula2>MODULE DoorsOpt; IMPORT InOut;
TYPE State = (Closed, Open); TYPE List = ARRAY [1 .. 100] OF State;
VAR
Doors: List; I: CARDINAL;
BEGIN
FOR I := 1 TO 10 DO Doors[I*I] := Open END;
FOR I := 1 TO 100 DO InOut.WriteCard(I, 3); InOut.WriteString(' is '); IF Doors[I] = Closed THEN InOut.WriteString('Closed.') ELSE InOut.WriteString('Open.') END; InOut.WriteLn END
END DoorsOpt.</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>
MUMPS
<lang <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.</lang>
Objeck
optimized <lang objeck> 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(); }; }; } }
} </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.
PARI/GP
Unoptimized version. <lang parigp> v=vector(d=100);/*set 100 closed doors*/ for(i=1,d,forstep(j=i,d,i,v[j]=1-v[j])); for(i=1,d,if(v[i],print("Door ",i," is open."))) </lang> Optimized version. <lang parigp>for(n=1,10,print("Door ",n^2," is open."))</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>
Optimized version.
<lang pascal>program OneHundredDoors;
{$APPTYPE CONSOLE}
uses
math, sysutils;
var
AOpendoors : String; ACloseDoors : String; i : Integer;
begin
for i := 1 to 100 do begin if (sqrt(i) = floor(sqrt(i))) then AOpenDoors := AOpenDoors + IntToStr(i) + ';' else ACloseDoors := ACloseDoors + IntToStr(i) +';'; end;
WriteLn('Open doors: ' + AOpenDoors); WriteLn('Close doors: ' + ACloseDoors);
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>
Piet
Perl 6
unoptimized
<lang perl6>my @doors = False xx 101;
($_ = !$_ for @doors[0, * + $_ ...^ * > 100]) for 1..100;
say "Door $_ is ", <closed open>[ @doors[$_] ] for 1..100;</lang>
optimized
<lang perl6>say "Door $_ is open" for map {$^n ** 2}, 1..10;</lang>
Here's a version using the cross meta-operator instead of a map:
<lang perl6> say "Door $_ is open" for 1..10 X** 2;</lang>
This one prints both opened and closed doors:
<lang perl6>say "Door $_ is ", <closed open>[.sqrt == .sqrt.floor] for 1..100;</lang>
PicoLisp
unoptimized <lang PicoLisp>(let Doors (need 100)
(for I 100 (for (D (nth Doors I) D (cdr (nth D I))) (set D (not (car D))) ) ) (println Doors) )</lang>
optimized <lang PicoLisp>(let Doors (need 100)
(for I (sqrt 100) (set (nth Doors (* I I)) T) ) (println Doors) )</lang>
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)
PL/I
<lang PL/I> declare door(100) bit (1) aligned; 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; </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] -bxor 1 }
} foreach($doornum in 1..100) {
if($doors[($doornum-1)] -eq $true) {"$doornum open"} else {"$doornum closed"}
}</lang>
unoptimized Pipeline
<lang powershell>$doors = 1..100 | ForEach-Object {0} 1..100 | ForEach-Object { $a=$_;1..100 | Where-Object { -not ( $_ % $a ) } | ForEach-Object { $doors[$_-1] = $doors[$_-1] -bxor 1 }; if ( $doors[$a-1] ) { "door opened" } else { "door closed" } } </lang>
unoptimized Pipeline 2
<lang powershell>$doors = 1..100 | ForEach-Object {0} $visited = 1..100 1..100 | ForEach-Object { $a=$_;$visited[0..([math]::floor(100/$a)-1)] | Where-Object { -not ( $_ % $a ) } | ForEach-Object { $doors[$_-1] = $doors[$_-1] -bxor 1;$visited[$_/$a-1]+=($_/$a) }; if ( $doors[$a-1] ) { "door opened" } else { "door closed" } } </lang>
PureBasic
unoptimized <lang purebasic>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()</lang>
optimized <lang PureBasic>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()</lang>
Output:
Following Doors are open: 1, 4, 9, 16, 25, 36, 49, 64, 81, 100,
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'
</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>
One liner
<lang python>print '\n'.join(['Door %s is %s' % (i, ('closed', 'open')[(i**0.5).is_integer()]) for i in xrange(1, 101)])</lang>
Q
unoptimized <lang q>`closed`open mod[;2]count each 1 _ group raze where each 0=t mod\:/:t:til 101</lang>
optimized <lang q>`closed`open (1+til 100) in `int$xexp[;2] 1+til 10</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>
optimized <lang r>x <- rep(1, 100) for (i in 1:100-1) {
x <- xor(x, rep(c(rep(0,i),1), length.out=100))
} which(!x)</lang>
REALbasic
<lang realbasic>//True=Open; False=Closed
Dim doors(100) As Boolean //Booleans default to false For j As Integer = 1 To 100 For i As Integer = 1 to 100 If i Mod j = 0 Then doors(i) = Not doors(i) End If Next Next</lang>
REBOL
Unoptimized
<lang rebol>doors: array/initial 100 'closed repeat i 100 [
door: at doors i forskip door i [change door either 'open = first door ['closed] ['open]]
]</lang>
Optimized
<lang rebol>doors: array/initial 100 'closed repeat i 10 [doors/(i * i): 'open] </lang>
Retro
<lang Retro>: squared ( n-n ) dup * ;
- doors ( n- ) [ 1 repeat 2over squared > 0; drop dup squared putn space 1+ again ] do 2drop ;
100 doors</lang>
REXX
<lang 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 </lang> Here is another version, solving it the hard way.
<lang rexx> /*REXX program to solve the 100 door puzzle, the hard-way version. */
parse arg doors . /*get the first argument (# of doors.) */ if doors== then doors=100 /*not specified? Then assume 100 doors*/
/* 0 = closed. */ /* 1 = open. */
door.=0 /*assume all that all doors are closed.*/
do j=1 for doors /*process a pass-through for all doors.*/ do k=j by j to doors /* ... every Jth door from this point. */ door.k=\door.k /*toggle the "openness" of the door. */ end end
say say 'After' doors "passes, the following doors are open:" say
do n=1 for doors if door.n then say right(n,20) end
say </lang> Output:
After 100 passes, the following doors are open: 1 4 9 16 25 36 49 64 81 100
Here is another version, solving it the easy way (version 1). <lang rexx> /*REXX program to solve the 100 door puzzle, the easy-way version. */
parse arg doors . /*get the first argument (# of doors.) */ if doors== then doors=100 /*not specified? Then assume 100 doors*/
/* 0 = closed. */ /* 1 = open. */
door.=0 /*assume all that all doors are closed.*/ say say 'For the' doors "doors problem, the following doors are open:" say
do j=1 for doors /*process an easy pass-through. */ p=j*j /*square the door number. */ /*An alternative: P=J**2 */ if p>doors then leave /*if too large, we're done. */ say right(p,20) end
say </lang> Output:
For the 100 doors problem, the following doors are open: 1 4 9 16 25 36 49 64 81 100
Here is another easy-way solution (version 2), but for 1,000 doors. <lang rexx> /*REXX program to solve the 100 door puzzle, the easy-way version 2.*/
parse arg doors . /*get the first argument (# of doors.) */ if doors== then doors=100 /*not specified? Then assume 100 doors*/
doors=1000
/* 0 = closed. */ /* 1 = open. */
door.=0 /*assume all that all doors are closed.*/ say say 'For the' doors "doors problem, the open doors are:" say
do j=1 for doors while j*j<=doors /*limit the pass-throughs. */ say right(j**2,20) end
say </lang> Output:
For the 1000 doors problem, the open doors are: 1 4 9 16 25 36 49 64 81 100 121 144 169 196 225 256 289 324 361 400 441 484 529 576 625 676 729 784 841 900 961
Ruby
unoptimized; Ruby-way
(I tried to show as much of Ruby syntax and conventions as possible. Of course, instead of a class you could just use generic true/false, but that's not the point, is it?)
<lang ruby>class Door
attr_reader :state
def initialize
@state=:closed
end
def close; @state=:closed; end def open; @state=:open; end
def closed?; @state==:closed; end def open?; @state==:open; end
def toggle if closed? open else close end end
def to_s; @state.to_s; end end
doors=Array.new(100){Door.new} 1.upto(100) do |multiplier| doors.each_with_index do |door, i| door.toggle if (i+1)%multiplier==0 end end
doors.each_with_index{|door, i| puts "Door #{i+1} is #{door}."}</lang>
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 (1..n).each do |i|
puts "Door #{i} is #{i**0.5 == (i**0.5).round ? "open" : "closed"}"
end </lang>
generic true/false, with another way of handling the inner loop demonstrating Range#step <lang ruby> doors = [false] * 100 100.times do |i|
(i .. doors.length).step(i+1) do |j| doors[j] = !doors[j] end
end puts doors.inspect
</lang>
S-lang
<lang s-lang>variable door,
isOpen = Char_Type [101], pass;
for (door = 1; door <= 100; door++) {
isOpen[door] = 0;
}
for (pass = 1; pass <= 100; pass++) {
for (door = pass; door <= 100; door += pass) { isOpen[door] = not isOpen[door]; }
}
for (door = 1; door <= 100; door++) {
if (isOpen[door]) { print("Door " + string(door) + ":open"); } else { print("Door " + string(door) + ":close"); }
}</lang>
Sather
<lang 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;</lang>
SAS
<lang sas>data _null_;
open=1; close=0; array Door{100}; do Pass = 1 to 100; do Current = Pass 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>
Unoptimized, using Morphs <lang smalltalk> | 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. </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>
TUSCRIPT
<lang tuscript> $$ MODE TUSCRIPT DICT doors create COMPILE LOOP door=1,100
LOOP pass=1,100 SET go=MOD (door,pass) DICT doors lookup door,num,cnt,status IF (num==0) THEN SET status="open" DICT doors add door,num,cnt,status ELSE IF (go==0) THEN IF (status=="closed") THEN SET status="open" ELSE SET status="closed" ENDIF DICT doors update door,num,cnt,status ENDIF ENDIF ENDLOOP
ENDLOOP ENDCOMPILE DICT doors unload door,num,cnt,status </lang> Output (variable status):
status = * 1 = open 2 = closed 3 = closed 4 = open 5 = closed 6 = closed 7 = closed 8 = closed 9 = open 10 = closed 11 = closed 12 = closed 13 = closed 14 = closed 15 = closed 16 = open 17 = closed 18 = closed 19 = closed 20 = closed 21 = closed 22 = closed 23 = closed 24 = closed 25 = open 26 = closed 27 = closed 28 = closed 29 = closed 30 = closed 31 = closed 32 = closed 33 = closed 34 = closed 35 = closed 36 = open 37 = closed 38 = closed 39 = closed 40 = closed 41 = closed 42 = closed 43 = closed 44 = closed 45 = closed 46 = closed 47 = closed 48 = closed 49 = open 50 = closed 51 = closed 52 = closed 53 = closed 54 = closed 55 = closed 56 = closed 57 = closed 58 = closed 59 = closed 60 = closed 61 = closed 62 = closed 63 = closed 64 = open 65 = closed 66 = closed 67 = closed 68 = closed 69 = closed 70 = closed 71 = closed 72 = closed 73 = closed 74 = closed 75 = closed 76 = closed 77 = closed 78 = closed 79 = closed 80 = closed 81 = open 82 = closed 83 = closed 84 = closed 85 = closed 86 = closed 87 = closed 88 = closed 89 = closed 90 = closed 91 = closed 92 = closed 93 = closed 94 = closed 95 = closed 96 = closed 97 = closed 98 = closed 99 = closed 100 = open
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>
Optimised version <lang bash>#!/bin/bash
for i in {1..100}; do
door[$i*$i]=1 [ -z ${door[$i]} ] && echo "$i closed" || echo "$i open"
done</lang>
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. <lang Ursala>#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)</lang> optimized version: <lang Ursala>#import nat
- cast %nL
main = product*tiiXS iota10</lang> output:
<1,4,9,16,25,36,49,64,81>
VBScript
Unoptimized <lang VBScript>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</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>
Wrapl
Unoptimized <lang wrapl>MOD Doors;
IMP Agg.Table; IMP Std.String; IMP IO.Terminal USE Out;
VAR door <- {}; EVERY door[1:to(100), "closed"];
DEF toggle(num) door[num] <- door[num] = "open" => "closed" // "open";
EVERY WITH pass <- 1:to(100), num <- pass:to(100, pass) DO toggle(num);
Out:write('Doors {door @ String.T}.');
END Doors.</lang> Optimized <lang wrapl>MOD Doors;
IMP IO.Terminal USE Out;
DEF open <- ALL 1:to(100) ^ 2 \ $ <= 100; DEF closed <- ALL 1:to(100) \ NOT $ IN open;
Out:write('Doors {open} are open.\n'); Out:write('Doors {closed} are closed.\n');
END Doors.</lang>
XSLT
See: 100 doors/XSLT
Yorick
Unoptimized, iterative <lang yorick>doors = array(0, 100); for(i = 1; i <= 100; i++)
for(j = i; j <= 100; j += i) doors(j) ~= 1;
print, where(doors);</lang>
Unoptimized, vectorized <lang yorick>doors = array(0, 100); for(i = 1; i <= 100; i++)
doors(i::i) ~= 1;
print, where(doors);</lang>
Optimized <lang yorick>print, indgen(1:long(sqrt(100)))^2</lang>
All of the above output:
[1,4,9,16,25,36,49,64,81,100]
- Programming Tasks
- Solutions by Programming Task
- 6502 Assembly
- 8086 Assembly
- ABAP
- ActionScript
- Ada
- Aikido
- ALGOL 68
- AmigaE
- AppleScript
- Argile
- AutoHotkey
- AWK
- Batch File
- BASIC
- Befunge
- C
- C Runtime
- C++
- C sharp
- CLIPS
- Clojure
- COBOL
- CoffeeScript
- ColdFusion
- Common Lisp
- D
- Dylan
- E
- Ela
- Emacs Lisp
- Erlang
- Euphoria
- Factor
- Falcon
- Fantom
- Forth
- Fortran
- F Sharp
- GAP
- Go
- Golfscript
- Groovy
- Haskell
- HaXe
- HicEst
- Icon
- Unicon
- Inform 7
- Informix 4GL
- Io
- Ioke
- J
- Java
- JavaScript
- K
- Liberty BASIC
- Logo
- Lua
- M4
- Mathematica
- MATLAB
- MAXScript
- Metafont
- MIPS Assembly
- MMIX
- Modula-2
- Modula-3
- MOO
- MUMPS
- Objeck
- OCaml
- Octave
- Oz
- PARI/GP
- Pascal
- PHP
- Perl
- Piet
- Perl 6
- PicoLisp
- PL/I
- Pop11
- PowerShell
- PureBasic
- Python
- Q
- R
- REALbasic
- REBOL
- Retro
- REXX
- Ruby
- S-lang
- Sather
- SAS
- Scala
- Scheme
- Slate
- Smalltalk
- SETL
- Tcl
- Tk
- TI-89 BASIC
- TUSCRIPT
- UNIX Shell
- Ursala
- VBScript
- Vedit macro language
- Visual Basic .NET
- Wrapl
- XSLT
- Yorick