U E D R , A S I H C RSS

Spiral Array/Leonardong

ํ”“œ ˜คฅดธฐ

2h 20m 28s
•„ด””–ดŠ” JuNe „ ฐฐ€ งํ–ˆ˜ ฒƒด‹ค.( €ฒˆ žฐ” ปจํŸฐŠค—„œ ˜€˜€..) ํ•œ ฒˆ ‚˜„ ํ˜•œกœ „ํ–‰˜Š” ฒƒ„ ฐ™€ ธตœกœ ณธ‹ค. ทธŸฌฉด €žฅ ฐ”ชฝ€ 1ธต, ‹คŒ •ˆชฝ€ 2ธต ดŸฐ ‹œกœ •ˆชฝœกœ ฐˆˆ˜ก †’ด€ †’•„„‹ค. ํ•œ ‚ฌžŒด ํ”“œ ํ•œ ฐ”ํ€Œณ  ‹คŒ ธตœกœ ˜ฌ€ฉด„œ ž‹ ด “ค €˜ ณณด ช‡ ฒˆงธธ€, ขŒํ‘œŠ” ฌด—‡ธ€ ธฐ–ตํ•œ‹ค. ํ•œ ธต„ ‹ค Œฉด ‹œž‘ํ–ˆ˜ žฆฌกœ Œ•„˜คธฐ •Œฌธ— ค‘ณตํ•ด„œ ธฐ–ตํ•œ ขŒํ‘œŠ” €šฐณ  ‹คŒ ธตœกœ ด™ํ•œ‹ค.

ํ•˜€งŒ —ฌ€ป ทธŸฌํ•œ  ‘ฒ•„ •Œณ „œ„ TDDกœ ํ’€€ ชปํ–ˆ—ˆ‹ค. งคฒˆ ‚˜„ ํ˜• "ํ–‰ ฌ"— –ด–ปฒŒ ˆซž ƒˆธธ€งŒ ƒฐํ–ˆธฐ •Œฌธด‹ค. ทธŸฌ‹ค ณด‹ˆ 2ฐจ› ฐฐ—ด˜ ธŠค กฐž‘ํ•˜Š” ˆ˜€—„œ ƒฐด ฒ—–ด‚˜งˆ ชปํ–ˆ‹ค. ํ•˜€งŒ ‚ฌ‹ค€ ›€งž„(ด „˜ ธŠค กฐž‘), ›€งธ  “ค, ํ–‰ ฌ„ ”ฐกœ ƒฐํ•  ˆ˜ žˆ—ˆ‹ค. •„! ด ‡ฒŒ ํ…ŒŠคํŠธ ํ•˜ฉด ˜ฒ ตฌ‚˜!

TDDกœ ํ’€—ˆ‹คŠ”  ด ธฐ˜‹ค. ฒ˜Œ€„„ˆฌด ฉ”„œ“œ –ด””— †ํ•˜ฒŒ ํ•  € ณ ํ•˜€ •Šณ  ‹œž‘ํ•œ ฒƒด œ šฉํ–ˆ‹ค. ทธ ฒฐกœ ˜ˆ „ ฐ™œฉด ƒฐํ•˜€ ชปํ–ˆ„ Directionํดž˜Šค™€ ทธ ํ•˜œ„ ํดž˜Šค€ ํƒ„ƒํ–ˆ‹ค. ˜ํ•œ ํ–‰ ฌ€ ตœข… ฒฐ„  €žฅํ•˜ณ  ณด—ฌŠ” ข…˜ ทฐฒ˜Ÿ “ฐ˜€‹ค.

ํ˜„žฌŠ” ํ–‰ ฌ ตฌ„ด „ํšจœจ ด‹ค. ›€ง˜€˜ ธฐก„ €€ณ  ํ–‰ ฌ„ ตฌ„ํ•˜ธฐ ฐ˜ณตํ•œ‹ค.ดฒƒ„ ˆ˜ •ํ•  •Œ €” ํšจœจ œกœ ž‘™ํ•˜ฒŒ งŒ“ค–ด•ฒ ‹ค. Moverํดž˜Šค, Arrayํดž˜Šค˜ ข…ฃŒ€‚ฌ, ํ…ŒŠคํŠธ €ดŠคŠ” ํ™•‹คํžˆ Refactoringด ํ•„š”ํ•˜‹ค.


~cpp
import unittest

ROW = 0
COL = 1

