79736128

Date: 2025-08-15 06:10:45
Score: 0.5
Natty:
Report link

There are a few changes you can make here to make this a little easier to add to. A couple major items to look at:

  1. Think about dividing the responsibility a little more clearly. Is it the Player object's responsibility to check for legal plays? This is likely a better fit for the Board object. In fact, it is hard to imagine the role a Player object fulfils in this structure, since you are the player and you are handling all the I/O in your controller/event loop, which is currently just in the main.
  2. The Board object likely doesn't need to understand the Player object, it only needs to provide its state and methods to update its state. Later, then you add a visual component to this, the visual component, maybe called View, will request the game state from the Board and draw it to screen, providing visually rich user input controls, and then forwarding those inputs to your Board for updates.
  3. Keeping the current structure, you can pass the Board object into your constructor for your Player and then save it to its internal state to reference whenever you need to make an update.
  4. It's unlikely that the goal is to create a new Player object for every input. I recommend moving the Player object initialization outside of the loop and referencing the same object over and over. This does require reworking the Player class a little to accept inputs from a function call instead of at initialization.

To address just the question as asked, I recommend changes like the following:

main.py

from Board import *
from Player import *

if __name__ == "__main__":
    b = Board()
    p = Player(b)  # Edited
    while True:
        old_x_input = int(input("x: "))
        old_y_input = int(input("y: "))
        new_x_input = int(input("move to newX: "))
        new_y_input = int(input("move to newY: "))

        # print(b.move())  # Edited
        p.move(old_x_input, old_y_input, new_x_input, new_y_input)  # Added
        print(b.board_flaeche)  # Edited

Player.py

# from numpy import np
# import main  # Edited
from Board import *

# from x, y to newX, newY
class Player:
    def __init__(self, board):  # Edited
        self.board = board  # Added
        # Edited
    #     self.old_x = old_x
    #     self.old_y = old_y
    #     self.new_x = new_x
    #     self.new_y = new_y
    #
    # def getOldX(self):
    #     return self.old_x
    #
    # def getOldY(self):
    #     return self.old_y
    #
    # def getNewX(self):
    #     return self.new_x
    #
    # def getNewY(self):
    #     return self.new_y


    # switching positions - not finished yet
    def move(self, old_x, old_y, new_x, new_y):  # Edited
        # Board.board_flaeche[x][y] = Board.board_flaeche[newX][newY]
        self.legal_length(old_x, old_y, new_x, new_y)  # Added
        # Still need to add something here, such as self.board.move(old_x, old_y, new_x, new_y)

    # ToDo:
    #  Task: Write a method legal_length where old_x, old_y, new_x, new_y
    #        must be checked if they are within the self.board_area[i][j] range

    def legal_length(self, old_x, old_y, new_x, new_y):  # Edited
        # ToDo Problem:
        # how do I get the attributes from another class in Python without creating an instance each time
        pass
        # Added section
        if old_x >= self.board.x or old_x < 0:
            raise ValueError(f'Provided old x is outside of range! {self.board.x} > {old_x} >= 0')
        if old_y >= self.board.y or old_y < 0:
            raise ValueError(f'Provided old y is outside of range! {self.board.y} > {old_y} >= 0')
        if new_x >= self.board.x or new_x < 0:
            raise ValueError(f'Provided new x is outside of range! {self.board.x} > {new_x} >= 0')
        if new_y >= self.board.y or new_y < 0:
            raise ValueError(f'Provided new y is outside of range! {self.board.y} > {new_y} >= 0')
        # / Added section

    def setPosition(self, new_x, new_y):
        pass

Board.py

import numpy as np
from Player import *

