100 doors kata solution

19
My attempt to solve 100 Doors kata Steven Mak Thursday, 6 June, 13

Upload: steven-mak

Post on 23-Jun-2015

807 views

Category:

Business


0 download

TRANSCRIPT

Page 1: 100 doors kata solution

My attempt to solve 100 Doors kataSteven Mak

Thursday, 6 June, 13

Page 2: 100 doors kata solution

Change history

2

Do you have experience that you think your code is already the best solution, but after a while you can think of ways improving it? This does happen to me with this kata. That’s why I decided to add this slide showing history of the changes.

I might not be updating the code here often, especially these changes didn’t change the overall thinking or analysis of the problem. You can refer to the source here: https://github.com/tcmak/kata-100-doors

• 2013-06-04: Initial solution, rather procedural• 2013-06-05: Apply recursion for shouldOpenInRound method

Thursday, 6 June, 13

Page 3: 100 doors kata solution

100 Doors Kata

3

Reference: http://rosettacode.org/wiki/100_doors

To quote how they describe the problem:

“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?”

(Spoiler warning: you might not want to continue if you haven’t done this kata before)

Thursday, 6 June, 13

Page 4: 100 doors kata solution

First test - all doors are close at the beginning

4

it("All doors closed at the beginning", function() local doors = doors(0) for i,door in ipairs(doors) do assert.is_false(door) end end)

Thursday, 6 June, 13

Page 5: 100 doors kata solution

Simple implementation

5

local function doors(round) local doors = {} for i = 1, NUM_DOORS do doors[i] = false end return doorsend

NUM_DOORS = 100(my apology for using global variables for now)

Thursday, 6 June, 13

Page 6: 100 doors kata solution

Second test - all doors opened after the first pass

6

it("All doors open after the first round", function() local doors = doors(1) for i,door in ipairs(doors) do assert.is_true(door) end end)

Thursday, 6 June, 13

Page 7: 100 doors kata solution

Another Simple implementation and extract doors initialization to its own function

7

local function doors(round) local doors = initializeDoors() if round == 0 then return doors end for i = 1, NUM_DOORS do doors[i] = true end return doorsend

Thursday, 6 June, 13

Page 8: 100 doors kata solution

Third test - only alternative doors opened

8

it("Second round, alternative doors are open", function() local doors = doors(2) for i= 1,NUM_DOORS, 2 do assert.is_true(doors[i]) end for i= 2,NUM_DOORS, 2 do assert.is_false(doors[i]) end end)

Thursday, 6 June, 13

Page 9: 100 doors kata solution

Let’s fake it for now as if I know the solution

9

local function doors(round) local doors = initializeDoors() if round == 0 then return doors end

for i = 1, NUM_DOORS do if (i+1) % round == 0 then doors[i] = true end end

return doorsend

You are right, at this moment I still have no clue how the complete solution is like,

or any pattern related to the problem

Thursday, 6 June, 13

Page 10: 100 doors kata solution

Fourth test - what is it???

10

it("All doors closed at the beginning", function() ... ... end)

it("All doors open after the first round", function() ... ... end)

it("Second round, alternative doors are open", function() ... ... end)

It does not seem to have any easy way to describe the pattern in the next test

Thursday, 6 June, 13

Page 11: 100 doors kata solution

Fourth test - get a piece of paper and do some math

11

Doors Pass 1 Pass 2 Pass 3

1 Open Open Open

2 Open Close Close

3 Open Open Close

4 Open Close Close

5 Open Open Open

6 Open Close Open

7 Open Open Open

8 Open Close Close

9 Open Open Close

10 Open Close Close

Thursday, 6 June, 13

Page 12: 100 doors kata solution

Fourth test - think deeper

12

Doors Pass 1 Pass 2 Pass 3 flips#

1 Open Open Open 1

2 Open Close Close 2

3 Open Open Close 2

4 Open Close Close 2

5 Open Open Open 1

6 Open Close Open 3

7 Open Open Open 1

8 Open Close Close 2

9 Open Open Close 2

10 Open Close Close 2

Do you see the pattern:

Whether a door is closed or opened depends on the number of numbers, limited by the number of passes, which can divide this door number.

For example: 9 is divisible by 1 and 36 is divisible by 1, 2, and 3

If this number of factors is odd, then it will be opened, otherwise it is closed

Thursday, 6 June, 13

Page 13: 100 doors kata solution

Put the original kata aside for now and do this little kata

13

For any integer N, how many integers, which are less than or equal to another given integer R, that can divide N

(for 100-door kata, we are only concerned if it is odd or even)

For example:

N R result Odd?1 1 1 TRUE2 2 2 FALSE3 3 2 FALSE4 2 2 FALSE4 4 3 TRUE

Thursday, 6 June, 13

Page 14: 100 doors kata solution

I will leave the process of solving this kata for your own pleasure

14

local function shouldOpenInRound(number, round) local shouldOpen = false for factor=1,round do if number % factor == 0 then shouldOpen = not shouldOpen end end return shouldOpenend

Thursday, 6 June, 13

Page 15: 100 doors kata solution

Fourth test - Let’s continue

15

it("Third round, [1 0 0 0 1 1]", function() local originalNumOfDoors = NUM_DOORS NUM_DOORS = 6 local doors = doors(3)

assert.is_true(doors[1]) assert.is_false(doors[2]) assert.is_false(doors[3]) assert.is_false(doors[4]) assert.is_true(doors[5]) assert.is_true(doors[6]) NUM_DOORS = originalNumOfDoors end)

Thursday, 6 June, 13

Page 16: 100 doors kata solution

Now it’s an easy piece of cake

16

local function doors(round) local doors = initializeDoors() if round == 0 then return doors end for i = 1, NUM_DOORS do if shouldOpenInRound(i, round) then doors[i] = true end end

return doorsend

Thursday, 6 June, 13

Page 17: 100 doors kata solution

Refactor and remove redundant code

17

NUM_DOORS = 100

local function shouldOpenInRound(number, round) local shouldOpen = false for factor=1,round do if number % factor == 0 then shouldOpen = not shouldOpen end end return shouldOpenend

local function doors(round) local doors = {} for i = 1, NUM_DOORS do doors[i] = shouldOpenInRound(i, round) end return doorsend

Thursday, 6 June, 13

Page 18: 100 doors kata solution

Fifth test - confirming this is right

18

it("100th round, 1,4,9,16...100", function() local doors = doors(100) for i=1,NUM_DOORS do if math.sqrt(i) == math.ceil(math.sqrt(i)) then assert.is_true(doors[i]) else assert.is_false(doors[i]) end end end)

Yay! things pass as expected. Smile!

Thursday, 6 June, 13

Page 19: 100 doors kata solution

In retrospect...• What if I follow TPP strictly?• Is this the most optimal solution?• Shall this code be more OO or functional?• Can these functions be shorter/cleaner?

Updates can be found at: https://github.com/tcmak/kata-100-doors

Thank you for spending time on this.More feedback can be sent to:

19

Steven Mak 麥天志[email protected]://www.odd-e.comhttps://twitter.com/stevenmakhttp://weibo.com/odde

Odd-e Hong Kong Ltd.Steven Mak 麥天志Agile CoachHong KongEmail: [email protected]: www.odd-e.comTwitter: stevenmak

Thursday, 6 June, 13