class Direction:
    def move(self, coordinate, board):
        if ( board.isWall( self.next(coordinate) ) ):    
            return coordinate
        return self.next(coordinate)

class Down(Direction):
    def next(self, coordinate):
        return (coordinate[ROW] + 1, coordinate[COL])
    
class Up( Direction ):
    def next(self, coordinate):
        return (coordinate[ROW] - 1, coordinate[COL])

class Right(Direction):
    def next(self, coordinate):
        return (coordinate[ROW], coordinate[COL] + 1 )

class Left(Direction):
    def next(self, coordinate):
        return (coordinate[ROW], coordinate[COL] - 1 )


class Board:
    def __init__(self):
        self.size = 0
    def setBoundary( self, start, end ):
        self.start = start
        self.end = end
    def isWall( self, coordinate ):
        if ( coordinate[ROW] < self.start ):
            return True
        elif ( coordinate[ROW] >= self.end ):
            return True
        elif ( coordinate[COL] < self.start ):
            return True
        elif ( coordinate[COL] >= self.end ):
            return True
        return False
    def decreaseBoundary(self, amount):
        self.setBoundary( self.start+amount, self.end-amount )
    

class Mover:
    def __init__(self):
        self.coordinate = (0,0)
        self.moveCount = 0
        self.history = []
    def position(self):
        return self.coordinate
    def goStraight(self, direction, board):
        while ( not self.coordinate == direction.move(self.coordinate, board) ):
            self.history.append( Point( self.coordinate, self.moveCount+1 ) )
            self.moveCount += 1
            self.coordinate = direction.move( self.coordinate, board )
        self.history.append( Point( self.coordinate, self.moveCount+1 ) )
    def mark(self, point, value):
        point.value = value
    def _setMoveCount(self, count):
        self.moveCount = count
    def _setPosition(self, coordinate):
        self.coordinate = coordinate
    def getHistory(self):
        return self.history
    def turnRound(self, board):
        self.goStraight( Right(), board )
        self.goStraight( Down(), board )
        self.goStraight( Left(), board )
        self.goStraight( Up(), board )
        board.decreaseBoundary(1)
        self.eraseLastMovement()
        self._setPosition( self.nextFloor() )
    def nextFloor(self):
        return (self.coordinate[ROW]+1, self.coordinate[COL]+1 )
    def eraseLastMovement(self):
        self._setMoveCount( self.history.pop().value - 1 )
        
class Point:
    def __init__(self, coordinate, value):
        self.coordinate = coordinate
        self.value = value

class Array:
    def __init__(self, size):
        self.matrix = []
        for i in range(size):
            self.matrix.append( [Point((-1,-1),-1)] * size )
    def isAllFilled(self):
        for row in self.matrix:
            for point in row:
                if ( point.value < 0 ):
                    return False
        return True
    def _fillAll(self):
        for row in self.matrix:
            for point in row:
                point.value = 1
    def get(self, row, col):
        return self.matrix[row][col]
    def construct(self, pointList):
        for p in pointList:
            self.matrix[p.coordinate[ROW]][p.coordinate[COL]] = p
    def printValues(self):
        for row in self.matrix:
            for point in row:
                print point.value,
                print "\t",
            print

