File size: 5,786 Bytes
b33ab01
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
from typing import List, Tuple, Optional
from enum import Enum

class Actions(Enum):
    UPRIGHT = "UR"
    RIGHT = "R"
    DOWNRIGHT = "DR"
    DOWNLEFT = "DL"
    LEFT = "L"
    UPLEFT = "UL"
    PICKUP = "Pickup"
    # Add more actions here if needed

class Board:
    def __init__(self, grid: List[str], player_pos: Tuple[int, int], 
                 flag_pos: Tuple[int, int], wall_pos:List[Tuple[int, int]], 
                 key_pos:Optional[Tuple[int, int]]):
        self.grid = grid
        self.player_pos = player_pos
        self.flag_pos = flag_pos
        self.wall_pos = wall_pos
        self.key_pos = key_pos

    @staticmethod
    def change(action):
        if action == Actions.UPRIGHT:
            dx, dy = -1, 1
        elif action == Actions.UPLEFT:
            dx, dy = -1, -1
        elif action == Actions.DOWNLEFT:
            dx, dy = 1, -1
        elif action == Actions.DOWNRIGHT:
            dx, dy = 1, 1
        elif action == Actions.LEFT:
            dx, dy = 0, -2
        elif action == Actions.RIGHT:
            dx, dy = 0, 2
        elif action == Actions.PICKUP:
            dx, dy = 0, 0
        return dx, dy

    def move(self, action: Actions) -> 'Board':
        dx, dy = 0, 0
        if action == Actions.UPRIGHT:
            dx, dy = -1, 1
        elif action == Actions.UPLEFT:
            dx, dy = -1, -1
        elif action == Actions.DOWNLEFT:
            dx, dy = 1, -1
        elif action == Actions.DOWNRIGHT:
            dx, dy = 1, 1
        elif action == Actions.LEFT:
            dx, dy = 0, -2
        elif action == Actions.RIGHT:
            dx, dy = 0, 2
        elif action == Actions.PICKUP:
            dx, dy = 0, 0
            if self.player_pos[0] == self.key_pos[0] and self.player_pos[1] == self.key_pos[1]:
                return Board(self.grid, self.player_pos, self.flag_pos, self.wall_pos, None), "pickup"
            else:
                return self, "nokey"

        else:
            # Handle other actions here if needed
            print("fail")
        
        new_player_pos = (self.player_pos[0] + dx, self.player_pos[1] + dy)
        if self.grid[new_player_pos[0]][new_player_pos[1]] == 'W':
            # Can't move through walls
            return self, "WALL"
            
        new_grid = [row[:] for row in self.grid] # Create a copy of the grid
        new_grid[self.player_pos[0]][self.player_pos[1]] = '.'
        new_grid[new_player_pos[0]][new_player_pos[1]] = '@'
        return Board(new_grid, new_player_pos, self.flag_pos, self.wall_pos, self.key_pos), "Good"
    
    def create_wall(self, pos: Tuple[int, int]) -> 'Board':
        if self.grid[pos[0]][pos[1]] in ( '@', 'P'):
            # Can't place a wall on top of another object
            return self
        
        new_grid = [row[:] for row in self.grid] # Create a copy of the grid
        new_grid[pos[0]][pos[1]] = "W"
        return Board(new_grid, self.player_pos, self.flag_pos, self.wall_pos + [pos], self.key_pos)
    
    
    def __str__(self) -> str:
        # return '\n'.join((' ' * i %2) + ' '.join(row) for i, row in enumerate(self.grid))
        return '\n'.join(''.join(row) for i, row in enumerate(self.grid))
    
    def illegal_moves(self):
        for action in Actions:
            dx, dy = self.change(action)
            new_player_pos = (self.player_pos[0] + dx, self.player_pos[1] + dy)
            if new_player_pos[0] < 0 or new_player_pos[0] > self.flag_pos[0]:
                #yield action, f"assert not 0 <= {new_player_pos[0]} < {self.flag_pos[0] + 1}"
                continue
            if new_player_pos[1] < 0 or new_player_pos[1] > self.flag_pos[1]:
                #yield action, f"assert not 0 <= {new_player_pos[1]} < {self.flag_pos[0] + 1}"
                continue
            if action == Actions.PICKUP and not(self.key_pos is not None and self.player_pos[0] == self.key_pos[0] and self.player_pos[1] == self.key_pos[1]):
                yield action, f"assert {new_player_pos} != board.key"
                continue
            if self.grid[new_player_pos[0]][new_player_pos[1]] == 'W':
                yield action, f"assert {new_player_pos} in board.walls"
                continue
            continue

    def board_state(self) -> str:
        walls = ",".join(map(str, self.wall_pos))
        return f"Flag: {self.flag_pos} | Walls (illegal): {walls} | Boundary: {add(self.flag_pos, (1, 1))} | Key: {self.key_pos}"
    def board_state2(self) -> str:
        walls = ",".join(map(str, self.wall_pos))
        return f"init={self.player_pos}, flag={self.flag_pos}, walls= {self.wall_pos}, boundary= {add(self.flag_pos, (1, 1))},  key= {self.key_pos}"

    def player_state(self) -> str:
        msg = " K"  if self.key_pos is None else ""
        return f"{self.player_pos}{msg}"

    @classmethod
    def create_empty_board(cls, size: Tuple[int, int], key_pos, flag_pos, init) -> 'Board':
        grid = [['.' if i % 2 == j % 2  else " " for i in range(size[1])] for j in range(size[0])]
        player_pos = init
        flag_pos = flag_pos
        grid[player_pos[0]][player_pos[1]] = '@'
        grid[flag_pos[0]][flag_pos[1]] = 'P'
        grid[key_pos[0]][key_pos[1]] = 'K'
        return cls(grid, player_pos, flag_pos, [], key_pos)
def add(a, b):
    return a[0] + b[0], a[1] + b[1]

class GameBoard:
    def __init__(self, init, flag, walls, key, boundary):
        self.board = Board.create_empty_board(boundary, key, flag, init)
        for wall in walls:
            self.board = self.board.create_wall(wall)
        self.original = self.board

        self.actions = []
    def move(self, action):
        self.board, _ = self.board.move(action)
        self.actions.append(action)

    @property
    def walls(self):
        return self.board.wall_pos