I've been tinkering around trying to make an AI player for the popular card game, Dominion (http://www.boardgamegeek.com/boardgame/36218/dominion).
If you are not familiar with the game, it is basically a very streamlined cousin of Magic: The Gathering, where there is a large-ish library of cards with different rules on them. Over the course of a game, players buy these cards and incorporate them into their deck.
I am interested in this game from a machine learning perspective - I want to pit bots against each other, have th开发者_如何学运维em play millions of games, and try to datamine insights that will make them play better.
I am unsure how to separate the rules of the game (the verbatim instructions printed on each card) from the core AI decision-making logic.
The obvious path that I have started down is creating a class for each Card, and putting both rules and AI stuff in the same place. This is sort of gross - but it seems like the path of least resistance. But maybe it is best for each card to support some sort of interface and then have AI components code against these?
Is there a "Correct" OOP design for this? Or several reasonable possibilities?
I would lean toward encapsulating the behaviour of a card as its own class, allowing easily for cards that have multiple behaviours (i.e. choices). It would also allow you to write parameterizable behaviours and mix and match them with cards.
So cards would contain things like the cost of the card, when it can be played, its name, etc. It would also contain a list of behaviours that the card can do.
The behaviours are seen by the AI actors as part of the cards. Just another property the cards have that can be weighed along with the cost.
The AI actor that is actually using the card's behaviour needs to be able to interpret the behaviours, so the behaviour class might need to contain some hints for the AI to understand it, but no actual AI logic itself should be contained there. If AIs need specific behaviours for specific cards, write that kind of thing into the AI actor, not the card behaviour.
If an AI actor needs to know that, for example, this behaviour has an expected victory point payoff of .2 points/round, that might be a part of the behaviour that acts as a hint to the AI when choosing what cards to buy/play.
But really I don't know how you're approaching your AI actor design so maybe this doesn't make sense. But I think that thinking of behaviour as a property of cards rather than a fundamental part of the cards themselves might help.
It gives you the advantage of encapsulating the AI actors' default actions (things the actors can do without needing cards) as behaviours as well, so you can weigh those actions against card actions without any special-case code.
there are several "correct" OOP designs for this, depending on how you want to model the game process and the game-playing-agent's AI
personally, i would take the minimum number of cards for a valid round in the game and implement those as instances of a Card class, and implement the players as instances of an Agent class, and implement a few simple playing strategies as instances of a Strategy (pattern) class, and then see what happens
run through some tests, have a totally random player as a foil, look at short-term gain/loss max/min operators, try mutating the agent's strategies using a genetic algorithm, download an XCS classifier and see if it is useful to derive strategies...
...the notion of a correct model depends strongly on how it will be used. Once you understand how you need to use the elements of the game and model/manipulate the player strategies/tactics, then you'll know what the 'correct' structure is for your solution
I'm not familiar with all the variations of cards in Dominion, but the idea of writing a class for each one seems burdensome. Ideally, you would want to create a general card class that encapsulated all the variations of instructions on the card, and then load the particular values for a given card into that general class.
I can imagine a class that contains sets of powers and restrictions could be a good general representation. Something like:
- Required in play resources for play
- State where play is prohibited
- Damage types/value
- Health/mana changes
- Effects on other cards (perhaps a dictionary of card ids and effects)
- etc...
I've been thinking about the logic for a non-AI version of Dominion, and it's still a mess to figure out.
You almost have to have a class for each card deck and an interface for each card type, keeping in mind that cards may have multiple types (such as Great Hall which is both Action and Victory).
At present, all Attack cards are also Actions, so you may want to make the Attack interface subclass action. For most cards, the Action would just call the Attack method. However, there are a few cards where this would need to be different, such as for Minion where you have a choice whether or not to attack.
Reaction cards are also Actions, but will also need special handling, as they can be revealed during an opponent's turn in response to an Attack card. As of Prosperity, they can also be revealed in response to things other than attacks... Watchtower can be revealed any time you would gain a card.
Duration cards (which I missed in my list of 7 card types earlier) are Actions that stay in play for an extra turn... and also count for the Peddler's buy cost in Prosperity.
Edit: Whoops, I didn't address the AI issue at all here... probably because my own development had been aimed more at a multiplayer network version.
精彩评论