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