100 doors: Difference between revisions

From Rosetta Code
Content added Content deleted
(added ocaml)
Line 311: Line 311:
format ("Door % is open?: %\n") i (root == (root as integer))
format ("Door % is open?: %\n") i (root == (root as integer))
)
)

=={{header|OCaml}}==
===unoptimized===
<pre>
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))
</pre>

===optimized===
<pre>
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))
</pre>


=={{header|Perl}}==
=={{header|Perl}}==

Revision as of 11:03, 10 March 2008

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.

Problem: You have 100 doors in a row that are all initially closed. You make 100 passes by the doors, starting with the first door every time. 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.

Ada

unoptimized

with Ada.Text_Io; use Ada.Text_Io;

procedure Doors is
   type Door_State is (Closed, Open);
   type Door_List is array(Positive range 1..100) of Door_State;
   The_Doors : Door_List := (others => Closed);
begin
   for I in 1..100 loop
      for J in The_Doors'range loop
         if J mod I = 0 then
            if The_Doors(J) = Closed then
                The_Doors(J) := Open;
            else
               The_Doors(J) := Closed;
            end if;
         end if;
      end loop;
   end loop;
   for I in The_Doors'range loop
      Put_Line(Integer'Image(I) & " is " & Door_State'Image(The_Doors(I)));
   end loop;
end Doors;

optimized

with Ada.Text_Io; use Ada.Text_Io;
with Ada.Numerics.Elementary_Functions; use Ada.Numerics.Elementary_Functions;

procedure Doors_Optimized is
   Num : Float;
begin
   for I in 1..100 loop
      Num := Sqrt(Float(I));
      Put(Integer'Image(I) & " is ");
      if Float'Floor(Num) = Num then
         Put_Line("Opened");
      else
         Put_Line("Closed");
      end if;
   end loop;
end Doors_Optimized;

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)

BASIC

Works with: QuickBasic version 4.5

unoptimized

DIM doors(0 TO 99)
FOR pass = 0 TO 99
	FOR door = pass TO 99 STEP pass + 1
		PRINT doors(door)
		PRINT NOT doors(door)
		doors(door) = NOT doors(door)
	NEXT door
NEXT pass
FOR i = 0 TO 99
	PRINT "Door #"; i + 1; " is ";
	IF NOT doors(i) THEN
		PRINT "closed"
	ELSE
		PRINT "open"
	END IF
NEXT i

optimized

DIM doors(0 TO 99)
FOR door = 0 TO 99
	IF INT(SQR(door)) = SQR(door) THEN doors(door) = -1
NEXT door
FOR i = 0 TO 99
	PRINT "Door #"; i + 1; " is ";
	IF NOT doors(i) THEN
		PRINT "closed"
	ELSE
		PRINT "open"
	END IF
NEXT i

C++

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

unoptimized

#include <iostream>
#include <ostream>

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.\n" : " is closed.\n");
}

optimized

This optimized version makes use of the fact that finally only the doors with square index are open, as well as the fact that .

#include <iostream>
#include <ostream>

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.\n";
      square += increment;
      increment += 2;
    }
    else
      std::cout << " is closed.\n";
  }
}

The following ultra-short optimized version demonstrates the flexibility of C++ loops, but isn't really considered good C++ style:

#include <iostream>
#include <ostream>

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.\n" : " is closed.\n");
}

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 

unoptimized

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

optimized

DOOR flip_o(inout DOOR d) {
  d[] = CLOSE ;
  for(int i= 1 ; i*i <= d.length  ; i++)
    d[i*i-1] = OPEN ;
  return d ;  
}

test program:

void main() {
  DOOR d ;
  d.length = 100 ;
  writefln(d.flip_u()) ;
  writefln(d.flip_o()) ;  
}

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

Haskell

unoptimized

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)

optimized

(without using square roots)

gate :: Eq a => [a] -> [a] -> [Door]
gate (x:xs) (y:ys) | x == y  =  Open   : gate xs ys
gate (x:xs) ys               =  Closed : gate xs ys
gate []     _                =  []

run n = gate [1..n] [k*k | k <- [1..]]

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

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."));
		}
	}
}

