-2

I'm new to programming, and as one of my first projects that is unguided by a tutorial, I'm implementing a chess program. The way I have it structured now, there is a base class called Piece, and each kind of piece is derived from that base class. That way, I can implement the board as a two-dimensional array of Pieces, with the base class representing the empty squares. This was working well until I considered what I would need to do to determine whether a king is in check. The way to do this that seemed least wasteful to me was to give the King class a function that, for example, checks whether the king has lines of sight with any enemy rooks or bishops, checks whether there are enemy pawns in either of the two squares from which they could reach the king, etc. But to do this, the function would need to know which specific derived classes are where. I suppose I could make it work by giving each piece class an ID member for the function to check, but that seems redundant, and besides, I gather that a program that needs such information is considered badly structured. Have I in fact made a bad choice so far, and if so, how might I clean it up?

Apologies that this isn't a very general question. I couldn't think of a way to generalize it that would still be helpful to me.

Alex Kindel
  • 173
  • 7
  • Why do you think that having an ID for each class (or rather object) is a bad design? You have to distinguish them somehow. The alternative would be to make everything virtual. – freakish Jul 01 '17 at 06:39
  • 1
    The question is good and justified, but unfit for Stack Overflow, which is more about specific problems and bugs with code you have already written. – Christian Hackl Jul 01 '17 at 07:31
  • @freakish Before I posted my question, I did a search for ways of getting the types of objects, and found threads like [this](https://stackoverflow.com/questions/351845/finding-the-type-of-an-object-in-c?noredirect=1&lq=1). freespace's answer in particular is the sort that has given me pause. Maybe I've overestimated how much what they're talking about has in common with my situation. The reason I say an ID member seems redundant is because it seems like the classes should already be distinguishable by virtue of...well, being different classes. – Alex Kindel Jul 01 '17 at 08:28
  • This would be a much better suited question for SO if you sketched the skeleton (most likely in code) of what you are trying to achieve and failing to do. Keep in mind that your question should be able to produce a clear and more or less objectively "correct" answer – Passer By Jul 01 '17 at 13:44

2 Answers2

0

It may not be the most elegant or 'safe' way of doing it.

If the piece is a king, you can cast the pointer for it to a pointer for the king class usingreinterpret_cast or (King*) and then call the method that belongs to it.

This way you wouldn't have to implement it for every piece.

Example:

class Base
{
public:
    unsigned int id;
    virtual Base() { id = 0 }
};

class Child1 : public Base
{
public:
    virtual Child1() { id = 1; }
};

class Child2 : public Base
{
public:
    virtual Child2() { id = 2; }

    // implement the check, checking here.
    void Child2SpecificMethod() { id++; }
};

int main()
{
    Base& test1=Child1();
    Base& test2=Child2();

    // convert tests to pointers and attempt to call the "Child2SpecificMethod"
    ((Child1*)&test1)->Child2SpecificMethod(); // Won't work
    ((Child2*)&test2)->Child2SpecificMethod(); // Will work

    return 0;
}

This is very c-style-ish and should work but I cannot test it because I'm using my phone right now.

flmng0
  • 387
  • 1
  • 2
  • 14
0

From what I can glean from your description, polymorphism seems like what you're looking for

int abs(int x) { return x < 0 ? -x : x; }

class Piece
{
public:
    Piece(int x, int y) : x{x}, y{y} {}
    virtual bool reachable(const Piece&) const = 0;

    // other methods

protected:
    int x, y;
    std::pair<int, int> delta(const Piece& p) const
    {
        return {abs(x - p.x), abs(y - p.y)};
    }
};

class Knight : public Piece
{
public:
    using Piece::Piece;
    bool reachable(const Piece& p) const override
    {
        auto [dx, dy] = delta(p);
        if((dx == 1 && dy == 2) || (dx == 2 && dy == 1))
            return true;
        return false;
    }
};

class King : public Piece
{
public:
    using Piece::Piece;
    bool reachable(const Piece& p) const override
    {
        auto [dx, dy] = delta(p);
        if(dx <= 1 && dy <= 1)
            return true;
        return false;
    }
};

// other pieces

class Board
{
public:
    bool check(const King& k) const
    {
        for(auto& p : pieces)
            if(p->reachable(k))
                return true;
        return false;
    }
private:
    std::vector<std::unique_ptr<Piece>> pieces;
};

A Piece has some common interface including reachable, indicating whether the piece can reach the specified piece.

To check whether there is a check, iterate through the collection of pieces and see if they can reach the specified king.

Passer By
  • 19,325
  • 6
  • 49
  • 96
  • I did consider having each of the enemy pieces check whether they can reach the king as you propose here, rather than having the king check the places from which enemy pieces of the right kind could reach it from, as I proposed above. I thought the latter would require checking fewer things, but at the time I was also thinking I would use the function each piece was already equipped with that determines all its legal moves. Adding a tailor-made function instead, as you do, I can imagine any difference in efficiency being small. – Alex Kindel Jul 01 '17 at 23:20
  • I was thinking that _if I were to implement implement the former_, I would use the function each piece was already equipped with that determines all its legal moves, that is. – Alex Kindel Jul 01 '17 at 23:34