Page 2 of 2

Re: Send me your decks for an AI Legacy tournament!

PostPosted: 14 Apr 2016, 00:15
by Xyx
serrasmurf wrote:I won! I guess the odds were with me :D
They sure were, but it's deserved nonetheless. The gobbo deck really is much stronger than the rest. Expect some hate next time!

serrasmurf wrote:Good idea to repeat it (next month?).
I would like to. :) Gonna run fewer rounds with more matches, though. Make it a little easier on myself and reduce variance.

serrasmurf wrote:You could also make an additional post in the deckbuilding section and send some prime deck builders over there a personal message to recruit them.
I wouldn't know where to begin. Can I ask you to do that?

serrasmurf wrote:You could also alternate between legacy/modern/standard..
Sure, maybe later. The reason I didn't want to go Vintage is because it's way higher variance, but I suppose we can do even that if we run enough games per match.

Taris36 wrote:I should probably modify my Burn Hotter deck with more player burn for next time.
Yeah. One of my decks was full of Young Wolf and Carrier Thrall because they soak up removal. The AI will burn basically anything with toughness, so those are cheap 2-for-1s. Not good against goblins or merfolk, though.

Don't hesitate to run some games yourself and watch how things play out. I haven't yet, but I'm certainly going to check what makes the gobbos and merfolk decks tick and what I can do to fight that (my guess is Anger of the Gods and Toxic Deluge, but we'll see).

Re: Send me your decks for an AI Legacy tournament!

PostPosted: 14 Apr 2016, 03:03
by friarsol
The forum just ate a response I had written up so I'll quickly summarize

A few new CLI parameters will be available in the next release:

-m <1,3,5..> to play a match of length X. Instead of just letting you run Y amount of games, now an actual match will be setup with the first to X/2+1 wins.
-q Quiet flag. Instead of saving a full log, we'll only output match and game results. Should be easier to parse.

As far as deck naming, the name provided to -d has to match the name inside the .dck file. If you want to make use of subfolders, I've added this ability, but you'll need to point to the actual .dck file. The simulator will automatically start looking in "<USER_DIR>\decks\constructed\" (or \commander if you are using that format) when using the filename.

sim -d "dueldecks\GoblinsElves vs Goblins.dck" "dueldecks\ElvesElves vs Goblins.dck" -m 3 -q

Edit: Looks like Krazy beat me to the punch, the subfolders didn't actually make it into the 1.5.51 release, but it'll be in any snapshot of .52.

Re: Send me your decks for an AI Legacy tournament!

PostPosted: 17 Apr 2016, 02:57
by friarsol
Since before these posts showed up I had been working on some Tournament code for Forge (to have actual tournaments, and also to better allow for Conspiracy, which I still would like to be more fully working inside Forge). So adding them into the Simulator was a pretty natural step. The code isn't quite committed, but some additions to the Bracket and RoundRobin have been made to help in this process for anyone interested in having AI tournaments in the future.

Here's a round robin tournament I ran with the same decks Xyx just ran (I had run with 5 game matches earlier, but realized it only did 11 rounds due to a small bug with the Bye fake player):

Name Wins Losses Ties
serrasmurfGoblins 10 2 0
QuestVicStone3 9 3 0
serrasmurfSneakShow 9 3 0
serrasmurfBurn 8 4 0
serrasmurfMerfolk 8 4 0
serrasmurfReanimatePox 8 4 0
ZhycksRock 8 4 0
serrasmurfTurboEldrazi 6 6 0
ZhycksJund 4 8 0
serrasmurfJund 3 9 0
serrasmurfEnchantress 2 10 0
Taris36BurnHotter 2 10 0
ZhycksPunish 1 11 0


I haven't started outputting GameWins/Losses yet. But can output whatever seems the most useful.

Re: Send me your decks for an AI Legacy tournament!

PostPosted: 17 Apr 2016, 09:35
by Xyx
Sweet! I bet I could also use that to make quest opponents fight one another to get a quick sense of their difficulty ratings. (Vic Stone keeps doing pretty well here.)

Is there a command to make all decks in a certain folder fight each other in a round robin? That would be ideal.

Re: Send me your decks for an AI Legacy tournament!

PostPosted: 17 Apr 2016, 13:07
by friarsol
Xyx wrote:Is there a command to make all decks in a certain folder fight each other in a round robin? That would be ideal.
Ah good idea. I'll tinker around with that.

