정상혁정상혁

지난 8월4~7일 여름휴가로 일본 동경을 갔다왔습니다. 동경의 번화가를 구경하는데 4일을 다 썼어도 아쉬움이 남을 정도로 구경거리가 많더군요. 그 와중에서도 일본에는 어떤 컴퓨터 책들이 나오고 있을까 하는 호기심을 참지못해 시부야에 있는 북퍼스트와 신주쿠의 기노쿠니아 서점을 가 봤었습니다. 사실 일본어는 '다꾸앙','와리바시','덴뿌라' 수준의 단어 밖에 모르고, 글자는 전혀 읽을 줄 모르기 때문에 책표지만 감상할 수 밖에 없었습니다. 그래도 전체적인 기류는 명확히 와 닿았기에 인상적인 경험이였습니다.

kinoku.jpg

book1st.jpg

역시 웹2.0, SNS(Social Network Service), SEM(Search Engine Marketing), SEO(Search Engine Optimization, 검색엔진 최적화) 에 관련된 책들이 컴퓨터 서적코너의 앞 쪽을 차지하고 있었습니다. 인터넷 비지니스에 대한 열기는 일본에서도 뜨겁게 느껴집니다. SEM/SEO는 아직 국내에서는 책 제목으로 붙일 정도로 보편화된 용어는 아닌 것 같은데 일본에서는 어느정도 알려졌나 봅니다.

web2-0-magazine.jpg

web2-0_1.jpg

web2-0_2.jpg

web2-0_3.jpg

구글, Yahoo, Myspace등 인터넷 서비스에 대한 책들도 많이 보였습니다. 서비스 사용자를 위한 이용법에 대한 내용도 있었지만, 개발자를 위한 Open API관련 서적이 눈에 띄게 많았습니다.

google.jpg

google-api.jpg

google-yahoo.jpg

google_1.jpg

Goole earth에 관한 책들이 몇권보이는 마지막 사진은 컴퓨터 코너가 아닌 기노쿠니아 서점의 지학(땅 지 ,배울 학) 코너에서 찍은 것입니다.

Second life에 대한 책도 진열장의 잘 보이는 곳을 차지하고 있었습니다.

secondlife.jpg

secondLife3.jpg

secondLife1.jpg

마지막 사진은 기노쿠니아 원서 코너에서 찍은 것인데, 그 서점에는 컴퓨터 원서가 몇권 없었음데도 second life와 my space에 대한 책이 보였습니다.

Java관련 책들을 찾아봤는데 반가운 책들을 여러 권 발견했습니다. Effective Java, Expert one and one J2EE developement, Core J2EE pattern.

java_1.jpg

java_2.jpg

java_3.jpg

Eclipse 관련 서적들도 비중있게 자리가 배정되어 있었습니다.

eclipse_1.jpg

eclipse_2.jpg

오픈소스 프레임웍에 관한 책들도 찾아보았습니다.

opensource-fw.jpg

spring2-0.jpg

그리고 국내에서는 보기 힘든 책의 번역판도 보였습니다.

Inside JavaOS라는 책인데 돌아와서 찾아보니 yes24에서는 외국서적으로도 검색이 안 되는 책이더군요.

java-os.jpg

함수형 언어 Haskell에 대한 책도 발견했습니다.

haskel.jpg

두 서점을 통들어 가장 강렬한 느낌을 주었던 책장은 북퍼스트에서 본 Oreli 원서를 모아둔 곳이였습니다. 잘 정리된 모습이 깔끔해 보이네요.

oreli_1.jpg

그리고 바로 옆에는 Oreli 번역서를 모아둔 책장이 있었습니다.

oreli_2.jpg

Ruby를 일본 사람이 만들었으니 Ruby관련 서적이 한 칸은 차지하고 있지 않을까 하는 상상을 했었으나, 그렇지는 않았습니다. 국내와 비슷해보이는 몇권 정도였던것 같습니다.

더 구경을 하고 하고 싶었으나,불만 가득한 아내 때문에 적당히 보고 나올 수 밖에 없었습니다. 여기까지 와서 이런 데를 오는 것이 이해가 안 간다고 하더군요. 아내가 옷가게 구경할 때 저는 불평없이 있었다는 사실이 별로 고려되지 않은 듯합니다.

