Dominion Strategy Forum

Please login or register.

Login with username, password and session length
Pages: [1]

Author Topic: Simulation verified engine beats bigmoney using Rats/WM/WT/Armory/Bridge  (Read 8605 times)

0 Members and 1 Guest are viewing this topic.

Sparafucile

  • Thief
  • ****
  • Offline Offline
  • Posts: 98
  • Respect: +153
    • View Profile
+6

This topic was inspired by the following forum post, but this forum seems more appropriate to the discussion about simulation.  Please see this topic for discussion:

http://forum.dominionstrategy.com/index.php?topic=9456.0

the tl;dr is that you can beat big money over 95% of the time quite easily with the cards in that post.

It took a bit to get the simulation working, but a tuned engine handidly can beat big money over 96% of the time on a board with Rats, Watchtower, Armory, Wandering Minstrell amd Bridge.   It also beats many many other strategies I have tried it against.   When comparing against BigMoney, here's some interesting things I learned.

For an opening build order, my initial guess was ok, but not optimal.
  • Initial guess: Armory, Silver, WanderingMinstrel, Watchtower, Rats, Watchtower:   89% win rate
  • Rats, Watchtower, Watchtower, Armory: 93.5% win rate
  • Rats, Watchtower, Armory, Watchtower: 95.3% win rate
  • Armory, Watchtower, Rats, Watchtower: 96.7% win rate

The quickest build seems to favor getting Watchtower/Rats fairly early for maximal trashing.

I confirmed the suspicion mentioned in the other post that adding a jester actually hurts vs big money.  Adding a jester brings the win rate down to 82%.
What effect does the armory have on the strategy?  If you ignore the armory, your winrate goes down to 82%.
Dont want to get the rats for the trashing?  Your win rate goes down to 85%
Wandering minstrell allows you to order the actions placed on top of the deck.  Just placing the cards randomly results in a 83.9%.  Using a relatively naive ordering, achieved the 96% win rate.
What effect does shelters have?  If you play with estates instead of shelters, win rate goes down to 90%.
3 watchtowers seems to be the right number.  After all, u need a wandering minstrell for every watchtower you play to keep chaining...

Furthermore, a tuned engine with these cards can beat out otherwise simple but strong contenders:
  • 77.6% win vs DoubleWitch
  • 72.6% win vs DoubleJack
It can go toe to toe with interesting engine combinations, for example:
  • 60.4% win vs EmbassyTunnelSpiceMerchantPlaza
  • 53.7% win vs FishingVillageChapelPoorHouse
  • 52.3% win vs Rebuild