Re: Send me your decks for an AI Legacy tournament!

PostPosted: 03 May 2016, 15:03
by friarsol
.52 added some more love for simulations:

Syntax: forge.exe sim -d <deck1[.dck]> ... <deckX[.dck]> -D [D] -n [N] -m [M] -t [T] -p [P] -f [F] -q"
sim - stands for simulation mode
deck1 (or deck2,...,X) - constructed deck name or filename (has to be quoted when contains multiple words)
deck is treated as file if it ends with a dot followed by three numbers or letters
D - absolute directory to load decks from
N - number of games, defaults to 1 (Ignores match setting)
M - Play full match of X games, typically 1,3,5 games. (Optional, overrides N)
T - Type of tournament to run with all provided decks (Bracket, RoundRobin, Swiss)
F - format of games, defaults to constructed
q - Quiet flag. Output just the game result, not the entire game log.

I wouldn't exactly call the swiss mode "perfect" but it seems to do a decent job of it. If you notice something odd, especially if its reproduceable lemme know and I'll see if I can fix it. I tried running a few 100 man swiss tournaments, but Forge couldn't quite handle that.

I ran a Round Robin of the 13 Pro Tour Gauntlet decks and this is how the AI faired:
Code: Select all
Name                                      Score   W(By)   L   T
Grzegorz Kowalski - Sultai Midrange      30   10(0)   2   0
Marcos Paulo de Jesus Freitas - Green-Red Ramp   30   10(0)   2   0
Patrick Cox - Mono-White Humans              30   10(0)   2   0
Michael Majors - White Blue Humans      24   8(0)   4   0
Andrea Mengucci - Bant Company              21   7(0)   5   0
Luis Salvatto - Red-White Eldrazi Goggles   18   6(0)   6   0
Seth Manfield - Esper Control (PT SOI)      18   6(0)   6   0
Steve Rubin - Green-White Tokens      18   6(0)   6   0
Brad Nelson - Goggles Ramp              12   4(0)   8   0
Luis Scott-Vargas - Black-Green Aristocrats   12   4(0)   8   0
Shota Yasooka - Esper Dragons              12   4(0)   8   0
Rob Pisano - Jeskai Control              6   2(0)   10   0
Jon Finkel - Seasons Past Control      3   1(0)   11   0

Re: Send me your decks for an AI Legacy tournament!

PostPosted: 03 May 2016, 18:58
by Xyx
Wow, awesome! That is sooo much easier. I'm definitely looking forward to making the AI tournament a thing, now.

Anyone have suggestions how we should run the tournament? Should we do different formats? Standard rotates, so that's more interesting from a deckbuilding perspective than Legacy, which is mostly about optimizing an existing deck for the meta. Vintage is possible, too, now. I didn't want to do Vintage because of the variance, but with these new features that's just a matter of upping the match length and letting Forge crunch some more numbers.

I tried the same decks as last tournament, round robin, best of 3. Different results each time:

Code: Select all
Name      Score   W(By)   L   T
ZhycksRock      30      10(0)   2   0
QuestVicStone3      24      8(0)   4   0
serrasmurfBurn      24      8(0)   4   0
serrasmurfJund      24      8(0)   4   0
serrasmurfMerfolk      21      7(0)   5   0
serrasmurfReanimatePox      21      7(0)   5   0
serrasmurfSneakShow      21      7(0)   5   0
serrasmurfGoblins      18      6(0)   6   0
serrasmurfTurboEldrazi      18      6(0)   6   0
Taris36BurnHotter      12      4(0)   8   0
ZhycksJund      12      4(0)   8   0
serrasmurfEnchantress      6      2(0)   10   0
ZhycksPunish      3      1(0)   11   0
And...

Code: Select all
Name      Score   W(By)   L   T
QuestVicStone3      27      9(0)   3   0
ZhycksRock      27      9(0)   3   0
serrasmurfGoblins      24      8(0)   4   0
serrasmurfMerfolk      24      8(0)   4   0
ZhycksJund      24      8(0)   4   0
serrasmurfSneakShow      21      7(0)   5   0
serrasmurfBurn      18      6(0)   6   0
serrasmurfJund      15      5(0)   7   0
serrasmurfTurboEldrazi      15      5(0)   7   0
Taris36BurnHotter      15      5(0)   7   0
serrasmurfReanimatePox      12      4(0)   8   0
serrasmurfEnchantress      9      3(0)   9   0
ZhycksPunish      3      1(0)   11   0
So clearly there's still a lot of variance.