서점에 가기 전에도 일본이 우리나라보다 인구가 많아서 시장이 넓으니 국내보다 풍부한 책들을 구경할 수 있을 것이라고 예상을 했었습니다. 둘러보니 역시 다양한 책들을 많이 볼 수 있었습니다 . Inside JavaOS 같은 책은 소수만이 관심을 가질 것으로 보이고 , 국내에서 이런 책을 읽고 싶은 사람은 아마 아마존에서 직접 주문해서 읽을 것입니다. 이런 전문적인 책들이 일본에 번역판이 나왔다는 사실은 크게 부럽지는 않습니다. 그러나 Open API에 대한 책에 대해서는 아쉬움이 남습니다. 이런 책도 역시 적극적인 의지를 가진 사람은 인터넷으로 자료를 찾거나 원서를 사 보면서 공부할 수 있겠죠. 하지만 영어로 읽는 것이 속도가 늦거나 약간이라도 저렴한 번역서를 사고 싶어하는 사람들을 끌어드릴 수 있다면 더욱 그 분야가 활성화 될 수 있을 것입니다. 즉 대중화하는 것이 의미가 있는 분야의 책은 수요를 보다 도전적으로 창출해야 한다고 생각합니다.

계속 open API를 예로 들면, '막연하게 뭔가 open api로 프로그램을 만들고 싶다는 사람이 있다. 그런데 그는 바쁜 업무를 핑계로 적극적으로 관련 자료를 찾아보지 못하고 있다. 우연찮게 그는 서점을 갔다가 Open API에 대한 책을 발견하고 사게 된다. 그는 출퇴근 길이나 집에서 뒹구는 시간에 그 책을 읽고 더욱 흥미를 느끼고, 결국에는 매쉬업 서비스를 만들어서 공개하게 된다.' 와 같은 일도 생길 수 있지 않겠습니까?

다음, 네이버, 스프링노트 같은 국내 서비스의 open API에 대한 입문서가 있다면 좋겠다는 생각도 듭니다.

아뭏든 읽지도 못하는 책을 신나게 구경하게 온, 특이한 경험이였습니다.

정상혁정상혁

