Above: An overhead view of the house in one of the tests. The green outline indicates the path taken by K
A mouse named K has found a new home on Ash Tree Lane. K wants to know the size of the interior of the house (which consists of just one room). K is able to measure precise distances in any direction he runs. But K is wary of open spaces and will only run alongside walls, as mice tend to do. In this house the walls always connect at right angles.
K's plan is to run alongside the walls, traversing the entire perimeter of the room, starting and ending at K's mousehole. K memorizes the path as an alternating sequence of distance traveled and directional turn. Your task is to write a function that will find the area of the house interior when given K's path.
Input
Your function will receive a string as an argument. The string will consist of turns (`L` or `R`, for `left` and `right`, respectively) and positive integers, in an alternating sequence. `L`/`R` represents the turn direction made by K, and the integers mark the number of distance units to move forward.
Output
Your function should return an integer representing the area of the house, based on K's path. If K's path is not a valid path, return `null` or `None`.
Invalid Paths
A path is invalid if it meets any of the following criteria:
- the path intersects/overlaps itself (with the exception of the mousehole when completing the loop); see examples of path fragments below
- the path doesn't complete the loop back to the mousehole
- the mousehole is located along the straight path of a wall (K's mousehole must be located at a convex/concave corner position to be valid)
Invalidating overlap path fragment examples
- Example A: Perpendicular intersection `...5L2L3L4...`
- Example B: Point of overlap `...2L2R3R2R3L2...`
- Example C: Parallel overlap `...4L2R2R3R4R1L2...`
Test Example
The circled K and green arrow indicate the starting position and direction as given in the example test below
```python
mouse_path('4R2L1R5R9R4R4L3') # 49
```
Additional Details
- K's path will always consist of fewer than `500` turns
- The area of the house (when valid) will always be less than `2**32`
- Full Test Suite: `12` fixed tests and `150` random tests
- Use Python 3+ for the Python translation
- For JavaScript, most built-in prototypes are frozen, except `Array` and `Function`
- All inputs will be of valid type and pattern (that is, it will alternate between distance moved and directional turn)
- NOTE: the random test generator may, on very rare occasions, throw an error (around 0.01% of the time, based on my observation); if you get an error pointing to the random test function, try running your solution again.
- This kata was inspired by [Kafka](https://en.wikipedia.org/wiki/A_Little_Fable) and [Danielewski](https://en.wikipedia.org/wiki/House_of_Leaves)
If you enjoyed this kata, be sure to check out my other katas
import re

def check_intersection(y, x0, x1, segments):
    return any(x0 <= x <= x1 and y0 <= y <= y1 for x, y0, y1 in segments)

def mouse_path(s):
    sort_coords = lambda x0, x1: (x0, x1) if x0 <= x1 else (x1, x0)
    dx, dy = 1, 0
    x, y = 0, 0
    hs, vs = [], []
    area = 0
    s = re.split('([LR])', s)
    n = len(s)
    for i in range(n):
        cmd = s[i]
        if cmd == 'L':
            dx, dy = -dy, dx
        elif cmd == 'R':
            dx, dy = dy, -dx
        else:
            d = int(cmd)
            x1, y1 = x + d * dx, y + d * dy
            if dy == 0:
                a, b = sort_coords(x, x1)
                if i == n - 1:
                    return None
                if check_intersection(y, a, b, vs[:-1]):
                    return None
                hs.append((y, a, b))
            else:
                a, b = sort_coords(y, y1)
                if i == n - 1:
                    hs = hs[1:]
                if check_intersection(x, a, b, hs[:-1]):
                    return None
                vs.append((x, a, b))
            area += x * y1 - x1 * y
            x, y = x1, y1
    return abs(area // 2) if x == 0 and y == 0 else None
import re

def check_intersection(y, x0, x1, segments):
    return any(x0 <= x <= x1 and y0 <= y <= y1 for x, y0, y1 in segments)

def mouse_path(s):
    sort_coords = lambda x0, x1: (x0, x1) if x0 <= x1 else (x1, x0)
    dx, dy = 1, 0
    x, y = 0, 0
    hs, vs = [], []
    area = 0
    s = re.split('([LR])', s)
    n = len(s)
    for i in range(n):
        cmd = s[i]
        if cmd == 'L':
            dx, dy = -dy, dx
        elif cmd == 'R':
            dx, dy = dy, -dx
        else:
            d = int(cmd)
            x1, y1 = x + d * dx, y + d * dy
            if dy == 0:
                a, b = sort_coords(x, x1)
                if i == n - 1:
                    return None
                if check_intersection(y, a, b, vs[:-1]):
                    return None
                hs.append((y, a, b))
            else:
                a, b = sort_coords(y, y1)
                if i == n - 1:
                    hs = hs[1:]
                if check_intersection(x, a, b, hs[:-1]):
                    return None
                vs.append((x, a, b))
            area += x * y1 - x1 * y
            x, y = x1, y1
    return abs(area // 2) if x == 0 and y == 0 else None