I then tried best of 9 but got a GINORMOUS stack overflow error in round 5 (70% snipped out so I could post it here, but that's all repetitive):

Error | Open
Language 'java.util.PropertyResourceBundle@128cdfa' loaded successfully.
(ThreadUtil first call): Running on a machine with 4 cpu core(s)
Read cards: 15691 archived files in 1246 ms (25 parts) using thread pool
Read decks (605 ms): 0 constructed, 0 sealed, 0 draft, 4 cubes, 0 scheme, 0 planar, 0 commander.
Simulation mode
[AI Preferences] AI profile Default was chosen for the lobby player QuestVicStone3.
[AI Preferences] AI profile Default was chosen for the lobby player serrasmurfBurn.
[AI Preferences] AI profile Default was chosen for the lobby player serrasmurfEnchantress.
[AI Preferences] AI profile Default was chosen for the lobby player serrasmurfGoblins.
[AI Preferences] AI profile Default was chosen for the lobby player serrasmurfJund.
[AI Preferences] AI profile Default was chosen for the lobby player serrasmurfMerfolk.
[AI Preferences] AI profile Default was chosen for the lobby player serrasmurfReanimatePox.
[AI Preferences] AI profile Default was chosen for the lobby player serrasmurfSneakShow.
[AI Preferences] AI profile Default was chosen for the lobby player serrasmurfTurboEldrazi.
[AI Preferences] AI profile Default was chosen for the lobby player Taris36BurnHotter.
[AI Preferences] AI profile Default was chosen for the lobby player ZhycksJund.
[AI Preferences] AI profile Default was chosen for the lobby player ZhycksPunish.
[AI Preferences] AI profile Default was chosen for the lobby player ZhycksRock.
[AI Preferences] AI profile Default was chosen for the lobby player BYE.
Starting a RoundRobin tournament with 13 players over 13 rounds

Round 1 Pairings:
serrasmurfBurn[0] BYE
serrasmurfEnchantress[0] vs ZhycksJund[0]
QuestVicStone3[0] vs serrasmurfTurboEldrazi[0]
Taris36BurnHotter[0] vs ZhycksPunish[0]
ZhycksRock[0] vs serrasmurfJund[0]
serrasmurfGoblins[0] vs serrasmurfMerfolk[0]
serrasmurfSneakShow[0] vs serrasmurfReanimatePox[0]

/// SNIP!!

Round 5 - ZhycksPunish[0] vs serrasmurfTurboEldrazi[3]
Game outcome: ZhycksPunish has lost because life total reached 0
Game outcome: serrasmurfTurboEldrazi has won because all opponents have lost
Match result: ZhycksPunish: 0 serrasmurfTurboEldrazi: 1

Game 1 ended in 1101 ms. serrasmurfTurboEldrazi has won!

Game outcome: ZhycksPunish has lost because life total reached 0
Game outcome: serrasmurfTurboEldrazi has won because all opponents have lost
Match result: ZhycksPunish: 0 serrasmurfTurboEldrazi: 2

Game 2 ended in 795 ms. serrasmurfTurboEldrazi has won!

Game outcome: ZhycksPunish has won because all opponents have lost
Game outcome: serrasmurfTurboEldrazi has lost because life total reached 0
Match result: ZhycksPunish: 1 serrasmurfTurboEldrazi: 2

Game 3 ended in 1192 ms. ZhycksPunish has won!

main > java.lang.StackOverflowError
at java.util.HashMap.hash(Unknown Source)
at java.util.HashMap.containsKey(Unknown Source)
at forge.trackable.TrackableTypes$TrackableObjectType.updateObjLookup(TrackableTypes.java:61)
at forge.trackable.TrackableTypes$TrackableObjectType.updateObjLookup(TrackableTypes.java:39)
at forge.trackable.TrackableProperty.updateObjLookup(TrackableProperty.java:172)
at forge.trackable.TrackableObject.set(TrackableObject.java:66)
at forge.game.spellability.SpellAbilityView.updateHostCard(SpellAbilityView.java:43)
at forge.game.spellability.SpellAbilityView.<init>(SpellAbilityView.java:29)
at forge.game.spellability.SpellAbility.<init>(SpellAbility.java:150)
at forge.game.spellability.SpellAbility.<init>(SpellAbility.java:143)
at forge.game.spellability.AbilitySub.<init>(AbilitySub.java:85)
at forge.game.spellability.AbilitySub.getCopy(AbilitySub.java:107)
at forge.game.card.CardFactory.copySpellAbility(CardFactory.java:643)
at forge.game.spellability.AbilitySub.getCopy(AbilitySub.java:108)
at forge.game.replacement.ReplacementEffect.getCopy(ReplacementEffect.java:149)
at forge.game.card.CardState.copyFrom(CardState.java:367)
at forge.game.card.CardFactory.copyState(CardFactory.java:606)
at forge.game.card.CardFactory.copyCopiableCharacteristics(CardFactory.java:511)
at forge.game.ability.effects.CloneEffect.resolve(CloneEffect.java:124)
at forge.game.spellability.AbilitySub.resolve(AbilitySub.java:119)
at forge.game.ability.AbilityUtils.resolveApiAbility(AbilityUtils.java:1236)
at forge.game.ability.AbilityUtils.resolveSubAbilities(AbilityUtils.java:1229)
at forge.game.ability.AbilityUtils.resolveApiAbility(AbilityUtils.java:1243)
at forge.game.ability.AbilityUtils.resolve(AbilityUtils.java:1218)
at forge.ai.ComputerUtil.playNoStack(ComputerUtil.java:269)

// SNIP!

at forge.ai.ComputerUtil.playNoStack(ComputerUtil.java:269)
at forge.ai.PlayerControllerAi.playSpellAbilityNoStack(PlayerControllerAi.java:314)
at forge.game.replacement.ReplacementHandler.executeReplacement(ReplacementHandler.java:235)
at forge.game.replacement.ReplacementHandler.run(ReplacementHandler.java:134)
at forge.game.replacement.ReplacementHandler.run(ReplacementHandler.java:67)
at forge.game.GameAction.changeZone(GameAction.java:220)
at forge.game.GameAction.moveTo(GameAction.java:449)
at forge.game.GameAction.moveTo(GameAction.java:430)
at forge.game.GameAction.moveToPlay(GameAction.java:536)
at forge.game.ability.effects.ETBReplacementEffect.resolve(ETBReplacementEffect.java:14)
at forge.game.spellability.AbilitySub.resolve(AbilitySub.java:119)
at forge.game.ability.AbilityUtils.resolveApiAbility(AbilityUtils.java:1236)
at forge.game.ability.AbilityUtils.resolveSubAbilities(AbilityUtils.java:1229)
at forge.game.ability.AbilityUtils.resolveApiAbility(AbilityUtils.java:1243)
at forge.game.ability.AbilityUtils.resolveSubAbilities(AbilityUtils.java:1229)
at forge.game.ability.AbilityUtils.resolveApiAbility(AbilityUtils.java:1243)
at forge.game.ability.AbilityUtils.resolve(AbilityUtils.java:1218)
at forge.ai.ComputerUtil.playNoStack(ComputerUtil.java:269)
at forge.ai.PlayerControllerAi.playSpellAbilityNoStack(PlayerControllerAi.java:314)
at forge.game.replacement.ReplacementHandler.executeReplacement(ReplacementHandler.java:235)
at forge.game.replacement.ReplacementHandler.run(ReplacementHandler.java:134)
at forge.game.replacement.ReplacementHandler.run(ReplacementHandler.java:67)
at forge.game.GameAction.changeZone(GameAction.java:220)
at forge.game.GameAction.moveTo(GameAction.java:449)
at forge.game.GameAction.moveTo(GameAction.java:430)
at forge.game.GameAction.moveToPlay(GameAction.java:536)
at forge.game.ability.effects.ETBReplacementEffect.resolve(ETBReplacementEffect.java:14)
at forge.game.spellability.AbilitySub.resolve(AbilitySub.java:119)
at forge.game.ability.AbilityUtils.resolveApiAbility(AbilityUtils.java:1236)
at forge.game.ability.AbilityUtils.resolveSubAbilities(AbilityUtils.java:1229)
at forge.game.ability.AbilityUtils.resolveApiAbility(AbilityUtils.java:1243)
at forge.game.ability.AbilityUtils.resolveSubAbilities(AbilityUtils.java:1229)
at forge.game.ability.AbilityUtils.resolveApiAbility(AbilityUtils.java:1243)
at forge.game.ability.AbilityUtils.resolve(AbilityUtils.java:1218)
at forge.ai.ComputerUtil.playNoStack(ComputerUtil.java:269)
at forge.ai.PlayerControllerAi.playSpellAbilityNoStack(PlayerControllerAi.java:314)
at forge.game.replacement.ReplacementHandler.executeReplacement(ReplacementHandler.java:235)
at forge.game.replacement.ReplacementHandler.run(ReplacementHandler.java:134)
at forge.game.replacement.ReplacementHandler.run(ReplacementHandler.java:67)
at forge.game.GameAction.changeZone(GameAction.java:220)
at forge.game.GameAction.moveTo(GameAction.java:449)
at forge.game.GameAction.moveTo(GameAction.java:430)
at forge.game.GameAction.moveToPlay(GameAction.java:536)
at forge.game.ability.effects.ETBReplacementEffect.resolve(ETBReplacementEffect.java:14)
at forge.game.spellability.AbilitySub.resolve(AbilitySub.java:119)
at forge.game.ability.AbilityUtils.resolveApiAbility(AbilityUtils.java:1236)
at forge.game.ability.AbilityUtils.resolveSubAbilities(AbilityUtils.java:1229)
at forge.game.ability.AbilityUtils.resolveApiAbility(AbilityUtils.java:1243)

Other than that, if you're up for any feature requests...
  • Some kind of notification when the tournament is done, preferably with a progress update every round so that I can get an idea of how long it's going to take. Currently, I have to watch for javaw.exe activity in Windows Task Manager.
  • Output results using spaces instead of tabs. The tabs format is messed up both in Notepad and here on the forum in [Code] tags. It's still clear who won, though.
Other than that, I'd say it's pretty much perfect. :)