지난 2월에 회사 워크샵에서 풀었던 나선형 배열 문제에 대한 글을 올린 적이 있었지요. ( http://blog.benelog.net/901106 )

알고보니 xper.org에도 이 문제가 올라와 있더군요 (http://xper.org/wiki/seminar/SpiralArray). 거기에 가면 다른 분들의 풀이도 많이 볼 수 있습니다. 저는 이 문제를 실컷 가지고 논 후에 더 이상 손 댈 것이 없다고 느껴질때 다른 분들의 풀이를 꼼꼼히 볼 생각입니다.

우연찮게 이에 대한 확장된 문제를 다른 블로그에서 보게 되었습니다. (http://blog.naver.com/itioma?Redirect=Log&logNo=40040118386 ). 그 포스트에서 본 문제에는 아래의 조건들이 더 추가되어 있었습니다.

  • 작성된 코드에서 한 글자만 수정해서 '숫자는 1씩 늘어난다’를 '숫자는 2씩 늘어난다’로 바꾸시오.

  • 코드에서 한 문장만 수정해서 시작점 좌표(x,y)를 마음대로 바꿀 수 있도록 만드시오

  • 코드에서 한 문장만 수정해서 시작할 때의 진행방향을 (위/아래/왼쪽/오른쪽 중에서 ) 바꿀 수 있도록 만드시오

  • 배열의 크기를 마음대로 정할 수 있도록 만드시오.

  • 코드에서 한 문장만 수정해서 '시계방향으로 90도’를 '반시계 반향으로 90’도로 바꾸시오

  • 코드에서 swich 문이나 else 문을 이용한 3단계 이상의 조건분기가 있다면 모두 제거하시오.

  • 코드에서 한 글자만 수정해서 '한칸씩 진행하며’를 두칸씩 건너뛰며’로 바꾸시오.

  • 1~7에서 수정되었던 문장/값/변수들이모두 하나의 함수 또는 블럭안에 존재하도록 고치시오.

그리고 숫자는 1에서 시작하고 , 채워지지 않은 부분이 있다면 0으로 표시된다는 점이 제가 처음에 풀었던 문제와 다르네요.

확장된 조건을 다 수용할 수 있는 만족시키는 코드를 다시 한번 만들어보았습니다.

소스코드

public class MatrixMain {
    public static void main(String[] args) {
       System.out.println("0.원래의 matrix");
       ExtMatrix mp = new ExtMatrix(6,6);
       mp.print();

       System.out.println("1.숫자가 2씩 늘어나게");
       mp.setIncrement(2);
       mp.print();

       System.out.println("2.시작점을 1,1로");
       mp.setStartPoint(1, 1);
       mp.print();

       System.out.println("3.시작방향을 아래부터");
       mp.setStartDirection(ExtMatrix.DOWN);
       mp.print();

       System.out.println("4.배열크기 바꾸는건 생성할때 파라미터 바꾸면 됨.");
       System.out.println();
       System.out.println("5.반시계 반향으로 회전");
       mp.setReverseClockWiseTurn();
       mp.print();

       System.out.println("6.그런 조건 분기 없음.");
       System.out.println();

       System.out.println("7.한칸씩이 아닌 두칸씩 건너뛰며.");
       mp.setMoveStep(2);
       mp.print();
    }
}

public class ExtMatrix {
    public static final int RIGHT = 0;
    public static final int DOWN = 1;
    public static final int LEFT = 2;
    public static final int UP  = 3;

    private static final int INIT_VALUE = 0;
    private static final int CLOCK_WISE_TURN = 1;
    private static final int REVERSE_CLOCK_WISE_TURN = -1;

    private int m = 0;
    private int n = 0;
    private int startX = 0;
    private int startY = 0;
    private int[][] matrix;
    private int startDirection = RIGHT;
    private int increment = 1;
    private int moveStep = 1;

    private int turnDirection = CLOCK_WISE_TURN;


    public ExtMatrix(int m, int n){
        this.m = m;
        this.n = n;
        matrix = new int[m][n];
    }

    public void setIncrement(int increment){
        this.increment = increment;
    }

    public void setStartPoint(int startX, int startY){
        this.startX = startX;
        this.startY = startY;
    }

    public void setClockWiseTurn(){
        turnDirection = CLOCK_WISE_TURN;

    }

    public void setReverseClockWiseTurn(){
        turnDirection = REVERSE_CLOCK_WISE_TURN;
    }

    public void setMoveStep(int moveStep){
        this.moveStep = moveStep;
    }

    public void setStartDirection(int startDirection){
        this.startDirection = startDirection;
    }

    public void print(){
        locateNumbers();
        for (int i=0;i< m ;i++){
            for (int j=0;j<n;j++) System.out.print(matrix[i][j] + "\t");
            System.out.println();
       }
       System.out.println();
    }

    private void locateNumbers() \{
       init();
       int[] startPosition = new int[]\{startX,startY};
       matrix[startX][startY]= 1;
       int direction = startDirection;
       while(move(startPosition ,direction)) direction= getNextDirection(direction);
    }

    private void init(){
        for (int i=0;i< m ;i++){
            for (int j=0;j<n;j++) matrix[i][j] = INIT_VALUE;
        }
    }

    private boolean move(int[] position, int direction){
        int nowNumber = matrix[position[0]][position[1]];
        boolean moved = false;
        int[] nextPosition =getNextPosition(position,direction);
        while(isMovable(nextPosition[0],nextPosition[1])){
            moved = true;
            nowNumber+= increment;
            position[0] = nextPosition[0];
            position[1] = nextPosition[1];
            matrix[position[0]][position[1]]= nowNumber;
            nextPosition = getNextPosition(position,direction);
        }
        return moved;
    }

    private int[] getNextPosition(int[] position,int direction){
        int x = position[0];
        int y = position[1];
        if (direction == RIGHT) y+= moveStep;
        else if (direction == DOWN) x+= moveStep;
        else if (direction == LEFT) y-= moveStep;
        else if (direction == UP)  x-= moveStep;
        return new int[]\{x,y};
    }

    private int getNextDirection(int direction){
        direction+= turnDirection;
        if (direction<0) direction+=4;
        direction = direction %4;
        return direction;
    }

    private boolean isMovable(int x, int y){
        if (x>=m) return false;
        if (y>=n) return false;
        if (x<0) return false;
        if (y<0) return false;
        if (matrix[x][y]!= INIT_VALUE) return false;
        return true;
    }
}

방향을 int로 나타내는 것이 처음에는 좋은 아이디어 라고 생각했는데 mp.setStartDirection(ExtMatrix.DOWN); 부분을 보니 타입안전열거형이나 enum을 도입해야지 좀더 코드가 이뻐질 것 같네요.

정상혁정상혁

1st JavaScript editor의 공짜 사용기한이 얼마 남지 않아서 JavaScript로 빨리 뭐라도 만들어봐야 겠다는 생각이 들었습니다. 프로젝트 업무 중에는 그런 일이 보이지 않아서 회사의 다른 팀원들이 하고 있는 스터디 모임에서 나왔던 http://blog.naver.com/i1j1jsy/70011900056뉴질랜드 화폐문제를 풀어보았습니다.

문제

원래 제가 문제를 봤던 URL : http://rdp.ahamoment.org/wiki/Dollars

요약

뉴질랜드 화폐는 $100, $50, $20, $10, $5 지폐와 $2, $1, 50센트, 20센트, 10센트, 5센트 동전으로 이루어져 있다. 주여진 합계액에 대해서 몇 가지의 방법으로 돈을 구성할 수 있는지 세는 프로그램을 작성해라.

예) 20센트는 4가지 방법으로 만들수 있다. : 1개의 20센트, 2개의 10센트, 10센트+ 2개의 5센트, 4개의 5센트

원래 문제는 파일에서 입력값을 받게 되어 있지만, JavaScript로 풀다보니 그 부분은 생략했습니다. 직접 풀어보실 분들은 풀이를 나중에 보세요~

풀이

<script language="JavaScript" type="text/JavaScript" src="app/jsUnitCore.js"></script>
<script language="JavaScript" type="text/JavaScript">

    var unitList = [100, 50, 20, 10, 5, 2, 1, 0.5, 0.2, 0.1, 0.05];


    function countWaysOfAmount(totalMoneyAmount, unitIndex, ways)\{
        if (unitIndex == null) unitIndex = 0;
        if (ways == null) ways = 0;

        var unit = unitList[unitIndex];
        var moneyLeft = totalMoneyAmount;

        do\{
          if (moneyLeft == 0) ways++;
          else if (unitIndex < unitList.length)
            ways = countWaysOfAmount(moneyLeft,unitIndex+1,ways);
          moneyLeft =  Math.round( (moneyLeft - unit) *100) /100;
        } while(moneyLeft >= 0)
        return ways;
    }

    function testDollars()\{
        assertEquals("0.05", countWaysOfAmount(0.05), 1);
        assertEquals("0.1",  countWaysOfAmount(0.1 ), 2);
        assertEquals("0.15", countWaysOfAmount(0.15), 2);
        assertEquals("0.2",  countWaysOfAmount(0.2 ), 4);
        assertEquals("2",  countWaysOfAmount(2), 293);
    }

    alert(countWaysOfAmount(2));
</script>

코드를 더 다듬을 여지가 있는 것 같지만 일단 올려봅니다

moneyLeft = Math.round( (moneyLeft - unit) *100) /100; 부분은 다른 언어들과 마찬가지로 JavaScript에서도 소숫점 계산이 정확하지 않아서 붙인 부분입니다. 이걸 안해주니 5가 나와야하는 값이 4.999999 같이 나오더군요. 이 문제만 아니면 moneyLeft -= unit 으로 간단하게 쓸수 있는데 말이죠, Java로 이걸 짠다면 BigDecimal을 쓰거나 별도의 클래스를 정의해야겠죠.

JSUnit 없이 로컬에서 수정해 보실 분은 `<script language="JavaScript" type="text/JavaScript" src="app/jsUnitCore.js"></script> 부분과 테스트 메서드만 지우고 돌려 보시면 되겠습니다.

Internet Explorer Developer Toolbar, 1st JavaScript editor, JSUnit, FireBug 를 한꺼번에 써서 코딩하니 이클립스가 부럽지 않았습니다 ^^; 그리고 jsunit에서 debug("로그"); 로 찍어보는 것도 상당히 유용했구요. 1st JavaScript edtior나 FireBug가 모두 디버거 기능이 훌륭하지만 반복문의 값을 추적하는 것은 break point 거는 것보다는 로그로 쫙 찍어보는 것이 편하더군요.