class SpiralArrayTest(unittest.TestCase):
    def setUp(self):
        self.board = Board()
        self.size = 10
        self.board.setBoundary(start=0, end=self.size)
        self.mover = Mover()
        self.array = Array( self.size )
    def testMoveDown(self):
        self.assertEquals( (1,0), Down().move( (0,0), self.board ) )
        self.assertEquals( (self.size-1,0), Down().move( (self.size-1,0), self.board ) )
    def testMoveUp(self):
        self.assertEquals( (0,0), Up().move( (0,0), self.board ) )
        self.assertEquals( (self.size-1,0), Up().move( (self.size,0), self.board ) )
    def testIsWall(self):
        self.assertEquals( False, self.board.isWall( (0,0) ) )
        self.assertEquals( True, self.board.isWall( (-1,0) ) )
        self.assertEquals( True, self.board.isWall( (0,-1) ) )
        self.assertEquals( True, self.board.isWall( (0,self.size) ) )
        self.assertEquals( True, self.board.isWall( (self.size,0) ) )
    def testGoStraightRight(self):
        self.mover.goStraight(Right(), self.board)
        self.assertEquals( (0,self.size-1), self.mover.position() )        
    def testMark(self):
        point = Point((0,0),0)
        self.mover._setMoveCount(1)
        self.mover.mark( point, self.mover.moveCount )
        self.assertEquals( 1, point.value )
    def testStorePointCoordinate(self):
        self.mover.goStraight( Down(), self.board )
        points = self.mover.getHistory()
        self.assertEquals( (self.size-1,0), points.pop().coordinate )
        self.assertEquals( (self.size-2,0), points.pop().coordinate )
    def testStoreMoveCount(self):
        self.mover._setPosition((self.size-1, self.size-1))
        self.mover.goStraight( Left(), self.board )
        points = self.mover.getHistory()
        self.assertEquals( self.size, points.pop().value )
        self.assertEquals( self.size-1, points.pop().value )
    def testTurnRound(self):
        self.mover._setPosition( (0,0) )
        self.mover.turnRound(self.board)
        self.assertEquals( (1,0), self.mover.getHistory().pop().coordinate )
    def testIsFinished(self):
        self.assertEquals( False, self.array.isAllFilled() )
        self.array._fillAll()
        self.assertEquals( True, self.array.isAllFilled() )        
    def testConstructArray(self):
        self.mover._setPosition( (0,0) )
        self.mover.turnRound(self.board)
        self.array.construct( self.mover.getHistory() )
        self.assertEquals( (0,0), self.array.get(0,0).coordinate )
        self.assertEquals( (self.size-1, self.size-1),
                           self.array.get(self.size-1, self.size-1).coordinate )
if __name__ == "__main__":
##    unittest.main()
    inputSize = input()
    board = Board()
    board.setBoundary(0, inputSize )
    array = Array(inputSize)
    mover = Mover()
    mover._setPosition((0,0))
    while not ( array.isAllFilled() ):
        mover.turnRound(board)
        array.construct(mover.getHistory())
    array.printValues()

ํ”“œ ˜คฅดธฐ Refacotring

1h 58m 26s

€‚œ ฒˆ ฆฌํŒฉํ† ง Œ€ƒด—ˆ˜ Moverํดž˜Šค, Arrayํดž˜Šค˜ ข…ฃŒ€‚ฌ, ํ…ŒŠคํŠธ €ดŠค ฆฌํŒฉํ† ง ํ–ˆ‹ค. ํ…ŒŠคํŠธ €ดŠค™€ Arrayํดž˜ŠคŠ” ‰ฝฒŒ ฆฌํŒฉํ† ง ํ•  ˆ˜ žˆ—ˆ‹ค. ํ•˜€งŒ Moverํดž˜Šค †Œ€Š”ฐ ˜คž˜  ธ‹ค.

goStraight  „ „ „€ Directionํดž˜Šค ดšฉํ•ด„œ ด™ํ•œ(ฒฝ„ งŒ‚˜ฉด ด™ํ•˜€ •ŠŒ) œ„˜ –ป–ด‚ดณ , ด™ํ•œ ธฐก„  €žฅํ•˜Š” ํ˜•‹ด—ˆ‹ค. ฒฝ— Œ€ํ•œ €‚ฌ€ ˜Š” ฒƒ ฐ™•„ mover—„œ ฐ”กœ ฒฝ„ €‚ฌํ•˜ณ  ฒฝ— “ค–ด„œฉด ข…ฃŒํ•˜Š” ฒƒœกœ งŒ“ค—ˆ‹ค. ทธŸฌณ  ณด‹ˆ ”ฐกœ šดํŠธ ํ•  ํ•„š”€ —†–ด moveCount€ˆ˜ —†•ด‹ค. mover€ ข…ฃŒ กฐ„ €‚ฌํ•˜Š”ฐ board „“ดงŒํ ด™ํ–ˆœฉด ‚˜Š” ฒƒดธฐ •Œฌธด‹ค.

ทธŸฐฐ ฒฝ— “ค–ด„œ• ข…ฃŒํ•˜‹ค ณด‹ˆŒ mover ฒฝ— “ค–ด€ธฐ  „— œ„˜กœ ˜Œ ค†“•„• ํ–ˆ‹ค. ทธž˜„œ direction— ชจ‘ previous ฉ”„œ“œ€ ƒ‹ค. ํ•œฐ ‹คŒ ฒˆ goStraight ํ•  •ŒŠ” ดด™ํ–ˆ˜ ธฐกด ‚จ•„žˆฒŒ ˜—ˆ‹ค. ทธž˜„œ งคฒˆ goStraight ํ•  •Œงˆ‹ค งˆ€ง‰ ด™ ธฐก„ ‚ญ œํ–ˆ‹ค. ทธŸฌ‹คณด‹ˆ boardํฌธฐ€ 1 ฒฝšฐŠ” ด™ํ•œ ธฐกด ชจ‘ €›Œ ธ„ฆฌŠ” ฒƒด •„‹Œ€. กฐžกํ•˜€งŒ ˜ˆ™ธ ฒ˜ฆฌ ํ•ด—ˆ‹ค.