class Board:

    def __init__(self, x=None, y=None):
        if x is None:
            x = int(input("Enter the width of the board: "))
        if y is None:
            y = int(input("Enter the height of the board: "))
        self.x = x
        self.y = y
        self.board_flaeche = np.zeros((x, y), dtype=str)
        fruits_liste = ["Y", "B", "P"]

        for i in range(x):
            for j in range(y):
                self.board_flaeche[i][j] = np.random.choice(fruits_liste)

        print(self.board_flaeche)
        # do I need it??
        # self.player = Player(0, 0, 0, 0)  # Edited


    # Recommend this function have the following signature:
    #   def move(self, old_x, old_y, new_x, new_y):
    def move(self):

        old_x = self.player.getOldX()
        old_y = self.player.getOldY()
        new_x = self.player.getNewX()
        new_y = self.player.getNewY()

        # Update position of the player instance
        # self.player.setPosition(new_x, new_y)

But overall, to address some of my other comments, I would recommend a larger rework to better divide the responsibilities of each class to look something like this:

import numpy as np

class Board:

    fruit_lists = ['Y', 'B', 'P']

    def __init__(self, x_size: int = None, y_size: int = None):
        if x_size is None:
            x_size = int(input("Enter the width of the board: "))
        if y_size is None:
            y_size = int(input("Enter the height of the board: "))
        self.x_size: int = x_size
        self.y_size: int = y_size

        rng = np.random.default_rng()
        self.board_flaeche  = rng.choice(Board.fruit_lists, size=(self.x_size, self.y_size))

    def get_state(self):
        return self.board_flaeche

    def print_board(self):
        board_str = ''
        for row in self.board_flaeche:
            for col in row:
                board_str += f' {col} '
            board_str += '\n'
        print(board_str)

    def validate_move(self, old_x: int, old_y: int, new_x: int, new_y: int):
        if old_x >= self.x_size or old_x < 0:
            raise ValueError(f'Provided old x is outside of range! {self.x_size} > {old_x} >= 0')
        if old_y >= self.y_size or old_y < 0:
            raise ValueError(f'Provided old y is outside of range! {self.y_size} > {old_y} >= 0')
        if new_x >= self.x_size or new_x < 0:
            raise ValueError(f'Provided new x is outside of range! {self.x_size} > {new_x} >= 0')
        if new_y >= self.y_size or new_y < 0:
            raise ValueError(f'Provided new y is outside of range! {self.y_size} > {new_y} >= 0')


    def move(self, old_x: int, old_y: int, new_x: int, new_y: int):
        self.validate_move(old_x, old_y, new_x, new_y)

        # Valid input, now swap them
        source_fruit = self.board_flaeche[old_x, old_y]
        target_fruit = self.board_flaeche[new_x, new_y]
        self.board_flaeche[old_x, old_y] = target_fruit
        self.board_flaeche[new_x, new_y] = source_fruit

class Player:
    def __init__(self):
        pass

    def get_input(self):
        old_x_input = int(input("x: "))
        old_y_input = int(input("y: "))
        new_x_input = int(input("move to newX: "))
        new_y_input = int(input("move to newY: "))

        return old_x_input, old_y_input, new_x_input, new_y_input

class Game:
    def __init__(self):
        self.board = None
        self.player = None

    def start_new_game(self, x_size: int = None, y_size: int = None):
        self.board = Board(x_size, y_size)
        self.player = Player()

        while True:
            self.board.print_board()
            old_x, old_y, new_x, new_y = self.player.get_input()
            try:
                self.board.move(old_x, old_y, new_x, new_y)
            except ValueError:
                print('Bad move requested! Try again')



if __name__ == '__main__':
    game = Game()
    game.start_new_game()

With this rework, each class is only responsible for one thing. The Board is only responsible for keeping track of the board, making updates to it, printing itself to console etc. The Player is only responsible for handling player interactions. The Game is only responsible for setting up and running the event loop. Now as you add functionality it'll be much easier to stay organized, as each object is more independent, and once you add a graphical component to it, you'll only need to update the Game class without really worrying about what's in the other classes.

Reasons:
  • Blacklisted phrase (1): how do I
  • Blacklisted phrase (0.5): I need
  • Long answer (-1):
  • Has code block (-0.5):
  • Contains question mark (0.5):
Posted by: BitsAreNumbersToo