It can even take some games off of a deck tuned to beat big money 99.89% of the time.  (though the strategies aren't tuned against each other)
  • 33.8% win vs GardensBeggarIronworks

Here's the complete strategy, using the simulator I've been playing around with.

Code: [Select]
private static ICardPicker PurchaseOrder()
{
    var highPriority = new CardPickByPriority(
            CardAcceptance.For<CardTypes.Province>(gameState => gameState.players.CurrentPlayer.AvailableBuys >= 4 || CountAllOwned<CardTypes.Province>(gameState) > 0),
            CardAcceptance.For<CardTypes.Duchy>(gameState => CountAllOwned<CardTypes.Province>(gameState) >= 3),
            CardAcceptance.For<CardTypes.Estate>(gameState => CountOfPile<CardTypes.Province>(gameState) <= 1));
                               
    var buildOrder = new CardPickByBuildOrder(
        new CardTypes.Armory(),
        new CardTypes.Watchtower(),                   
        new CardTypes.Rats(),                   
        new CardTypes.Watchtower());
               

    var lowPriority = new CardPickByPriority(
            CardAcceptance.For<CardTypes.Bridge>(ShouldBuyBridge),                       
            CardAcceptance.For<CardTypes.WanderingMinstrell>(),                       
            CardAcceptance.For<CardTypes.Watchtower>(gameState => CountAllOwned<CardTypes.Watchtower>(gameState) < 3));

    return new CardPickConcatenator(highPriority, buildOrder, lowPriority);
}

private static bool ShouldBuyBridge(GameState gameState)
{
    return CountAllOwned<CardTypes.WanderingMinstrell>(gameState) > CountAllOwned<CardTypes.Bridge>(gameState) + CountAllOwned<CardTypes.Watchtower>(gameState) + 1;
}

private static bool ShouldPlayArmory(GameState gameState)
{
    return CountAllOwned<CardTypes.Bridge>(gameState) < 5;
}

private static bool CanPlayTerminalWhileChaining(GameState gameState)
{
    return gameState.players.CurrentPlayer.AvailableActions >= 1;
}

private static bool CanPlay2TerminalsWhileChaining(GameState gameState)
{
    return gameState.players.CurrentPlayer.AvailableActions >= 2;
}

private static bool WillRatsComboWork(GameState gameState)
{
    return HasCardInHand<CardTypes.Watchtower>(gameState) &&
            HasCardInHand<CardTypes.Rats>(gameState) &&
            HasCardFromInHand(TrashOrderWithoutRats(), gameState);
}

private static CardPickByPriority ActionOrder()
{
    return new CardPickByPriority(
                CardAcceptance.For<CardTypes.Armory>(gameState => CanPlay2TerminalsWhileChaining(gameState) && ShouldPlayArmory(gameState)),
                CardAcceptance.For<CardTypes.Jester>(gameState => CanPlay2TerminalsWhileChaining(gameState)),
                CardAcceptance.For<CardTypes.Bridge>(gameState => CanPlay2TerminalsWhileChaining(gameState)),
                CardAcceptance.For<CardTypes.Watchtower>(gameState => CanPlayTerminalWhileChaining(gameState) && !WillRatsComboWork(gameState) && gameState.players.CurrentPlayer.Hand.Count() <= 5),
                CardAcceptance.For<CardTypes.Rats>(gameState => WillRatsComboWork(gameState)),
                CardAcceptance.For<CardTypes.WanderingMinstrell>(),
                CardAcceptance.For<CardTypes.Necropolis>(),
                CardAcceptance.For<CardTypes.Jester>(),
                CardAcceptance.For<CardTypes.Armory>(ShouldPlayArmory),
                CardAcceptance.For<CardTypes.Bridge>(),                           
                CardAcceptance.For<CardTypes.Watchtower>());
}

// dicard order used to tune which actions to put back with wandering minstrell
private static CardPickByPriority DiscardOrder()
{
    return new CardPickByPriority(
        CardAcceptance.For<CardTypes.Armory>(),
        CardAcceptance.For<CardTypes.Bridge>(),
        CardAcceptance.For<CardTypes.Necropolis>(),
        CardAcceptance.For<CardTypes.Watchtower>(),
        CardAcceptance.For<CardTypes.WanderingMinstrell>(),
        CardAcceptance.For<CardTypes.Rats>());
}

private static CardPickByPriority TrashOrder()
{
    return new CardPickByPriority(
                CardAcceptance.For<CardTypes.Rats>(gameState => CountAllOwned<CardTypes.Rats>(gameState) > 0),
                CardAcceptance.For<CardTypes.Curse>(),
                CardAcceptance.For<CardTypes.Estate>(),
                CardAcceptance.For<CardTypes.OvergrownEstate>(),                         
                CardAcceptance.For<CardTypes.Hovel>(),
                CardAcceptance.For<CardTypes.Necropolis>(),
                CardAcceptance.For<CardTypes.Copper>());
}

private static CardPickByPriority TrashOrderWithoutRats()
{
    return new CardPickByPriority(
                CardAcceptance.For<CardTypes.Curse>(),
                CardAcceptance.For<CardTypes.Estate>(),
                CardAcceptance.For<CardTypes.OvergrownEstate>(),
                CardAcceptance.For<CardTypes.Hovel>(),
                CardAcceptance.For<CardTypes.Necropolis>(),                           
                CardAcceptance.For<CardTypes.Copper>()
                );
}
« Last Edit: October 02, 2013, 02:11:56 pm by Sparafucile »
Logged

SCSN

  • Mountebank
  • *****
  • Offline Offline
  • Posts: 2227
  • Respect: +7140
    • View Profile
Re: Simulation verified engine beats bigmoney using Rats/WM/WT/Armory/Bridge
« Reply #1 on: October 02, 2013, 03:19:23 pm »
0

Nice work!

I think using a WM-reorder method based on what you actually need now/are most likely to need next hand can lead to significant improvements still.

Here's the complete strategy, using the simulator I've been playing around with.

What simulator is that?
Logged

Sparafucile

  • Thief
  • ****
  • Offline Offline
  • Posts: 98
  • Respect: +153
    • View Profile
Re: Simulation verified engine beats bigmoney using Rats/WM/WT/Armory/Bridge
« Reply #2 on: October 02, 2013, 03:25:20 pm »
0

[What simulator is that?]

One I've been working on.  Haven't publicized the code much yet.

If u  install visual studio express, u can find the code here:  https://github.com/NathanTeeuwen/Dominion
Logged

dondon151

  • 2012 US Champion
  • *
  • Offline Offline
  • Posts: 2522
  • Respect: +1856
    • View Profile
Re: Simulation verified engine beats bigmoney using Rats/WM/WT/Armory/Bridge
« Reply #3 on: October 02, 2013, 04:35:00 pm »
0

If you play a Jester against BM and reveal a Silver or a Gold, can't you just choose to gain the Silver or Gold and trash it with Watchtower?
Logged

Warfreak2

  • Saboteur
  • *****
  • Offline Offline
  • Posts: 1149
  • KC->KC->[Scavenger, Scavenger, Lookout]
  • Respect: +1324
    • View Profile
    • Music what I do
Re: Simulation verified engine beats bigmoney using Rats/WM/WT/Armory/Bridge
« Reply #4 on: October 02, 2013, 04:49:47 pm »
+1

Is that really worth getting a Jester for? Seems like you'd rather just have another Bridge.
Logged
If the only engine on the board is Procession->Conspirator, I will play it.

dondon151

  • 2012 US Champion
  • *
  • Offline Offline
  • Posts: 2522
  • Respect: +1856
    • View Profile
Re: Simulation verified engine beats bigmoney using Rats/WM/WT/Armory/Bridge
« Reply #5 on: October 02, 2013, 05:24:11 pm »
0

You're getting the Jester in hopes of hitting Copper/Victory.
Logged

SCSN

  • Mountebank
  • *****
  • Offline Offline
  • Posts: 2227
  • Respect: +7140
    • View Profile
Re: Simulation verified engine beats bigmoney using Rats/WM/WT/Armory/Bridge
« Reply #6 on: October 02, 2013, 05:38:50 pm »
0

You're getting the Jester in hopes of hitting Copper/Victory.

Copper doesn't hurt the BM player much and a Curse or two don't slow him down that much either, especially because you also improve his next hand by discarding a green card. That said, I think it might still be okish if you were guaranteed to always have a Watchtower in hand to trash incoming Silvers/Golds and if you had unlimited actions. That last condition is the most important one: with this engine you want to build towards a Bridge mega-turn, and with WT for draw and WM as the only source of +Actions, you really want to avoid any non-Bridge terminals other than a single Armory.
Logged

Warfreak2

  • Saboteur
  • *****
  • Offline Offline
  • Posts: 1149
  • KC->KC->[Scavenger, Scavenger, Lookout]
  • Respect: +1324
    • View Profile
    • Music what I do
Re: Simulation verified engine beats bigmoney using Rats/WM/WT/Armory/Bridge
« Reply #7 on: October 02, 2013, 05:47:33 pm »
0

Yeah, it seems like a terminal Silver now is going to slow you down more than a few Coppers later for your opponent. If Jester couldn't gain you good cards, it would probably be $3, and unfavourably comparable to Swindler.
Logged
If the only engine on the board is Procession->Conspirator, I will play it.

SCSN

  • Mountebank
  • *****
  • Offline Offline
  • Posts: 2227
  • Respect: +7140
    • View Profile
Re: Simulation verified engine beats bigmoney using Rats/WM/WT/Armory/Bridge
« Reply #8 on: October 02, 2013, 06:45:07 pm »
0

[What simulator is that?]

One I've been working on.  Haven't publicized the code much yet.

If u  install visual studio express, u can find the code here:  https://github.com/NathanTeeuwen/Dominion

Could you help me out getting started? I'm quite a n00b with anything beyond scripting. I do have VS2012 and can open the project, but when I click the green-arrowed start button I get the message "A project with an Output Type of Class Library cannot be started directly". I can build the project successfully, but then all I get is an executable that starts a console window that disappears after a while, leaving no apparent trace, and I want to run the stuff from inside Visual Studio anyway.

Maybe it's easier to start with the end I have in mind: what I would like to do, as an introductory exercise, is to compare different Rebuild strategies against each other. So I'd like to know how to specify a strategy, select two strategies to run against each other, how to select the parameters of the simulation (how many trials to run, and ideally also what game-state to start from, i.e. I'd love to alter each player's starting deck and cards left in the supply to faster optimize parameters that are relevant in only a fraction of games that would randomly show up), and then I'd like to access the logs of the simulated games (or just generate a few sample logs, saving all would be pointless), as I find that the best way to debug strategies.

Then I'd like to know how to access the contents of your hand, your deck and your discard (and, by deduction, your draw pile), because these things are really essential to know for any decent Rebuild strategy (you might want to check the nameVPPriority methods of these two Rebuild scripts and look at how they perform against each other, if it interests you).
« Last Edit: October 02, 2013, 06:49:44 pm by SheCantSayNo »
Logged

Sparafucile

  • Thief
  • ****
  • Offline Offline
  • Posts: 98
  • Respect: +153
    • View Profile
Re: Simulation verified engine beats bigmoney using Rats/WM/WT/Armory/Bridge
« Reply #9 on: October 02, 2013, 06:58:19 pm »
+1

Apologies its not more friendly to setup. 

For whatever reason, the test program is not setup as the startup project.  In solution explorer, find the test program, right click on it, and set as startup project.

The output of the program is to the console - so set a break point on the last line of the main function to see the output before the window auto closes.

Also, there should be 100 result files in the TestProgram\Results directory.  (it runs 1000 times per simulation by default, but u dont need 100 logs do u?)

Is it possible to submit future technical troubles through the GIT website, so as not to bombard this forum with technical help?

There is a rebuild strategy I already coded that should get u started.

The main program has a method called ComparePlayers that takes 2 strategies as parameters. You can specify how  many iterations to run there.

« Last Edit: October 02, 2013, 07:00:07 pm by Sparafucile »
Logged

SCSN

  • Mountebank
  • *****
  • Offline Offline
  • Posts: 2227
  • Respect: +7140
    • View Profile
Re: Simulation verified engine beats bigmoney using Rats/WM/WT/Armory/Bridge
« Reply #10 on: October 02, 2013, 11:26:31 pm »
0

Thanks alot! I got it running and I'm well on my way towards implementing some strategies.

One additional question: how do I get the score, or rather the difference between my #VP and that of my opponent? Quite a number of decisions depend on that :)
Logged

Sparafucile

  • Thief
  • ****
  • Offline Offline
  • Posts: 98
  • Respect: +153
    • View Profile
Re: Simulation verified engine beats bigmoney using Rats/WM/WT/Armory/Bridge
« Reply #11 on: October 02, 2013, 11:34:36 pm »
+1

Quote
how do I get the score, or rather the difference between my #VP and that of my opponent? Quite a number of decisions depend on that

If you need your score mid game, use gameState.players.CurrentPlayer.TotalScore().   If you are vs 1 opponent, the other opponents score is: gameState.players.OtherPlayers.First().TotalScore()

If you are looking for the end game score, look at the Program.ComparePlayers method.   It extracts the score for the two players and shows you how you can do it.   If you pass in showDistribution:true to the method, it will print out a display like this:

Player 1 Score Delta distribution
=================================
24 points:   0.1% = 1
22 points:   0.2% = 2
20 points:   0.2% = 2
18 points:   0.5% = 5
17 points:   0.2% = 2
16 points:   0.5% = 5
15 points:   0.1% = 1
14 points:   0.7% = 7
...
5 points:   2.4% = 24
4 points:   4.1% = 41
3 points:   5.5% = 55
2 points:   6.5% = 65
1 points:   4.5% = 45
0 points:   12.3% = 123
-1 points:   3.6% = 36
-2 points:   5.2% = 52
-3 points:   4.4% = 44
-4 points:   4.7% = 47
-5 points:   3.1% = 31
....
-10 points:   2.2% = 22
-18 points:   0.3% = 3
-20 points:   0.1% = 1
-22 points:   0.1% = 1
« Last Edit: October 02, 2013, 11:42:19 pm by Sparafucile »
Logged

SCSN

  • Mountebank
  • *****
  • Offline Offline
  • Posts: 2227
  • Respect: +7140
    • View Profile
Re: Simulation verified engine beats bigmoney using Rats/WM/WT/Armory/Bridge
« Reply #12 on: October 02, 2013, 11:57:21 pm »
0

Quote
how do I get the score, or rather the difference between my #VP and that of my opponent? Quite a number of decisions depend on that

If you need your score mid game, use gameState.players.CurrentPlayer.TotalScore().   If you are vs 1 opponent, the other opponents score is: gameState.players.OtherPlayers.First().TotalScore()

Thanks, that's indeed what I was looking for. When I write

Code: [Select]
public override Type NameACard(GameState gameState)
                {

                    PlayerState currentPlayer = gameState.players.CurrentPlayer;

                    int score = gameState.players.CurrentPlayer.TotalScore() -  gameState.players.OtherPlayers.First().TotalScore();

I can indeed use the score as a factor in deciding what to name. However, I also want it to use as a factor in deciding what to purchase and whether to play Rebuild at all, but

Code: [Select]
            private static CardPickByPriority PurchaseOrder()
            {

                int score = gameState.players.CurrentPlayer.TotalScore() - gameState.players.PlayerLeft.TotalScore();

returns the error "The name 'gameState' does not exist in the current context".

And changing the first line to

Code: [Select]
private static CardPickByPriority PurchaseOrder(GameState gameState)
fucks things up even more. How can I access the score from within the PurchaseOrder() and ActionOrder() methods?
Logged

Sparafucile

  • Thief
  • ****
  • Offline Offline
  • Posts: 98
  • Respect: +153
    • View Profile
Re: Simulation verified engine beats bigmoney using Rats/WM/WT/Armory/Bridge
« Reply #13 on: October 03, 2013, 01:13:18 am »
+2

Quote
fucks things up even more. How can I access the score from within the PurchaseOrder() and ActionOrder() methods?

Kudos to you for braving this on your own with documentation.   Let me help a little.  There is no user level way of interacting with the simulator.  Just programmatic right now. 

The design of the simulator I'm writing is modular.   The game engine itself makes no AI decisions.  It just enforces the rules of the game.  You plug into the game engine players that implement IPlayerAction interface.  Check it out.  There's a lot of methods in there, and the list is changing and growing as I am refining the game engine.   I have implemented one generic AI, that implements IPlayerAction.  It's the PlayerAction class.    This class mirrors the behavior of other simulators you may be familar with.  You plug in a purchase order, an action order, a discard order, etc, and the PlayerAction instance translates this answer the questions the game engine needs.   The question you are looking at, is what do these Purchase order and discard order things look like.   Well, those implement the ICardPicker interface.  It looks like this:

public interface ICardPicker
    {
        int AmountWillingtoOverPayFor(Card card, GameState gameState);
        Type GetPreferredCard(GameState gameState, CardPredicate cardPredicate);
        IEnumerable<Card> GetNeededCards();
    }

There's 2 implemenations right now - CardPickByBuildOrder and CardPickByPriority, and combinations thereof.   All the strategies I have coded up so far use this approach.   If you want to create your own way of picking cards that doesnt fit in this category, you must implement ICardPicker.  The most important method is GetPreferredCard.   The gamestate (mentioned above) is passed in.   All this is background to help you understand what's going on.

Sounds like what you want to do is something like this:

(look for this text below:  gameState.players.CurrentPlayer.TotalScore() < 50)

Code: [Select]
private static CardPickByPriority PurchaseOrder()
            {
                return new CardPickByPriority(
                           CardAcceptance.For<CardTypes.Province>(),
                           CardAcceptance.For<CardTypes.Duchy>(gameState => CountAllOwned<CardTypes.Estate>(gameState) < CountAllOwned<CardTypes.Rebuild>(gameState)),
                           CardAcceptance.For<CardTypes.Rebuild>(gameState => CountAllOwned<CardTypes.Rebuild>(gameState) < 3 && gameState.players.CurrentPlayer.TotalScore() < 50),
                           CardAcceptance.For<CardTypes.Gold>(),                           
                           CardAcceptance.For<CardTypes.Silver>());
            }

Logged

SCSN

  • Mountebank
  • *****
  • Offline Offline
  • Posts: 2227
  • Respect: +7140
    • View Profile
Re: Simulation verified engine beats bigmoney using Rats/WM/WT/Armory/Bridge
« Reply #14 on: October 04, 2013, 10:12:21 am »
+1

Thanks alot for the explanation, your general willingness to help me out and for creating this simulator in the first place, I'm having a lot of fun with it (so much so that I haven't played any real Dominion game in days)! I recommend you to create a separate thread dedicated to your simulator and have it stickied like those dedicated to the simulators of Geronimoo and rspeer. Your simulator is the only one with all the cards, so it certainly has something to offer.

I have created a few Rebuild scripts you might like to add. I'll post them in a seperate post below this one.

If it's not too much trouble, could you explain to me the easiest way to manipulate the gamestate from which to start simulating? I'd very much like to specify both the starting decks for each player and the supply piles. As a concrete example: I want to be able to let both players start with 2 Rebuilds and 4 Duchies in their deck (and 0 Duchies left in the supply), but one of the players has an Estate whereas the other has none.
Logged

SCSN

  • Mountebank
  • *****
  • Offline Offline
  • Posts: 2227
  • Respect: +7140
    • View Profile
Re: Simulation verified engine beats bigmoney using Rats/WM/WT/Armory/Bridge
« Reply #15 on: October 04, 2013, 10:28:52 am »
+1

The scripts:

RebuildAdvanced.cs The basic Rebuild strategy as I think it should be played. It buys 2 Rebuilds in the mirror, 3 in the non-mirror and pays attention to both its hand, the draw- and discard-piles, and the score when deciding what to name or whether to play Rebuild at all. Feel free to either include this alongside the existing Rebuild script or replace the existing script with this one.

Code: [Select]
using Dominion;
using CardTypes = Dominion.CardTypes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

//Author: SheCantSayNo

namespace Program
{
    public static partial class Strategies
    {
        public static class RebuildAdvanced
        {
            // big money smithy player
            public static PlayerAction Player(int playerNumber)
            {
                return new MyPlayerAction(playerNumber);
            }

            class MyPlayerAction
                : PlayerAction
            {
                public MyPlayerAction(int playerNumber)
                    : base("RebuildAdvanced",
                        playerNumber,
                        purchaseOrder: PurchaseOrder(),
                        treasurePlayOrder: Default.TreasurePlayOrder(),
                        actionOrder: ActionOrder())
                {
                }

                public override Type NameACard(GameState gameState)
                {

                    PlayerState currentPlayer = gameState.players.CurrentPlayer;

                    int score = gameState.players.CurrentPlayer.TotalScore() - gameState.players.OtherPlayers.First().TotalScore();

                    //Name Duchy
                    if (CountOfPile<CardTypes.Duchy>(gameState) > 0
                        && CountInDeckAndDiscard<CardTypes.Estate>(gameState) > 0
                        && (CountInDeckAndDiscard<CardTypes.Province>(gameState) == 0
                           || CountInDeck<CardTypes.Province>(gameState) == 0 && CountInDeck<CardTypes.Duchy>(gameState) > 0
                           && CountInDeck<CardTypes.Estate>(gameState) > 0))
                    {
                        return typeof(CardTypes.Duchy);
                    }

                    //Name Province if you are ensured of gaining a Province
                    if (CountInDeck<CardTypes.Estate>(gameState) == 0 && CountInDeck<CardTypes.Province>(gameState) >= 0
                        && CountInDeck<CardTypes.Duchy>(gameState) > 0)
                    {
                        return typeof(CardTypes.Province);
                    }

                    //Name Province if you are ensured of gaining a Province
                    if (CountInDeckAndDiscard<CardTypes.Estate>(gameState) == 0
                        && CountInDeckAndDiscard<CardTypes.Province>(gameState) >= 0
                        && CountInDeckAndDiscard<CardTypes.Duchy>(gameState) > 0)
                    {
                        return typeof(CardTypes.Province);
                    }

                    //Name Estate if you can end it with a win                   
                    if (CountInHand<CardTypes.Rebuild>(gameState) + 1 >= CountOfPile<CardTypes.Province>(gameState) && score > 0)
                    {
                        return typeof(CardTypes.Estate);
                    }

                    //Name Estate if it's the only thing left in your draw pile and the Duchies are gone
                    if (CountOfPile<CardTypes.Duchy>(gameState) == 0 && CountInDeck<CardTypes.Province>(gameState) == 0
                        && CountInDeck<CardTypes.Estate>(gameState) > 0)
                    {
                        return typeof(CardTypes.Estate);
                    }

                    //Name Province if Duchy is in Draw and Draw contains more P than E
                    if (CountOfPile<CardTypes.Duchy>(gameState) == 0 && CountInDeck<CardTypes.Duchy>(gameState) > 0
                        && CountInDeck<CardTypes.Province>(gameState) > CountInDeck<CardTypes.Estate>(gameState))
                    {
                        return typeof(CardTypes.Province);
                    }

                    //Name Estate if you're ahead and both P and E are left in draw
                    if (CountOfPile<CardTypes.Duchy>(gameState) == 0 && CountInDeck<CardTypes.Province>(gameState) > 0
                        && CountInDeck<CardTypes.Estate>(gameState) > 0 && score > 2)
                    {
                        return typeof(CardTypes.Estate);
                    }

                    //Name Estate over Province if you're way ahead
                    if (CountOfPile<CardTypes.Duchy>(gameState) == 0 && CountInDeckAndDiscard<CardTypes.Province>(gameState) > 0
                        && CountInDeckAndDiscard<CardTypes.Duchy>(gameState) < 3
                        && CountInDeckAndDiscard<CardTypes.Estate>(gameState) > 0 && score > 4)
                    {
                        return typeof(CardTypes.Estate);
                    }

                    //Province -> Province when ahead without any Duchies left
                    if (CountOfPile<CardTypes.Duchy>(gameState) == 0 && CountAllOwned<CardTypes.Duchy>(gameState) == 0
                       && score > 0)
                    {
                        return typeof(CardTypes.Estate);
                    }

                    //Province -> Province when ahead without any Duchies not in hand
                    if (CountOfPile<CardTypes.Duchy>(gameState) == 0 && CountInDeckAndDiscard<CardTypes.Duchy>(gameState) == 0
                        && CountInDeckAndDiscard<CardTypes.Province>(gameState) > 0 && score > 2)
                    {
                        return typeof(CardTypes.Estate);
                    }

                    if (CountInDeckAndDiscard<CardTypes.Province>(gameState) > 0)
                    {
                        return typeof(CardTypes.Province);
                    }

                    return typeof(CardTypes.Estate);
                }
            }

            private static int getScore(GameState gameState)
            {
                return gameState.players.CurrentPlayer.TotalScore() - gameState.players.OtherPlayers.First().TotalScore();
            }

            private static CardPickByPriority PurchaseOrder()
            {
                return new CardPickByPriority(                   
                           CardAcceptance.For<CardTypes.Province>(),
                           CardAcceptance.For<CardTypes.Rebuild>(gameState => CountAllOwned<CardTypes.Rebuild>(gameState) < 2),
                           //In non-mirrors, get a 3rd Rebuild
                           CardAcceptance.For<CardTypes.Rebuild>(gameState => CountAllOwned<CardTypes.Rebuild>(gameState) < 3
                           && CountOfPile<CardTypes.Rebuild>(gameState) > 7),
                           CardAcceptance.For<CardTypes.Duchy>(),
                           CardAcceptance.For<CardTypes.Estate>(gameState => CountOfPile<CardTypes.Province>(gameState) <= 1),
                           CardAcceptance.For<CardTypes.Estate>(gameState => CountOfPile<CardTypes.Province>(gameState) == 2
                           && getScore(gameState) > -8),                           
                           CardAcceptance.For<CardTypes.Gold>(),
                           CardAcceptance.For<CardTypes.Estate>(gameState => CountOfPile<CardTypes.Province>(gameState) <= 2),
                           CardAcceptance.For<CardTypes.Rebuild>(gameState => (CountAllOwned<CardTypes.Duchy>(gameState) > 0
                           || getScore(gameState) > 2) && (CountOfPile<CardTypes.Rebuild>(gameState) > 2 || getScore(gameState) > 3                           
                           || (CountOfPile<CardTypes.Rebuild>(gameState) == 1 && getScore(gameState) > 0) )),
                           CardAcceptance.For<CardTypes.Estate>(gameState => CountOfPile<CardTypes.Duchy>(gameState) >= 4
                           && CountAllOwned<CardTypes.Duchy>(gameState) == 0 && CountAllOwned<CardTypes.Estate>(gameState) == 0),
                           CardAcceptance.For<CardTypes.Estate>(gameState => CountOfPile<CardTypes.Duchy>(gameState) == 0
                           && CountAllOwned<CardTypes.Duchy>(gameState) == 0),
                           CardAcceptance.For<CardTypes.Silver>());
            }

            private static CardPickByPriority ActionOrder()
            {
                return new CardPickByPriority(
                           CardAcceptance.For<CardTypes.Rebuild>(gameState =>
                           !(gameState.players.CurrentPlayer.ExpectedCoinValueAtEndOfTurn >= 8
                            && CountOfPile<CardTypes.Province>(gameState) == 1)
                            && !(CountOfPile<CardTypes.Duchy>(gameState) == 0
                            && CountInDeckAndDiscard<CardTypes.Duchy>(gameState) == 0 && getScore(gameState) < 0)
                            && CountOfPile<CardTypes.Province>(gameState) > 0));
            }                       
        }
    }
}

RebuildJack.cs Same strategy as RebuildAdvanced but with one Jack added to it (which beats adding two Jacks). It performs strictly better than RebuildAdvanced, but Jack isn't available in all Rebuild games ;)

Code: [Select]
using Dominion;
using CardTypes = Dominion.CardTypes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

//Author: SheCantSayNo

namespace Program
{
    public static partial class Strategies
    {
        public static class RebuildJack
        {
            // big money smithy player
            public static PlayerAction Player(int playerNumber)
            {
                return new MyPlayerAction(playerNumber);
            }

            class MyPlayerAction
                : PlayerAction
            {
                public MyPlayerAction(int playerNumber)
                    : base("RebuildJack",
                        playerNumber,
                        purchaseOrder: PurchaseOrder(),
                        treasurePlayOrder: Default.TreasurePlayOrder(),
                        actionOrder: ActionOrder())
                {
                }

                public override Type NameACard(GameState gameState)
                {

                    PlayerState currentPlayer = gameState.players.CurrentPlayer;

                    int score = gameState.players.CurrentPlayer.TotalScore() - gameState.players.OtherPlayers.First().TotalScore();

                    //Name Duchy
                    if (CountOfPile<CardTypes.Duchy>(gameState) > 0
                        && CountInDeckAndDiscard<CardTypes.Estate>(gameState) > 0
                        && (CountInDeckAndDiscard<CardTypes.Province>(gameState) == 0
                           || CountInDeck<CardTypes.Province>(gameState) == 0 && CountInDeck<CardTypes.Duchy>(gameState) > 0
                           && CountInDeck<CardTypes.Estate>(gameState) > 0))
                    {
                        return typeof(CardTypes.Duchy);
                    }

                    //Name Province if you are ensured of gaining a Province
                    if (CountInDeck<CardTypes.Estate>(gameState) == 0 && CountInDeck<CardTypes.Province>(gameState) >= 0
                        && CountInDeck<CardTypes.Duchy>(gameState) > 0)
                    {
                        return typeof(CardTypes.Province);
                    }

                    //Name Province if you are ensured of gaining a Province
                    if (CountInDeckAndDiscard<CardTypes.Estate>(gameState) == 0
                        && CountInDeckAndDiscard<CardTypes.Province>(gameState) >= 0
                        && CountInDeckAndDiscard<CardTypes.Duchy>(gameState) > 0)
                    {
                        return typeof(CardTypes.Province);
                    }

                    //Name Estate if you can end it with a win                   
                    if (CountInHand<CardTypes.Rebuild>(gameState) + 1 >= CountOfPile<CardTypes.Province>(gameState) && score > 0)
                    {
                        return typeof(CardTypes.Estate);
                    }

                    //Name Estate if it's the only thing left in your draw pile and the Duchies are gone
                    if (CountOfPile<CardTypes.Duchy>(gameState) == 0 && CountInDeck<CardTypes.Province>(gameState) == 0
                        && CountInDeck<CardTypes.Estate>(gameState) > 0)
                    {
                        return typeof(CardTypes.Estate);
                    }

                    //Name Province if Duchy is in Draw and Draw contains more P than E
                    if (CountOfPile<CardTypes.Duchy>(gameState) == 0 && CountInDeck<CardTypes.Duchy>(gameState) > 0
                        && CountInDeck<CardTypes.Province>(gameState) > CountInDeck<CardTypes.Estate>(gameState))                       
                    {
                        return typeof(CardTypes.Province);
                    }

                    //Name Estate if you're ahead and both P and E are left in draw
                    if (CountOfPile<CardTypes.Duchy>(gameState) == 0 && CountInDeck<CardTypes.Province>(gameState) > 0
                        && CountInDeck<CardTypes.Estate>(gameState) > 0 && score > 2)
                    {
                        return typeof(CardTypes.Estate);
                    }

                    //Name Estate over Province if you're way ahead
                    if (CountOfPile<CardTypes.Duchy>(gameState) == 0 && CountInDeckAndDiscard<CardTypes.Province>(gameState) > 0
                        && CountInDeckAndDiscard<CardTypes.Duchy>(gameState) < 3
                        && CountInDeckAndDiscard<CardTypes.Estate>(gameState) > 0 && score > 4)
                    {
                        return typeof(CardTypes.Estate);
                    }

                    //Province -> Province when ahead without any Duchies left
                    if (CountOfPile<CardTypes.Duchy>(gameState) == 0 && CountAllOwned<CardTypes.Duchy>(gameState) == 0
                       && score > 0)
                    {
                        return typeof(CardTypes.Estate);
                    }

                    //Province -> Province when ahead without any Duchies not in hand
                    if (CountOfPile<CardTypes.Duchy>(gameState) == 0 && CountInDeckAndDiscard<CardTypes.Duchy>(gameState) == 0
                        && CountInDeckAndDiscard<CardTypes.Province>(gameState) > 0 && score > 2)
                    {
                        return typeof(CardTypes.Estate);
                    }

                    if (CountInDeckAndDiscard<CardTypes.Province>(gameState) > 0)
                    {
                        return typeof(CardTypes.Province);
                    }

                    return typeof(CardTypes.Estate);
                }
            }

            private static int getScore(GameState gameState)
            {
                return gameState.players.CurrentPlayer.TotalScore() - gameState.players.OtherPlayers.First().TotalScore();
            }

            private static CardPickByPriority PurchaseOrder()
            {
                return new CardPickByPriority(                   
                           CardAcceptance.For<CardTypes.Province>(),
                           CardAcceptance.For<CardTypes.Rebuild>(gameState => CountAllOwned<CardTypes.Rebuild>(gameState) < 2),
                           //In non-mirrors, get a 3rd Rebuild
                           CardAcceptance.For<CardTypes.Rebuild>(gameState => CountAllOwned<CardTypes.Rebuild>(gameState) < 3
                           && CountOfPile<CardTypes.Rebuild>(gameState) > 7),
                           CardAcceptance.For<CardTypes.Duchy>(),
                           CardAcceptance.For<CardTypes.Estate>(gameState => CountOfPile<CardTypes.Province>(gameState) <= 1),
                           CardAcceptance.For<CardTypes.Estate>(gameState => CountOfPile<CardTypes.Province>(gameState) == 2
                           && getScore(gameState) > -8),                           
                           CardAcceptance.For<CardTypes.Gold>(),
                           CardAcceptance.For<CardTypes.Estate>(gameState => CountOfPile<CardTypes.Province>(gameState) <= 2),
                           CardAcceptance.For<CardTypes.Rebuild>(gameState => (CountAllOwned<CardTypes.Duchy>(gameState) > 0
                           || getScore(gameState) > 2) && (CountOfPile<CardTypes.Rebuild>(gameState) > 2 || getScore(gameState) > 3                           
                           || (CountOfPile<CardTypes.Rebuild>(gameState) == 1 && getScore(gameState) > 0) )),
                           CardAcceptance.For<CardTypes.Estate>(gameState => CountOfPile<CardTypes.Duchy>(gameState) >= 4
                           && CountAllOwned<CardTypes.Duchy>(gameState) == 0 && CountAllOwned<CardTypes.Estate>(gameState) == 0),
                           CardAcceptance.For<CardTypes.Estate>(gameState => CountOfPile<CardTypes.Duchy>(gameState) == 0
                           && CountAllOwned<CardTypes.Duchy>(gameState) == 0),
                           CardAcceptance.For<CardTypes.JackOfAllTrades>(gameState =>
                               CountAllOwned<CardTypes.JackOfAllTrades>(gameState) < 1),
                           CardAcceptance.For<CardTypes.Silver>());
            }

            private static CardPickByPriority ActionOrder()
            {
                return new CardPickByPriority(
                           CardAcceptance.For<CardTypes.Rebuild>(gameState =>
                           !(gameState.players.CurrentPlayer.ExpectedCoinValueAtEndOfTurn >= 8
                           && CountOfPile<CardTypes.Province>(gameState) == 1)
                           && !(CountOfPile<CardTypes.Duchy>(gameState) == 0
                           && CountInDeckAndDiscard<CardTypes.Duchy>(gameState) == 0 && getScore(gameState) < 0)
                           && CountOfPile<CardTypes.Province>(gameState) > 0),
                           CardAcceptance.For<CardTypes.JackOfAllTrades>());
            }                       
        }
    }
}

RebuildMonument.cs The same strategy as RebuildAdvanced except it adds up to 2 Monuments. It beats RebuildJack and also seems to perform better than it against other strategies, though this is based on only a few simulations of limited size.

Code: [Select]
using Dominion;
using CardTypes = Dominion.CardTypes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

//Author: SheCantSayNo

namespace Program
{
    public static partial class Strategies
    {
        public static class RebuildMonument
        {
            // big money smithy player
            public static PlayerAction Player(int playerNumber)
            {
                return new MyPlayerAction(playerNumber);
            }

            class MyPlayerAction
                : PlayerAction
            {
                public MyPlayerAction(int playerNumber)
                    : base("RebuildMonument",
                        playerNumber,
                        purchaseOrder: PurchaseOrder(),
                        treasurePlayOrder: Default.TreasurePlayOrder(),
                        actionOrder: ActionOrder())
                {
                }

                public override Type NameACard(GameState gameState)
                {

                    PlayerState currentPlayer = gameState.players.CurrentPlayer;

                    int score = gameState.players.CurrentPlayer.TotalScore() - gameState.players.OtherPlayers.First().TotalScore();

                    //Name Duchy
                    if (CountOfPile<CardTypes.Duchy>(gameState) > 0
                        && CountInDeckAndDiscard<CardTypes.Estate>(gameState) > 0
                        && (CountInDeckAndDiscard<CardTypes.Province>(gameState) == 0
                           || CountInDeck<CardTypes.Province>(gameState) == 0 && CountInDeck<CardTypes.Duchy>(gameState) > 0
                           && CountInDeck<CardTypes.Estate>(gameState) > 0))
                    {
                        return typeof(CardTypes.Duchy);
                    }

                    //Name Province if you are ensured of gaining a Province
                    if (CountInDeck<CardTypes.Estate>(gameState) == 0 && CountInDeck<CardTypes.Province>(gameState) >= 0
                        && CountInDeck<CardTypes.Duchy>(gameState) > 0)
                    {
                        return typeof(CardTypes.Province);
                    }

                    //Name Province if you are ensured of gaining a Province
                    if (CountInDeckAndDiscard<CardTypes.Estate>(gameState) == 0
                        && CountInDeckAndDiscard<CardTypes.Province>(gameState) >= 0
                        && CountInDeckAndDiscard<CardTypes.Duchy>(gameState) > 0)
                    {
                        return typeof(CardTypes.Province);
                    }

                    //Name Estate if you can end it with a win                   
                    if (CountInHand<CardTypes.Rebuild>(gameState) + 1 >= CountOfPile<CardTypes.Province>(gameState) && score > 0)
                    {
                        return typeof(CardTypes.Estate);
                    }

                    //Name Estate if it's the only thing left in your draw pile and the Duchies are gone
                    if (CountOfPile<CardTypes.Duchy>(gameState) == 0 && CountInDeck<CardTypes.Province>(gameState) == 0
                        && CountInDeck<CardTypes.Estate>(gameState) > 0)
                    {
                        return typeof(CardTypes.Estate);
                    }

                    //Name Province if Duchy is in Draw and Draw contains more P than E
                    if (CountOfPile<CardTypes.Duchy>(gameState) == 0 && CountInDeck<CardTypes.Duchy>(gameState) > 0
                        && CountInDeck<CardTypes.Province>(gameState) > CountInDeck<CardTypes.Estate>(gameState))                       
                    {
                        return typeof(CardTypes.Province);
                    }

                    //Name Estate if you're ahead and both P and E are left in draw
                    if (CountOfPile<CardTypes.Duchy>(gameState) == 0 && CountInDeck<CardTypes.Province>(gameState) > 0
                        && CountInDeck<CardTypes.Estate>(gameState) > 0 && score > 2)
                    {
                        return typeof(CardTypes.Estate);
                    }

                    //Name Estate over Province if you're way ahead
                    if (CountOfPile<CardTypes.Duchy>(gameState) == 0 && CountInDeckAndDiscard<CardTypes.Province>(gameState) > 0
                        && CountInDeckAndDiscard<CardTypes.Duchy>(gameState) < 3
                        && CountInDeckAndDiscard<CardTypes.Estate>(gameState) > 0 && score > 4)
                    {
                        return typeof(CardTypes.Estate);
                    }

                    //Province -> Province when ahead without any Duchies left
                    if (CountOfPile<CardTypes.Duchy>(gameState) == 0 && CountAllOwned<CardTypes.Duchy>(gameState) == 0
                       && score > 0)
                    {
                        return typeof(CardTypes.Estate);
                    }

                    //Province -> Province when ahead without any Duchies not in hand
                    if (CountOfPile<CardTypes.Duchy>(gameState) == 0 && CountInDeckAndDiscard<CardTypes.Duchy>(gameState) == 0
                        && CountInDeckAndDiscard<CardTypes.Province>(gameState) > 0 && score > 2)
                    {
                        return typeof(CardTypes.Estate);
                    }

                    if (CountInDeckAndDiscard<CardTypes.Province>(gameState) > 0)
                    {
                        return typeof(CardTypes.Province);
                    }

                    return typeof(CardTypes.Estate);
                }
            }

            private static int getScore(GameState gameState)
            {
                return gameState.players.CurrentPlayer.TotalScore() - gameState.players.OtherPlayers.First().TotalScore();
            }

            private static CardPickByPriority PurchaseOrder()
            {
                return new CardPickByPriority(                   
                           CardAcceptance.For<CardTypes.Province>(),
                           CardAcceptance.For<CardTypes.Rebuild>(gameState => CountAllOwned<CardTypes.Rebuild>(gameState) < 2),
                           //In non-mirrors, get a 3rd Rebuild
                           CardAcceptance.For<CardTypes.Rebuild>(gameState => CountAllOwned<CardTypes.Rebuild>(gameState) < 3
                           && CountOfPile<CardTypes.Rebuild>(gameState) > 7),
                           CardAcceptance.For<CardTypes.Duchy>(),
                           CardAcceptance.For<CardTypes.Estate>(gameState => CountOfPile<CardTypes.Province>(gameState) <= 1),
                           CardAcceptance.For<CardTypes.Estate>(gameState => CountOfPile<CardTypes.Province>(gameState) == 2
                           && getScore(gameState) > -8),                           
                           CardAcceptance.For<CardTypes.Gold>(),
                           CardAcceptance.For<CardTypes.Estate>(gameState => CountOfPile<CardTypes.Province>(gameState) <= 2),
                           CardAcceptance.For<CardTypes.Rebuild>(gameState => (CountAllOwned<CardTypes.Duchy>(gameState) > 0
                           || getScore(gameState) > 2) && (CountOfPile<CardTypes.Rebuild>(gameState) > 2 || getScore(gameState) > 3                           
                           || (CountOfPile<CardTypes.Rebuild>(gameState) == 1 && getScore(gameState) > 0) )),
                           CardAcceptance.For<CardTypes.Estate>(gameState => CountOfPile<CardTypes.Duchy>(gameState) >= 4
                           && CountAllOwned<CardTypes.Duchy>(gameState) == 0 && CountAllOwned<CardTypes.Estate>(gameState) == 0),
                           CardAcceptance.For<CardTypes.Estate>(gameState => CountOfPile<CardTypes.Duchy>(gameState) == 0
                           && CountAllOwned<CardTypes.Duchy>(gameState) == 0),
                           CardAcceptance.For<CardTypes.Monument>(gameState =>
                               CountAllOwned<CardTypes.Monument>(gameState) < 2),
                           CardAcceptance.For<CardTypes.Silver>());
            }

            private static CardPickByPriority ActionOrder()
            {
                return new CardPickByPriority(
                           CardAcceptance.For<CardTypes.Rebuild>(gameState =>
                           !(gameState.players.CurrentPlayer.ExpectedCoinValueAtEndOfTurn >= 8
                           && CountOfPile<CardTypes.Province>(gameState) == 1)
                           && !(CountOfPile<CardTypes.Duchy>(gameState) == 0
                           && CountInDeckAndDiscard<CardTypes.Duchy>(gameState) == 0 && getScore(gameState) < 0)
                           && CountOfPile<CardTypes.Province>(gameState) > 0),
                           CardAcceptance.For<CardTypes.Monument>());
            }                       
        }
    }
}
« Last Edit: October 04, 2013, 11:43:00 am by SheCantSayNo »
Logged

SCSN

  • Mountebank
  • *****
  • Offline Offline
  • Posts: 2227
  • Respect: +7140
    • View Profile
Re: Simulation verified engine beats bigmoney using Rats/WM/WT/Armory/Bridge
« Reply #16 on: October 04, 2013, 10:52:26 am »
0

And to add something that's actually relevant to the topic, your RatsWanderingMinstrelWatchtowerArmory strategy

wins 45.7% against RebuildAdvanced
wins 40.2% against RebuildJack
wins 36.5% against RebuildMonument

Though the last one isn't a fair match-up, as I expect the engine to win if it only buys Monuments instead of Bridges (well, maybe one Bridge for the +buy) and focuses on playing Monuments as much as possible.
« Last Edit: October 04, 2013, 11:51:10 am by SheCantSayNo »
Logged

Sparafucile

  • Thief
  • ****
  • Offline Offline
  • Posts: 98
  • Respect: +153
    • View Profile
Re: Simulation verified engine beats bigmoney using Rats/WM/WT/Armory/Bridge
« Reply #17 on: October 04, 2013, 01:05:58 pm »
+2

Wow.  Your advanced rebuild strategy is quite detailed.     Thanks for the additional strategies and comparisons.  I'm glad you are having fun playing with the simulator.  You seem to have picked it up quite quickly.  I will see  - I may start a dedicated post to my simulator.

I checked in the strategies you authored.   I took the liberty of formatting the code, and refactoring for reuse.  Please pull from the head of the GIT repository.  Let me know if I missed anything when reorganzing.

Quote
I'd very much like to specify both the starting decks for each player and the supply piles. As a concrete example: I want to be able to let both players start with 2 Rebuilds and 4 Duchies in their deck (and 0 Duchies left in the supply), but one of the players has an Estate whereas the other has none.

I also made a submission to demonstrate how you can tweak the starting decks of the players.  I took your example, and gave each player 5 silvers and 2 golds.  That seems to be roughly what RebuildAdvanced gets in practice.

Looks like starting with an estate is a liability once all the duchies are gone:

42.9% win RebuildAdvanced with a starting estate
54.4% win RebuildAdvanced with only duchies

Here's how I setup assymettric starting decks:
Code: [Select]
static void Main()
        {
            ComparePlayers(Strategies.RebuildAdvanced.Player(1), Strategies.RebuildAdvanced.Player(2), startingDeckPerPlayer: StartingDecksForRebuildWithEstateAdvantage.StartingDecks);           
        }

        class StartingDecksForRebuildWithEstateAdvantage
            : StartingDeckBuilder
        {
            static new public IEnumerable<CardCountPair>[] StartingDecks
            {
                get
                {
                    return StartingDecks(
                       StartingDeck(
                            CardWithCount<CardTypes.Copper>(7),
                            CardWithCount<CardTypes.Estate>(1),
                            CardWithCount<CardTypes.Silver>(5),
                            CardWithCount<CardTypes.Gold>(2),
                            CardWithCount<CardTypes.Rebuild>(2),
                            CardWithCount<CardTypes.Duchy>(4)),
                       StartingDeck(
                            CardWithCount<CardTypes.Copper>(7),
                            CardWithCount<CardTypes.Silver>(5),
                            CardWithCount<CardTypes.Gold>(2),
                            CardWithCount<CardTypes.Rebuild>(2),
                            CardWithCount<CardTypes.Duchy>(4))
                            );
                }
            }
        }
Logged

SCSN

  • Mountebank
  • *****
  • Offline Offline
  • Posts: 2227
  • Respect: +7140
    • View Profile
Re: Simulation verified engine beats bigmoney using Rats/WM/WT/Armory/Bridge
« Reply #18 on: October 04, 2013, 07:24:18 pm »
0

Thanks a lot, especially for the asymmetric starting decks functionality!

Quote
I checked in the strategies you authored.   I took the liberty of formatting the code, and refactoring for reuse.  Please pull from the head of the GIT repository.  Let me know if I missed anything when reorganzing.

It looks great, and easily extendable indeed! One small thing: RebuildMonument should gain 2 Monuments max, not 3. I guess you copied my script before I edited my post :) There's also some stray commentary "// big money smithy player" here and there. I copied that over from your Rebuild script, but I think it's better to just remove it, as it's more confusing than illuminating ;)

It might also be an idea to move all the methods that correspond to the testing of specific strategies that are currently in program.cs to a separate file (simulations.cs, say), as over time these will really start to clog the main file.

I have one more (probably very silly) question:

Quote
           private static CardPickByPriority ActionOrder(Card withCard)
            {
                return new CardPickByPriority(
                           CardAcceptance.For<CardTypes.Rebuild>(ShouldPlayRebuild),
                           new CardAcceptance(withCard)
                           );
            }           

            private static bool ShouldPlayRebuild(GameState gameState)
            {
                return !(gameState.players.CurrentPlayer.ExpectedCoinValueAtEndOfTurn >= 8 && CountOfPile<CardTypes.Province>(gameState) == 1)
                       && !(CountOfPile<CardTypes.Duchy>(gameState) == 0
                       && CountInDeckAndDiscard<CardTypes.Duchy>(gameState) == 0 && PlayersPointLead(gameState) < 0)
                       && CountOfPile<CardTypes.Province>(gameState) > 0;
            }

Why doesn't send the bolded part "gameState" as an argument, even though the method ShouldPlayRebuild requires it?
Logged

Sparafucile

  • Thief
  • ****
  • Offline Offline
  • Posts: 98
  • Respect: +153
    • View Profile
Re: Simulation verified engine beats bigmoney using Rats/WM/WT/Armory/Bridge
« Reply #19 on: October 04, 2013, 10:06:37 pm »
0

I will be cleaning up program.cs.   I agree it's too cluttered, just haven't gotten around to it yet.

Quote
Why doesn't send the bolded part "gameState" as an argument, even though the method ShouldPlayRebuild requires it?

ShouldPlayRebuild is a delegate or method.   It's a delegate that you are actually always passing in as the argument to CardAcceptance.For<T>.    Usually you are used to seeing soemthing more like CardAcceptance.For<T>(gamestate => something about gamestate).  This syntax with the arrow is also just creating a delegate.
Logged

SCSN

  • Mountebank
  • *****
  • Offline Offline
  • Posts: 2227
  • Respect: +7140
    • View Profile
Re: Simulation verified engine beats bigmoney using Rats/WM/WT/Armory/Bridge
« Reply #20 on: October 05, 2013, 04:48:22 pm »
0

RebuildDuke.cs A really simple to execute yet deceptively strong combo. It should be played differently than standard Rebuild strategies, so it can't inherit their rules.

Code: [Select]
using Dominion;
using CardTypes = Dominion.CardTypes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

//Author: SheCantSayNo

namespace Program
{
    public static partial class Strategies
    {
        public static class RebuildDuke
        {
            public static PlayerAction Player(int playerNumber)
            {
                return new MyPlayerAction(playerNumber);
            }

            class MyPlayerAction
                : PlayerAction
            {
                public MyPlayerAction(int playerNumber)
                    : base("RebuildDuke",
                        playerNumber,
                        purchaseOrder: PurchaseOrder(),
                        treasurePlayOrder: Default.TreasurePlayOrder(),
                        actionOrder: ActionOrder())
                {
                }

                public override Type NameACard(GameState gameState)
                {                   
                    PlayerState currentPlayer = gameState.players.CurrentPlayer;
                   
                    return typeof(CardTypes.Duchy);
                }
            }

            private static CardPickByPriority PurchaseOrder()
            {
                return new CardPickByPriority(
                           CardAcceptance.For<CardTypes.Rebuild>(gameState => CountAllOwned<CardTypes.Rebuild>(gameState) < 2),
                           CardAcceptance.For<CardTypes.Duchy>(),
                           CardAcceptance.For<CardTypes.Province>(),
                           CardAcceptance.For<CardTypes.Duke>(),                           
                           CardAcceptance.For<CardTypes.Estate>(gameState => CountAllOwned<CardTypes.Estate>(gameState) == 0 && CountAllOwned<CardTypes.Rebuild>(gameState) >= 2),
                           CardAcceptance.For<CardTypes.Estate>(gameState => CountOfPile<CardTypes.Duchy>(gameState) == 0),
                           CardAcceptance.For<CardTypes.Rebuild>(),                           
                           CardAcceptance.For<CardTypes.Silver>());
            }

            private static CardPickByPriority ActionOrder()
            {
                return new CardPickByPriority(
                           CardAcceptance.For<CardTypes.Rebuild>());
            }
        }
    }
}

I'm happy to also contribute to the project itself, e.g. by adding cards. I'd like to program the Hermit-Market Square combo and do some simulations with Cultist, none of which are (fully) implemented atm, so they seem to me as good a start as any. I'm fine with just playing around, checking out how other cards are done and trying to copy those methods, but I'm not very experienced, so any kind of directions or guidance would be very welcome.
Logged

Sparafucile

  • Thief
  • ****
  • Offline Offline
  • Posts: 98
  • Respect: +153
    • View Profile
Re: Simulation verified engine beats bigmoney using Rats/WM/WT/Armory/Bridge
« Reply #21 on: October 05, 2013, 09:46:10 pm »
0

I fixed the monument rebuild.  Added RebuildDuchy.   I also looked over Cultist.  It had an exception, but I removed it as I believe the card is fully implemented, though not tested.  Why don't you start with Cultist strategies :).  Let me know if there's a bug with it.

I was going to do hermit card next - as I am also interested in seeing what the hermit/market square strat would look like.
Logged
Pages: [1]
 

Page created in 2.513 seconds with 20 queries.