ฒฝ„กฐด ฐธ ฌ˜ํ•˜‹คŠ” ฒƒ„ Šˆ‹ค. ‹œž‘ „ –ด–ปฒŒ ํ•  ฒƒธ€? ํ•œฐธ„ ํ—คงค‹คณด‹ˆ ” ‚˜€ ฐฉฒ•ด žˆŠ”ฐ„ ฐพงˆ ชปํ•˜Š” ฒƒ ฐ™‹ค.

ฝ”“œ •ˆ—„œ ํ—คงคธฐ ณด‹คŠ”  •ํ™•ํžˆ ƒฐ„  •ฆฌํ•ด„œ ตฌํ˜„ํ•ด• ํ•œ‹ค. ดฒƒ ํ•ดณดณ   €ฒƒ ํ•ดณดŠ” ‚ฌด— ‹œ„ด „ˆฌด งŽด ํ˜Ÿฌฐ”‹ค. ฒฐตญ— ‹ต€ ‚˜™”€งŒ, ดณด‹ค ฆฌ ํ•  ˆ˜ žˆ„ ฒƒด‹ค.


~cpp

import unittest

ROW = 0
COL = 1

class Direction:
    pass
class Down(Direction):
    def next(self, coordinate):
        return (coordinate[ROW] + 1, coordinate[COL])
    def previous(self, coordinate):
        return Up().next( coordinate )
    
class Up( Direction ):
    def next(self, coordinate):
        return (coordinate[ROW] - 1, coordinate[COL])
    def previous(self, coordinate):
        return Down().next( coordinate )

class Right(Direction):
    def next(self, coordinate):
        return (coordinate[ROW], coordinate[COL] + 1 )
    def previous(self, coordinate):
        return Left().next( coordinate )

class Left(Direction):
    def next(self, coordinate):
        return (coordinate[ROW], coordinate[COL] - 1 )
    def previous(self, coordinate):
        return Right().next( coordinate )


class Board:
    def __init__(self, initialSize):
        self.size = initialSize
        self.setBoundary( 0, self.size )
    def setBoundary( self, start, end ):
        self.start = start
        self.end = end
    def isWall( self, coordinate ):
        if ( coordinate[ROW] < self.start ):
            return True
        elif ( coordinate[ROW] >= self.end ):
            return True
        elif ( coordinate[COL] < self.start ):
            return True
        elif ( coordinate[COL] >= self.end ):
            return True
        return False
    def decreaseBoundary(self, amount):
        self.setBoundary( self.start+amount, self.end-amount )
    

class Mover:
    def __init__(self):
        self.coordinate = (0,0)
        self.history = []
    def position(self):
        return self.coordinate
    def goStraight(self, direction, board):
        while ( not board.isWall( self.coordinate ) ):
            self.history.append( Point( self.coordinate, self.moveCount() ) )
            self.coordinate = direction.next( self.coordinate )
        self.coordinate = direction.previous( self.coordinate )
    def mark(self, point, value):
        point.value = value
    def moveCount(self):
        return len( self.history ) + 1
    def setPosition(self, coordinate):
        self.coordinate = coordinate
    def getHistory(self):
        return self.history
    def turnRound(self, board):
        for direction in [Right(), Down(), Left()]:
            self.goStraight( direction, board )
            self.eraseLastMovement()
        self.goStraight( Up(), board )
        if ( board.end - board.start != 1 ):
            self.eraseLastMovement()
        self.setPosition( self.nextFloor() )
    def nextFloor(self):
        return (self.coordinate[ROW]+1, self.coordinate[COL]+1 )
    def eraseLastMovement(self):
        self.history.pop()
    def isFinished( self, board ):
        return board.size * board.size < self.moveCount()
    def lastHistory( self ):
        return self.history[-1]
            
        
class Point:
    def __init__(self, coordinate, value):
        self.coordinate = coordinate
        self.value = value

