<s>[INST] So, I have a 2D array in Python like the one below:

```
[
  ['A', 'B', 'C'],
  ['D', 'E', 'F'],
  ['G', 'H', 'I']
]
```

And I want to manage it like a grid, with each cell being a separate entity. So I want to create a Board class. The initial structure should have methods for the following:
- Creating a board with size (rows x cols)
- Getting the number of rows and cols
- Getting the value of a cell
- Setting the value of a cell
- Checking if the board has a cell at a given position
- Printing the board
- Initializing the board with values

Here is an example of what I'd like the usage to look like:
```
board = Board(3, 3, [['A', 'B', 'C'], ['D', 'E', 'F'], ['G', 'H', 'I']])
board.print_board()
board.set_value(1, 1, 'X')
board.print_board()
```
And here is my attempt:
```
class Board:
    def __init__(self, rows, cols, values=None):
        self.rows = rows
        self.cols = cols
        if values is not None:
            self.values = values
        else:
            self.values = [[None for _ in range(cols)] for _ in range(rows)]

    def get_rows(self):
        return self.rows

    def get_cols(self):
        return self.cols

    def get_value(self, row, col):
        if self.has_cell(row, col):
            return self.values[row][col]
        else:
            return None

    def set_value(self, row, col, value):
        if self.has_cell(row, col):
            self.values[row][col] = value
        else:
            raise IndexError('Cell out of bounds')

    def has_cell(self, row, col):
        return (0 <= row < self.rows) and (0 <= col < self.cols)

    def print_board(self):
        for row in self.values:
            print(' '.join(row))[/INST]