<Main()
>=
public static void
main(String args[])
// Play some number of Eagle's Wing games using some playing style. Print
// the number of games won and lost to std-out.
<handle command-line arguments>
<play the games>
DefinesMain
(links are to index).Used below.
The only manditory command-line argument is a non-negative integer giving the number of games to play. For interest, there are two other optional command-line arguments:
-s
n
: Use the integer n
as the seed for
the random-number generator used to shuffle the card decks. The default seed
is based on the time.
-p
s
: Play the games using strategy s
,
which can be one of random
(the default), biased
, or
strongBiased
.
<handle command-line arguments>= final CommandLineOptions clo = new CommandLineOptions(new String [] "p", "random" , "play style", "s", "" + (int) new Date().getTime(), "random-number seed" }) int gameCount = doArgs(clo.doOptions(args)), gamesWon = 0, gamesLost = 0 long seed = clo.getInt("s")
Used above.
Once everything’s squared away, let the games begin.
<play the games>= GamePlayStyles style try { style = GamePlayStyles.valueOf(clo.getString("p")); } catch (Exception e) System.err.println("Unrecognized game-play style. Recognized styles are") System.err.println("\"random\", \"biased\", or \"strongBiased\".") System.exit(1) while --gameCount > -1 if style.play(seed++) gamesWon++ else gamesLost++ System.out.println("Won: " + gamesWon + " lost: " + gamesLost)
Used above.
<game-play strategies>= private enum GamePlayStyles <random-play strategy>, <biased-play strategy>, <strong-biased-play strategy> // Create, using the given seed, and play an Eagle's Wing game. Return true // if the game ended in a win. abstract boolean play(long seed)
DefinesGamePlayStyles
(links are to index).Used below.
The play strategies are implemented with the
template pattern using
Java 5's enumeration type. The GamePlayStyles
class defines the
abstract play()
method, which is implemented as appropriate by each member
of the enumeration.
The main advantage of using enums, apart from a neat implementation of the
template pattern, is using the valueOf()
enum method to map between a
string representing the play style and the associated enum.
<random-play strategy>= random() boolean play(long seed) final EaglesWing game = EaglesWing.newGame(seed) final CardPiles.PairFun pairFun = new CardPiles.PairFun() public int f(CardPiles fromPile, CardPiles toPile) makeMove(game, fromPile, toPile) return 0 do CardPiles.pairIterate(pairFun) while game.movesPossible() return game.gameWon()
Definesrandom
(links are to index).Used above.
<biased-play strategy>= biased() boolean play(long seed) final EaglesWing game = EaglesWing.newGame(seed) do foundationPlay(game) nonfoundationPlay(game) while game.movesPossible() return game.gameWon()
Definesbiased
(links are to index).Used above.
Biased play in favor of foundation piles makes a pass through all possible moves, making each that involves foundation piles and ignoring the rest.
<biased-play methods>= private static void foundationPlay(final EaglesWing game) CardPiles.pairIterate(new CardPiles.PairFun() public int f(CardPiles fromPile, CardPiles toPile) if pileGroup(toPile) == CardPiles.Group.foundationPile makeMove(game, fromPile, toPile) return 0 })
DefinesfoundationPlay
(links are to index).
Biased play against foundation piles is just the opposite: make any move not involving foundation piles.
<biased-play methods>+= private static void nonfoundationPlay(final EaglesWing game) // Iterate through all possible non-foundation moves in the given game, // making each legal move once. CardPiles.pairIterate(new CardPiles.PairFun() public int f(CardPiles fromPile, CardPiles toPile) if pileGroup(toPile) ≠ CardPiles.Group.foundationPile makeMove(game, fromPile, toPile) return 0 })
DefinesnonfoundationPlay
(links are to index).Used below; previous definition.
<strong-biased-play strategy>= strongBiased() boolean play(long seed) final EaglesWing game = EaglesWing.newGame(seed) do strongFoundationPlay(game) tieredWeakNonfoundationPlay(game) while game.movesPossible() return game.gameWon()
DefinesstrongBiased
(links are to index).Used above.
A strong bias towards foundation-pile moves keeps passing through all possible moves utill there are no more foundation-pile moves possible.
<strong-biased-play methods>= private static void strongFoundationPlay(final EaglesWing game) // Repeatedly make foundation moves in the given game until there aren't // any more. class StrongFoundationFun implements CardPiles.PairFun boolean iterateAgain public int f(CardPiles fromPile, CardPiles toPile) if pileGroup(toPile) == CardPiles.Group.foundationPile if makeMove(game, fromPile, toPile) iterateAgain = true return 0 final StrongFoundationFun strongFoundationFun = new StrongFoundationFun() do strongFoundationFun.iterateAgain = false CardPiles.pairIterate(strongFoundationFun) while strongFoundationFun.iterateAgain
DefinesstrongFoundationPlay
(links are to index).
A strong bias against non-foundation-pile moves quits searching for moves after the first successful non-foundation move is found. In addition, because it's always possible to move cards between the stock and waste piles, the search for non-foundation moves also excludes waste- and stock-pile moves. If no other non-foundation moves are found then the apropriate stock-waste move is made as a last resort.
<strong-biased-play methods>+= private static void tieredWeakNonfoundationPlay(final EaglesWing game) class CountingPairFun implements CardPiles.PairFun boolean moved = false public int f(CardPiles fromPile, CardPiles toPile) if (pileGroup(toPile) ≠ CardPiles.Group.foundationPile ∧ ( (pileGroup(fromPile) ≠ CardPiles.Group.stockPile) ∨ (pileGroup(toPile) ≠ CardPiles.Group.wastePile)) ∧ ( (pileGroup(fromPile) ≠ CardPiles.Group.wastePile) ∨ (pileGroup(toPile) ≠ CardPiles.Group.stockPile))) if makeMove(game, fromPile, toPile) moved = true return 2 return 0 final CountingPairFun countingPairFun = new CountingPairFun() CardPiles.pairIterate(countingPairFun) if !countingPairFun.moved if game.size(CardPiles.stock) > 0 makeMove(game, CardPiles.stock, CardPiles.waste) else makeMove(game, CardPiles.waste, CardPiles.stock)
DefinestieredWeakNonfoundationPlay
(links are to index).Used below; previous definition.
And that's about it; the rest is utility.
<player/Main.java
>= package player import playerAPI.EaglesWing import playerAPI.EaglesWingStatus import playerAPI.CardPiles import java.util.EnumMap import java.util.Date public class Main <Main()
> <game-play strategies> <biased-play methods> <strong-biased-play methods> private static int doArgs(String args[]) // Handle the given command-line arguments. if args.length ≠ 1 System.err.println("One game-count command-line argument expected.") System.exit(1) int gameCount = 0 try { gameCount = new Integer(args[0]); } catch (Exception e) System.err.println( "The game-count argument should be a non-negative integer.") System.exit(1) if gameCount < 0 System.err.println( "The game-count argument should be a non-negative integer.") System.exit(1) return gameCount private static boolean makeMove(EaglesWing game, CardPiles fromPile, CardPiles toPile) // Make, in the given game, a non-trivial move from the given pile to // the given pile, returning true iff the move was non-trivial and // successful. if ((pileGroup(fromPile) == CardPiles.Group.wingPile) && (pileGroup(toPile) == CardPiles.Group.wingPile) && (game.size(toPile) == 0)) return false return game.move(fromPile, toPile) == EaglesWingStatus.MOVE_SUCCESSFUL private static CardPiles.Group pileGroup(CardPiles pile) // Return the given pile's group. return CardPiles.pileGroup(pile)
This code is written to a file (or else not used).
Main()
>: D1, U2
player/Main.java
>: D1