Re: Send me your decks for an AI Legacy tournament!

PostPosted: 03 May 2016, 19:46
by friarsol
Xyx wrote:
  • Some kind of notification when the tournament is done, preferably with a progress update every round so that I can get an idea of how long it's going to take. Currently, I have to watch for javaw.exe activity in Windows Task Manager.
  • Output results using spaces instead of tabs. The tabs format is messed up both in Notepad and here on the forum in [Code] tags. It's still clear who won, though.
Other than that, I'd say it's pretty much perfect. :)
Ah right, I meant to mention that, but I haven't been playing with it in a while.

I use was using a "tailer" to just follow the forge.log instead of needing to peek at the running process. I believe the one I was using was "baretail" but their website isn't loading right now, http://snakenest.com/snaketail/ seems like roughly the same thing. I'm sure if you search for "tail log file" you can find one that works for your needs.

At some point I'll see if I can make use of Forge loading dialog to show the current round/games, but I haven't figured out how to get it to work for me yet.

Yea, the standings output is definitely messed up, I'll see if I can come up with some better options.

Edit: Looks like that Crash is due to the AI starting the game with - Vesuva (no clone), Vesuva (clone Vesuva) with no other lands. Or more likely - Eye of Ugin, Vesuva, Vesuva. Since Vesuva is coded not to clone legendary permanents you already control.

Re: Send me your decks for an AI Legacy tournament!

PostPosted: 03 May 2016, 21:02
by Xyx
friarsol wrote:Looks like that Crash is due to the AI starting the game with - Vesuva (no clone), Vesuva (clone Vesuva) with no other lands. Or more likely - Eye of Ugin, Vesuva, Vesuva. Since Vesuva is coded not to clone legendary permanents you already control.
You mean it's recursively cloning? It's not supposed to work like that. Copying a blank Vesuva just gives you a blank Vesuva.

Re: Send me your decks for an AI Legacy tournament!

PostPosted: 09 Apr 2017, 23:57
by Voda
Is there a way to prevent the simulator from checking deck compliance ? What I'm trying to do is running some 40 cards decks matches, and all I am getting is "could not load deck". I've tried to add "-f Limited" or "-f Sealed", but nothing quite made it.

Re: Send me your decks for an AI Legacy tournament!

PostPosted: 30 Sep 2019, 16:28
by Glandalf
Hi I post here because I though the first post about Headless mode has been made here ^^
Do you know any flag I can use for having a more efficient log file?
I need information like all casted spell for each game as well as the strategic responses from an AI to an other.

Thank you for your help.