import unittest
from snake import *


wall = [Point(0, 1), Point(0, 2), Point(1, 2),
        Point(2, 2), Point(3, 2), Point(3, 3)]
snake = [Point(5, 2), Point(6, 2), 
        Point(7, 2), Point(8, 2)]

class WorldTest(unittest.TestCase):

    def setUp(self):
        self.world = World.load(file('fixtures/simple.snake'))
        self.world.putApple(Point(0, 0))

    def testRegIndex(self):
        line = "# # 012"
        self.assertEquals({0:'#', 2:'#'},
                            regIndex(line, r'#'))
        self.assertEquals({4:'0', 5:'1', 6:'2'},
                            regIndex(line, r'\d'))

    def testLoad(self):
        world = self.world

        self.assertEquals(set(wall), set(world.wall()))
        self.assertEquals(snake, world.snake())

        for segment in wall:
            self.assertEquals(WALL, world[segment])

        for segment in snake:
            self.assertEquals(SNAKE, world[segment])
    

    def testAdvanceNoDir(self):
        world = self.world
        status, point = world.advance()

        self.assertEquals(TICK, status)
        self.assertEquals(snake[0].left(), point)
        self.assertEquals(snake[0].left(), world.head())

    def testAdvanceDirection(self):
        world = self.world
        start = snake[0]

        status, point = world.advance(UP)
        self.assertEquals(start.up(), world.head())
        self.assertEquals(TICK, status)

        status, point = world.advance(UP)
        self.assertEquals(start.up().up(),
                    world.head())
        self.assertEquals(TICK, status)

        status, point = world.advance(LEFT)
        self.assertEquals(start.up().up().left(),
                    world.head())
        self.assertEquals(TICK, status)

        status, point = world.advance(LEFT)
        self.assertEquals(
                start.up().up().left().left(),
                world.head())
        self.assertEquals(TICK, status)

        status, point = world.advance(DOWN)
        self.assertEquals(
                start.up().left().left(),
                world.head())
        self.assertEquals(TICK, status)
            
        status, point = world.advance(RIGHT)
        self.assertEquals(
                start.up().left(),
                world.head())
        self.assertEquals(TICK, status)

    def testCantBiteItselfStupidly(self):
        world = self.world
        start = snake[0]
        status, position = world.advance(RIGHT)

        self.assertEquals(TICK, status)
        self.assertEquals(start.left(), world.head())

    def testHitBoundary(self):
        world = self.world
        world.advance(UP)
        world.advance()
        status, pos = world.advance()

        self.assertEquals(FAIL, status)

    def testHitWall(self):
        world = self.world
        world.advance()
        status, pos = world.advance()

        self.assertEquals(FAIL, status)
    
    def testAppleEat(self):
        world = self.world
        pos = snake[0].up()

        world.putApple(pos)
        self.assertEquals(pos, world.apple())

        status, point = world.advance(UP)
        world.putApple(Point(0, 0))

        self.assertEquals(EAT, status)
        self.assertEquals(pos, point)

        world.advance(LEFT)
        world.advance()
        world.advance()

        self.assertEquals(len(snake) + 1, len(world.snake()))

    def testwithinWorld(self):
        world = self.world
        self.assertTrue(world.withinWorld(Point(0, 0)))
        self.assertTrue(world.withinWorld(Point(9, 0)))
        self.assertTrue(world.withinWorld(Point(0, 4)))
        self.assertTrue(world.withinWorld(Point(9, 4)))

        self.assertFalse(world.withinWorld(Point(10, 0)))
        self.assertFalse(world.withinWorld(Point(0, 5)))
        self.assertFalse(world.withinWorld(Point(10, 5)))

    def testGenerateApple(self):
        world = self.world

        point = world.generateApple()
        self.assertEquals(point, world.apple())
        self.assertEquals(APPLE, world[point])

    def testBiteSelf(self):
        world = self.world

        world.putApple(snake[0].up())
        world.advance()
        world.advance(UP)
        world.advance(UP)
        world.advance(RIGHT)
        world.advance(DOWN)
        status, point = world.advance(LEFT)

        self.assertEquals(FAIL, status)
        self.assertEquals(world.head().left(), point)

    def testWin(self):
        world = self.world

        world.putApple(snake[0].left())
        status, _ = world.advance()
        self.assertEquals(EAT, status)

        world.putApple(world.head().up())
        status, _ = world.advance(UP)
        self.assertEquals(WIN, status)

if __name__ == "__main__":
    unittest.main()