class Array:
    def __init__(self, size):
        self.matrix = []
        for i in range(size):
            self.matrix.append( [Point((-1,-1),-1)] * size )
    def get(self, row, col):
        return self.matrix[row][col]
    def construct(self, pointList):
        for p in pointList:
            self.matrix[p.coordinate[ROW]][p.coordinate[COL]] = p
    def printValues(self):
        for row in self.matrix:
            for point in row:
                print point.value,
                print "\t",
            print

class SpiralArrayTest(unittest.TestCase):
    def setUp(self):
        self.size = 10
        self.board = Board(self.size)
        self.board.setBoundary(start=0, end=self.size)
        self.mover = Mover()
        self.array = Array( self.size )


class DirectionTest(SpiralArrayTest):
    def testNext(self):
        self.assertEquals( (1,0), Down().next( (0,0) ) )

    def testPrevious(self):
        self.assertEquals( (0,0), Down().previous( (1,0) ) )

class BoardTest(SpiralArrayTest):
    def testIsWall(self):
        self.assertEquals( False, self.board.isWall( (0,0) ) )
        self.assertEquals( True, self.board.isWall( (-1,0) ) )
        self.assertEquals( True, self.board.isWall( (0,-1) ) )
        self.assertEquals( True, self.board.isWall( (0,self.size) ) )
        self.assertEquals( True, self.board.isWall( (self.size,0) ) )

class MoverTest(SpiralArrayTest):
    def testGoStraightRight(self):
        self.mover.goStraight(Right(), self.board)
        self.assertEquals( (0,self.size-1), self.mover.position() )

    def testStorePointCoordinate(self):
        self.mover.goStraight( Down(), self.board )
        points = self.mover.getHistory()
        self.assertEquals( (self.size-1,0), points.pop().coordinate )
        self.assertEquals( (self.size-2,0), points.pop().coordinate )
    def testStoreMoveCount(self):
        self.mover.setPosition((self.size-1, self.size-1))
        self.mover.goStraight( Left(), self.board )
        points = self.mover.getHistory()
        self.assertEquals( self.size, points.pop().value )
        self.assertEquals( self.size-1, points.pop().value )
    def testStoreMovementWhenTurnRoundAndBoudaryNotOne(self):
        self.mover.setPosition( (0,0) )
        self.mover.turnRound(self.board)
        points = self.mover.getHistory()
        self.assertEquals( (self.size-1) * 4 , len( points ) )
    def testStoreMovementWhenTurnRoundAndBoudaryOne(self):
        self.board = Board( initialSize = 1 )
        self.mover.setPosition( (0,0) )
        self.mover.turnRound(self.board)
        points = self.mover.getHistory()
        self.assertEquals( 1 , len( points ) )
    def testTurnRoundWithBoundary0(self):
        self.mover.setPosition( (0,0) )
        self.mover.turnRound(self.board)
        self.assertEquals( (1,0), self.mover.lastHistory().coordinate )
    def testIsFinished(self):
        self.board = Board( initialSize = 1 )
        self.assertEquals( False, self.mover.isFinished( self.board ) )
        self.mover.turnRound( self.board )
        self.assertEquals( True, self.mover.isFinished( self.board ) )
    def testRun(self):
        self.board = Board( initialSize = 3 )
        self.mover.setPosition( (0,0) )
        self.mover.turnRound(self.board)
        self.assertEquals( (1,0), self.mover.lastHistory().coordinate )
        self.assertEquals( (1,1), self.mover.position() )

        self.board.decreaseBoundary(1)
        self.mover.turnRound(self.board)
        self.assertEquals( (1,1), self.mover.lastHistory().coordinate )

class ArrayTest(SpiralArrayTest):    
    def testConstructArray(self):
        self.mover.setPosition( (0,0) )
        self.mover.turnRound(self.board)
        self.array.construct( self.mover.getHistory() )
        self.assertEquals( (0,0), self.array.get(0,0).coordinate )
        self.assertEquals( (self.size-1, self.size-1),
                           self.array.get(self.size-1, self.size-1).coordinate )
        

    
if __name__ == "__main__":
    unittest.main()
    inputSize = input()
    board = Board(inputSize)
    mover = Mover()
    mover.setPosition((0,0))
    while ( not mover.isFinished( board ) ):
        mover.turnRound(board)
        board.decreaseBoundary(1)
    array = Array(inputSize)
    array.construct(mover.getHistory())
    array.printValues()

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2021-02-07 05:28:05
Processing time 0.0217 sec