optimized

public class Doors {
	public static void main(String[] args) {
		boolean[] doors = new boolean[100];
		for(int pass = 0; pass < 10; pass++){
			doors[(pass + 1) * (pass + 1) - 1] = true;
		}
		for(int i = 0; i < 100; i++){
			System.out.println("Door #" + (i + 1) + " is " + (doors[i] ? 
						"open." : "closed."));
		}
	}
}

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

OCaml

unoptimized

let max_doors = 100

let show_doors =
  Array.iteri (fun i x -> Printf.printf "Door %d is %s\n" (i+1)
                                        (if x then "open" else "closed"))

let flip_doors doors =
  for i = 1 to max_doors do
    let rec flip idx =
      if idx < max_doors then begin
        doors.(idx) <- not doors.(idx);
        flip (idx + i)
      end
    in flip (i - 1)
  done;
  doors

let () =
  show_doors (flip_doors (Array.make max_doors false))

optimized

let optimised_flip_doors doors =
  for i = 1 to int_of_float (sqrt (float_of_int max_doors)) do
    doors.(i*i - 1) <- true
  done;
  doors

let () =
  show_doors (optimised_flip_doors (Array.make max_doors false))

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

lvars i;
lvars doors = {% for i from 1 to 100 do false endfor %};
for i from 1 to 100 do
   for j from i by i to 100 do
      not(doors(j)) -> doors(j);
   endfor;
endfor;
;;; Print state
for i from 1 to 100 do
   printf('Door ' >< i >< ' is ' ><
            if doors(i) then 'open' else 'closed' endif, '%s\n');
endfor;

optimized

lvars i, ri, rri, s;
for i from 1 to 100 do
    sqrt(i) -> ri;
    round(ri) -> rri;
    if rri = ri then 'open' else 'closed' endif -> s;
    printf('Door ' >< i >< ' is ' >< s, '%s\n');
endfor;

Python

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

unoptimized

close = 0
open = 1
doors = [close] * 100
  
for i in range(100):
    for j in range(i, 100, i+1):
        doors[j] = open if doors[j] is close else close
    print "Door %d:" % (i+1), 'open' if doors[i] else 'close'
  
for k, door in enumerate(doors):
    print "Door %d:" % (k+1), 'open' if door else 'close'

optimized

A version that only visits each door once:

for i in xrange(1, 101):
    root = i ** 0.5
    print "Door %d:" % i, 'open' if root == int(root) else 'close'

Ruby

unoptimized

n = 100
Open = "open"
Closed = "closed"
def Open.f
    Closed
end
def Closed.f
    Open
end
doors = [Closed] * (n+1)
for mul in 1..n
    for x in 1..n
        doors[mul*x] = (doors[mul*x] || break).f
    end
end
doors.each_with_index {
    |b, i|
    puts "Door #{i} is #{b}" if i>0
}

optimized

n = 100
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
}

Scheme

unoptimized

(define *max-doors* 100)

(define (show-doors doors)
  (let door ((i 0)
             (l (vector-length doors)))
    (cond ((= i l) 
           (newline))
          (else 
           (printf "~nDoor ~a is ~a" 
                   (+ i 1) 
                   (if (vector-ref doors i) "open" "closed"))
           (door (+ i 1) l)))))

(define (flip-doors doors)
  (define (flip-all i)
    (cond ((> i *max-doors*) doors)
          (else 
           (let flip ((idx (- i 1)))
             (cond ((>= idx *max-doors*) 
                    (flip-all (+ i 1))) 
                   (else 
                    (vector-set! doors idx (not (vector-ref doors idx)))
                    (flip (+ idx i))))))))
  (flip-all 1))

(show-doors (flip-doors (make-vector *max-doors* #f)))

optimized

(define (optimised-flip-doors doors)
  (define (flip-all i)
    (cond ((> i (floor (sqrt *max-doors*))) doors)
          (else 
           (vector-set! doors (- (* i i) 1) #t)
           (flip-all (+ i 1)))))
  (flip-all 1))

(show-doors (optimised-flip-doors (make-vector *max-doors* #f)))


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