Path Finder #4: where are you?, CodeWars Kata

Path Finder #4: where are you?

Hey, Path Finder, where are you?

 

My Solution

Path Finder 시리즈의 자바 버전은 #4가 마지막입니다. 문제를 보고 굉장히 황당했습니다. 디렉션이 전혀 없기 때문입니다. 힌트는 오로지 테스트 코드였습니다. Point 클래스는 문제에서 주어집니다.

	@Parameters
    public static Collection<Object[]> prepTests() {
        return Arrays.asList(new Object[] { "", new Point(0, 0) }, new Object[] { "RLrl", new Point(0, 0) },
                new Object[] { "r5L2l4", new Point(4, 3) }, new Object[] { "r5L2l4", new Point(0, 0) },
                new Object[] { "10r5r0", new Point(-10, 5) }, new Object[] { "10r5r0", new Point(0, 0) });
    }

테스트 코드를 보면 동일한 입력값에 대해 다른 결과가 나오는 것을 알 수 있습니다. 이것을 보고 이 문제를 풀기 위해서는 멤버 변수를 static변수를 통해 상태값을 유지할 필요가 있다는 것을 알 수 있습니다.

다음으로 풀어야 할 것은 r, l, R, L 문자의 쓰임새입니다. 옆에 숫자가 나오는 경우도 있기 때문에 방향을 바꾸는 지시어라는 것을 알 수 있습니다. 결국 (x, y)로 이뤄진 2차원의 좌표상에서 방향을 움직여가며 이동하게 되는 것이기 때문에 `r, l, R, L이 각각 어떤 방향으로 이동하는지만 알면 되는 문제였습니다. 결과적으로 r은 오른쪽으로 방향 전환, l은 왼쪽으로 방향 전환, RL은 반대방향으로 전환이었습니다. 이것을 코드로 옮기기 시작했습니다.

#3의 BP를 보고 객체지향적인 설계를 좀 더 신경쓰기로 마음 먹었습니다. enum Direction을 생성하고 void move(Point now, int move)를 통해 현재 포인트에서 이동하는 것을 구현했고요, void changeDirection(char flag)로 방향 전환을 구현했습니다.

여기까지만 하면 나머지는 쉽습니다. 입력값을 한 글자씩 읽어가면서 `r, l, R, L이 나오면 방향을 전환하고 숫자가 나오면 그만큼 움직여줍니다. 황당하면서도 재밌는 유형이긴 했는데 문제 해석이 너무 시간을 많이 쏟아 이런 문제는 추천드리고 싶진 않네요.

솔루션 코드

테스트 코드

import java.awt.Point;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.regex.Pattern;

// Do your magic...!

public class PathFinder {    
    
    enum Direction {
        LEFT, UP, RIGHT, DOWN;

        static LinkedList<Direction> directions = new LinkedList<Direction>();
        static {
            directions.addAll(Arrays.asList(Direction.values()));
        }

        public static void move(Point now, int move) {
            Direction peek = directions.peek();
            if (peek == UP) {
                now.setLocation(now.getX(), now.getY() + move);
            } else if (peek == RIGHT) {
                now.setLocation(now.getX() + move, now.getY());
            } else if (peek == DOWN) {
                now.setLocation(now.getX(), now.getY() - move);
            } else if (peek == LEFT) {
                now.setLocation(now.getX() - move, now.getY());
            }
        }

        public static void changeDirection(char flag) {
            if (flag == 'r') {
                directions.addLast(directions.removeFirst());
            } else if (flag == 'R') {
                directions.addLast(directions.removeFirst());
                directions.addLast(directions.removeFirst());
            } else if (flag == 'L') {
                directions.addLast(directions.removeFirst());
                directions.addLast(directions.removeFirst());
            } else {
                directions.addFirst(directions.removeLast());
            }
        }
    }

    static Point now = new Point(0, 0);

    public static Point iAmHere(String path) {
        StringBuffer sb = new StringBuffer();

        for (int i = 0; i < path.length(); i++) {
            if (Pattern.matches("r|l|R|L", path.charAt(i) + "")) {
                if (sb.length() > 0) {
                    int move = Integer.parseInt(sb.toString());
                    sb.setLength(0);
                    Direction.move(now, move);
                }
                Direction.changeDirection(path.charAt(i));
            } else {
                sb.append(path.charAt(i));
            }
        }

        if (sb.length() > 0) {
            int move = Integer.parseInt(sb.toString());
            sb.setLength(0);
            Direction.move(now, move);
        }

        return now;
    }
}

 

Best Practice

BP는 주어진 Point클래스를 상속한 Me라는 클래스를 활용했습니다. 이 클래스를 static으로 선언하여 상태를 유지했고, move, back, turn메소드를 통해 방향전환과 이동을 처리했네요. 이 BP 역시 객체지향 설계가 돋보이는 코드입니다.

import java.util.regex.*;
import java.awt.Point;


public class PathFinder {
    
    private static final Pattern P_PATH = Pattern.compile("\\d+|.");
    private static final Me      ME     = new Me(0,0);
    
    private static class Me extends Point {
        
        private int dx=-1, dy=0;
        private Me(int x, int y)  { super(x,y); }
        
        private Point here()      { return new Point(this); }
        
        private void move(int n)  { x += n*dx; y += n*dy; }
        private void back()       { dx*=-1; dy*=-1; }
        private void turn(char c) { int oldX = dx;
                                    dx = dy==0   ? 0 : dy   * (c=='l'?-1:1);
                                    dy = oldX==0 ? 0 : oldX * (c=='r'?-1:1); }
        
        @Override public String toString() { return String.format("x,y=%d,%d (dx,dy=%d,%d)", x,y,dx,dy); }
    }
    
    
    public static Point iAmHere(String path) {
    
        Matcher m = P_PATH.matcher(path);
        while (m.find()) {
            String v = m.group();
            if      ("RL".contains(v)) ME.back();
            else if ("rl".contains(v)) ME.turn(v.charAt(0));
            else                       ME.move(Integer.parseInt(v));
        }
        return ME.here();
    }
}

 

728x90
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기