Commit cc76adc8 authored by Fabian Jakob Sauer's avatar Fabian Jakob Sauer

Testing different players against eachother.

parent f4cc2df5
......@@ -38,8 +38,8 @@
<recent name="C:\Dev\java\thegame_ai\src" />
</key>
<key name="CopyClassDialog.RECENTS_KEY">
<recent name="util.Extensions" />
<recent name="players" />
<recent name="util.Extensions" />
<recent name="" />
</key>
<key name="CreateClassDialog.RecentsKey">
......@@ -108,10 +108,10 @@
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state x="587" y="0" key="#com.intellij.refactoring.rename.AutomaticRenamingDialog/0.0.1920.1040@0.0.1920.1040" timestamp="1590663254804" />
<state width="477" height="466" key="DebuggerActiveHint" timestamp="1591264300086">
<state width="477" height="466" key="DebuggerActiveHint" timestamp="1591279078408">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state width="477" height="466" key="DebuggerActiveHint/0.0.1920.1040@0.0.1920.1040" timestamp="1591264300086" />
<state width="477" height="466" key="DebuggerActiveHint/0.0.1920.1040@0.0.1920.1040" timestamp="1591279078408" />
<state x="622" y="273" key="FileChooserDialogImpl" timestamp="1589471605471">
<screen x="0" y="0" width="1920" height="1040" />
</state>
......@@ -132,22 +132,22 @@
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state width="1877" height="394" key="GridCell.Tab.-1.right/0.0.1920.1040@0.0.1920.1040" timestamp="1590745335105" />
<state width="1877" height="331" key="GridCell.Tab.0.bottom" timestamp="1591275350868">
<state width="1877" height="236" key="GridCell.Tab.0.bottom" timestamp="1591281335195">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state width="1877" height="331" key="GridCell.Tab.0.bottom/0.0.1920.1040@0.0.1920.1040" timestamp="1591275350868" />
<state width="1877" height="331" key="GridCell.Tab.0.center" timestamp="1591275350868">
<state width="1877" height="236" key="GridCell.Tab.0.bottom/0.0.1920.1040@0.0.1920.1040" timestamp="1591281335195" />
<state width="1877" height="236" key="GridCell.Tab.0.center" timestamp="1591281335194">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state width="1877" height="331" key="GridCell.Tab.0.center/0.0.1920.1040@0.0.1920.1040" timestamp="1591275350868" />
<state width="1877" height="331" key="GridCell.Tab.0.left" timestamp="1591275350868">
<state width="1877" height="236" key="GridCell.Tab.0.center/0.0.1920.1040@0.0.1920.1040" timestamp="1591281335194" />
<state width="1877" height="236" key="GridCell.Tab.0.left" timestamp="1591281335194">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state width="1877" height="331" key="GridCell.Tab.0.left/0.0.1920.1040@0.0.1920.1040" timestamp="1591275350868" />
<state width="1877" height="331" key="GridCell.Tab.0.right" timestamp="1591275350868">
<state width="1877" height="236" key="GridCell.Tab.0.left/0.0.1920.1040@0.0.1920.1040" timestamp="1591281335194" />
<state width="1877" height="236" key="GridCell.Tab.0.right" timestamp="1591281335194">
<screen x="0" y="0" width="1920" height="1040" />
</state>
<state width="1877" height="331" key="GridCell.Tab.0.right/0.0.1920.1040@0.0.1920.1040" timestamp="1591275350868" />
<state width="1877" height="236" key="GridCell.Tab.0.right/0.0.1920.1040@0.0.1920.1040" timestamp="1591281335194" />
<state width="1877" height="394" key="GridCell.Tab.1.bottom" timestamp="1590745318973">
<screen x="0" y="0" width="1920" height="1040" />
</state>
......
WinRate, Threshold, WeightOwn, WeightOpp
0.9419, 52, 1.0, 1.0
0.9463, 52, 1.0, 0.9
0.9421, 52, 1.0, 0.8
0.9396, 52, 1.0, 0.7
0.943, 52, 1.0, 0.6
0.9391, 52, 1.0, 0.5
0.942, 52, 1.0, 0.4
0.9417, 52, 1.0, 0.3
0.94, 52, 1.0, 0.2
0.9406, 52, 1.0, 0.1
0.9402, 52, 1.0, 0.0
0.4987, 42, 1.0, 0.06
......@@ -51,9 +51,9 @@ public class OptimizeTurnPlayer implements Player {
cardTracker = new CardTracker();
}
public OptimizeTurnPlayer(int badPlacementTheshold, float weightOwn, float weightOpp)
public OptimizeTurnPlayer(int badPlacementTheshold, float weightOwn, float weightOpp, boolean debug)
{
logger = new LoggingSystem(false);
logger = new LoggingSystem(debug);
gameValue = new GameValue(logger);
cardTracker = new CardTracker();
......
package players;
import de.upb.isml.thegamef2f.engine.CardPosition;
import de.upb.isml.thegamef2f.engine.GameState;
import de.upb.isml.thegamef2f.engine.Move;
import de.upb.isml.thegamef2f.engine.Placement;
import de.upb.isml.thegamef2f.engine.board.Card;
import de.upb.isml.thegamef2f.engine.player.Player;
import util.Extensions.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* Basic Player AI
* based on RandomPlayer from Alexander Tornede
* @author fjsauer
*
* Functionality:
* Special Method hierarchy:
* Generate stack value data and compute best possible move [alpha]
* Choose random placement.
* Other rules:
* None
*/
public class OptimizeTurnPlayerDefault implements Player {
private LoggingSystem logger;
private int countTurn = 0;
private Random random;
private int badPlacementTheshold = 42;
private float lastGameValue;
private GameValue gameValue;
private CardTracker cardTracker;
private GameState latestGameState;
public OptimizeTurnPlayerDefault()
{
logger = new LoggingSystem(false);
gameValue = new GameValue(logger);
cardTracker = new CardTracker();
}
public OptimizeTurnPlayerDefault(boolean debug)
{
logger = new LoggingSystem(debug);
gameValue = new GameValue(logger);
cardTracker = new CardTracker();
}
public OptimizeTurnPlayerDefault(int badPlacementTheshold, float weightOwn, float weightOpp, boolean debug)
{
logger = new LoggingSystem(debug);
gameValue = new GameValue(logger);
cardTracker = new CardTracker();
this.badPlacementTheshold = badPlacementTheshold;
this.gameValue.SetWeights(weightOwn, weightOpp);
}
@Override
public void initialize(long randomSeed) {
this.countTurn = 0;
this.gameValue = new GameValue(logger);
this.random = new Random(randomSeed);
this.cardTracker = new CardTracker();
}
private List<ExtendedPlacement> ComputePlacements(List<Card> pile, Card lastKnownCard, CardPosition pos)
{
/* Generates a list of ExtendedPlacements
(containing information about last card on given pile)
given a card pile and the last known card */
List<ExtendedPlacement> placements = new ArrayList<ExtendedPlacement>();
boolean isNewCard = false;
for (Card card : pile)
{
if(isNewCard)
{
placements.add(new ExtendedPlacement(card, pos, lastKnownCard));
lastKnownCard = card;
}
if (!isNewCard && card == lastKnownCard) // find start of new cards on given pile
{
isNewCard = true;
}
}
return placements;
}
private List<ExtendedPlacement> ReconstructPlacements(GameState newGameState)
{
/* Checks if any piles top card has changed compared to last saved gamestate.
If yes new moves are generated and added to list.
This list is returned.
*/
List<ExtendedPlacement> reconstructedPlacements = new ArrayList<ExtendedPlacement>();
if (latestGameState == null)
{
if (newGameState.getTopCardOnOwnDescendingDiscardPile().getNumber() != 60)
{
List<Card> pile = newGameState.getCardsOnOwnDescendingDiscardPile();
Card lastKnownCard = newGameState.getCardsOnOwnDescendingDiscardPile().get(0);
reconstructedPlacements.addAll(ComputePlacements(pile, lastKnownCard, CardPosition.OWN_DESCENDING_DISCARD_PILE));
}
if (newGameState.getTopCardOnOwnAscendingDiscardPile().getNumber() != 1)
{
List<Card> pile = newGameState.getCardsOnOwnAscendingDiscardPile();
Card lastKnownCard = newGameState.getCardsOnOwnAscendingDiscardPile().get(0);
reconstructedPlacements.addAll(ComputePlacements(pile, lastKnownCard, CardPosition.OWN_ASCENDING_DISCARD_PILE));
}
if (newGameState.getTopCardOnOpponentsDescendingDiscardPile().getNumber() != 60)
{
List<Card> pile = newGameState.getCardsOnOpponentsDescendingDiscardPile();
Card lastKnownCard = newGameState.getCardsOnOpponentsDescendingDiscardPile().get(0);
reconstructedPlacements.addAll(ComputePlacements(pile, lastKnownCard, CardPosition.OPPONENTS_DESCENDING_DISCARD_PILE));
}
if (newGameState.getTopCardOnOpponentsAscendingDiscardPile().getNumber() != 1)
{
List<Card> pile = newGameState.getCardsOnOpponentsAscendingDiscardPile();
Card lastKnownCard = newGameState.getCardsOnOpponentsAscendingDiscardPile().get(0);
reconstructedPlacements.addAll(ComputePlacements(pile, lastKnownCard, CardPosition.OPPONENTS_ASCENDING_DISCARD_PILE));
}
}
else
{
if (newGameState.getTopCardOnOwnDescendingDiscardPile() != latestGameState.getTopCardOnOwnDescendingDiscardPile())
{
List<Card> pile = newGameState.getCardsOnOwnDescendingDiscardPile();
Card lastKnownCard = latestGameState.getTopCardOnOwnDescendingDiscardPile();
reconstructedPlacements.addAll(ComputePlacements(pile, lastKnownCard, CardPosition.OWN_DESCENDING_DISCARD_PILE));
}
if (newGameState.getTopCardOnOwnAscendingDiscardPile() != latestGameState.getTopCardOnOwnAscendingDiscardPile())
{
List<Card> pile = newGameState.getCardsOnOwnAscendingDiscardPile();
Card lastKnownCard = latestGameState.getTopCardOnOwnAscendingDiscardPile();
reconstructedPlacements.addAll(ComputePlacements(pile, lastKnownCard, CardPosition.OWN_ASCENDING_DISCARD_PILE));
}
if (newGameState.getTopCardOnOpponentsDescendingDiscardPile() != latestGameState.getTopCardOnOpponentsDescendingDiscardPile())
{
List<Card> pile = newGameState.getCardsOnOpponentsDescendingDiscardPile();
Card lastKnownCard = latestGameState.getTopCardOnOpponentsDescendingDiscardPile();
reconstructedPlacements.addAll(ComputePlacements(pile, lastKnownCard, CardPosition.OPPONENTS_DESCENDING_DISCARD_PILE));
}
if (newGameState.getTopCardOnOpponentsAscendingDiscardPile() != latestGameState.getTopCardOnOpponentsAscendingDiscardPile())
{
List<Card> pile = newGameState.getCardsOnOpponentsAscendingDiscardPile();
Card lastKnownCard = latestGameState.getTopCardOnOpponentsAscendingDiscardPile();
reconstructedPlacements.addAll(ComputePlacements(pile, lastKnownCard, CardPosition.OPPONENTS_ASCENDING_DISCARD_PILE));
}
}
return reconstructedPlacements;
}
@Override
public Move computeMove(GameState newGameState) {
countTurn++;
// Reconstruct enemies last move
List<ExtendedPlacement> reconstructedPlacements = ReconstructPlacements(newGameState);
cardTracker.TrackPlacedCardsByOp(reconstructedPlacements);
latestGameState = newGameState;
boolean placedOnOpponentsPiles = false;
List<Placement> placementsOfMove = new ArrayList<>();
// as long as we still have hand cards
while (!latestGameState.getHandCards().isEmpty()) {
List<Placement> validPlacements = new ArrayList<>();
// compute all valid placements
for (Card card : latestGameState.getHandCards()) {
for (CardPosition position : CardPosition.values()) {
Placement placement = new Placement(card, position);
if (isPlacementValid(placement, latestGameState, !placedOnOpponentsPiles)) {
validPlacements.add(placement);
}
}
}
// if we cannot find a valid placement anymore, we can stop here and return the
// ones we have so far
if (validPlacements.isEmpty()) {
cardTracker.TrackPlacedCardsByMe(placementsOfMove);
return new Move(placementsOfMove);
}
//Pick next placement
// calculate game value before placing a card
lastGameValue = gameValue.calcGameValue(latestGameState, cardTracker);
// rate all possible placements using game value
List<RatedPlacement> ratedPlacements = new ArrayList<RatedPlacement>();
for (Placement potentialPlacement : validPlacements)
{
CardTracker tmpCardTracker = new CardTracker(cardTracker);
List<Placement> tmpPlacementsOfMove = new ArrayList<Placement>(placementsOfMove);
tmpPlacementsOfMove.add(potentialPlacement);
tmpCardTracker.TrackPlacedCardsByMe(tmpPlacementsOfMove);
GameState potentialGameState = computeNewGameStateAfterPlacement(latestGameState, potentialPlacement);
ratedPlacements.add(new RatedPlacement(potentialPlacement, gameValue.calcGameValue(potentialGameState, tmpCardTracker)));
}
// find best rated placement
RatedPlacement bestRatedPlacement = ratedPlacements.get(0);
for (RatedPlacement ratedPlacement : ratedPlacements)
{
if (ratedPlacement.resultingGameValue < bestRatedPlacement.resultingGameValue)
{
bestRatedPlacement = ratedPlacement;
}
}
Placement nextPlacement = bestRatedPlacement.placement;
logger.Log("_______________________End of turn No. " + countTurn + "_________________________");
// return if
//two or more placements are selected
if (placementsOfMove.size() >= 2)
{
// no placement was on opponents pile OR the next best rated placement is too bad)
if (!placedOnOpponentsPiles || bestRatedPlacement.resultingGameValue - lastGameValue < badPlacementTheshold)
{
cardTracker.TrackPlacedCardsByMe(placementsOfMove);
return new Move(placementsOfMove);
}
}
if (nextPlacement.getPosition() == CardPosition.OPPONENTS_ASCENDING_DISCARD_PILE
|| nextPlacement.getPosition() == CardPosition.OPPONENTS_DESCENDING_DISCARD_PILE) {
placedOnOpponentsPiles = true;
}
// add this random placement to the placements for our move
placementsOfMove.add(nextPlacement);
// update the view we have on the game to make sure that the next set of valid
// placements is indeed valid
latestGameState = computeNewGameStateAfterPlacement(latestGameState, nextPlacement);
}
cardTracker.TrackPlacedCardsByMe(placementsOfMove);
return new Move(placementsOfMove);
}
private GameState computeNewGameStateAfterPlacement(GameState gameStatePriorToPlacement, Placement placement) {
List<Card> handCards = new ArrayList<>(gameStatePriorToPlacement.getHandCards());
handCards.remove(placement.getCard());
List<Card> cardsOnOwnAscendingDiscardPile = new ArrayList<>(
gameStatePriorToPlacement.getCardsOnOwnAscendingDiscardPile());
if (placement.getPosition() == CardPosition.OWN_ASCENDING_DISCARD_PILE) {
cardsOnOwnAscendingDiscardPile.add(placement.getCard());
}
List<Card> cardsOnOwnDescendingDiscardPile = new ArrayList<>(
gameStatePriorToPlacement.getCardsOnOwnDescendingDiscardPile());
if (placement.getPosition() == CardPosition.OWN_DESCENDING_DISCARD_PILE) {
cardsOnOwnDescendingDiscardPile.add(placement.getCard());
}
List<Card> cardsOnOpponentsAscendingDiscardPile = new ArrayList<>(
gameStatePriorToPlacement.getCardsOnOpponentsAscendingDiscardPile());
if (placement.getPosition() == CardPosition.OPPONENTS_ASCENDING_DISCARD_PILE) {
cardsOnOpponentsAscendingDiscardPile.add(placement.getCard());
}
List<Card> cardsOnOpponentsDescendingDiscardPile = new ArrayList<>(
gameStatePriorToPlacement.getCardsOnOpponentsDescendingDiscardPile());
if (placement.getPosition() == CardPosition.OPPONENTS_DESCENDING_DISCARD_PILE) {
cardsOnOpponentsDescendingDiscardPile.add(placement.getCard());
}
return new GameState(handCards, cardsOnOwnAscendingDiscardPile, cardsOnOwnDescendingDiscardPile,
cardsOnOpponentsAscendingDiscardPile, cardsOnOpponentsDescendingDiscardPile);
}
private boolean isPlacementValid(Placement placement, GameState gameState, boolean placingOnOpponentPilesAllowed) {
switch (placement.getPosition()) {
case OPPONENTS_ASCENDING_DISCARD_PILE:
return placingOnOpponentPilesAllowed
? canPlaceCardOnOpponentsAscendingDiscardPile(placement.getCard(), gameState)
: false;
case OPPONENTS_DESCENDING_DISCARD_PILE:
return placingOnOpponentPilesAllowed
? canPlaceCardOnOpponentsDescendingDiscardPile(placement.getCard(), gameState)
: false;
case OWN_ASCENDING_DISCARD_PILE:
return canPlaceCardOnOwnAscendingDiscardPile(placement.getCard(), gameState);
case OWN_DESCENDING_DISCARD_PILE:
return canPlaceCardOnOwnDescendingDiscardPile(placement.getCard(), gameState);
}
return false;
}
private boolean canPlaceCardOnOwnAscendingDiscardPile(Card card, GameState gameState) {
return gameState.getTopCardOnOwnAscendingDiscardPile().isSmallerThan(card)
|| gameState.getTopCardOnOwnAscendingDiscardPile().is10LargerThan(card);
}
private boolean canPlaceCardOnOwnDescendingDiscardPile(Card card, GameState gameState) {
return card.isSmallerThan(gameState.getTopCardOnOwnDescendingDiscardPile())
|| card.is10LargerThan(gameState.getTopCardOnOwnDescendingDiscardPile());
}
private boolean canPlaceCardOnOpponentsAscendingDiscardPile(Card card, GameState gameState) {
return card.isSmallerThan(gameState.getTopCardOnOpponentsAscendingDiscardPile());
}
private boolean canPlaceCardOnOpponentsDescendingDiscardPile(Card card, GameState gameState) {
return gameState.getTopCardOnOpponentsDescendingDiscardPile().isSmallerThan(card);
}
@Override
public String toString() {
return getName();
}
public void SetWeights(int badPlacementTheshold, float weightOwn, float weightOpp)
{
gameValue.SetWeights(weightOwn, weightOpp);
this.badPlacementTheshold = badPlacementTheshold;
}
}
\ No newline at end of file
......@@ -4,6 +4,7 @@ import de.upb.isml.thegamef2f.engine.board.Game;
import de.upb.isml.thegamef2f.engine.player.Player;
import players.BasicPlayer;
import players.OptimizeTurnPlayer;
import players.OptimizeTurnPlayerDefault;
import java.io.FileWriter;
import java.io.IOException;
......@@ -13,14 +14,42 @@ import java.util.List;
import java.util.Random;
public class OptimizeWeights {
private int badPlacementThreshold = 52;
private float weightOwn = 1.0f;
private float aryWeightsOpp[] = {1.0f, 0.9f, 0.8f, 0.7f, 0.6f, 0.5f, 0.4f, 0.3f, 0.2f, 0.1f, 0.0f};
private int sizeThreshold = 1;
private int startThreshold = 42;
private int stepThreshold = 1;
private int sizeWeightOwn = 1;
private float startWeightOwn = 1.0f;
private float stepWeightOwn = 1.0f;
private int sizeWeightOpp = 1;
private float startWeightOpp = 0.06f;
private float stepWeightOpp = 0.02f;
private List<Integer> listThreshold = new ArrayList<Integer>();
private List<Float> listWeightOwn = new ArrayList<Float>();
private List<Float> listWeightOpp = new ArrayList<Float>();
private List<Result> results = new ArrayList<Result>();
public OptimizeWeights()
{
for (int i = 0; i < sizeThreshold; i++)
{
listThreshold.add(startThreshold + stepThreshold * i);
}
for (int i = 0; i < sizeWeightOwn; i++)
{
listWeightOwn.add(startWeightOwn + stepWeightOwn * i);
}
for (int i = 0; i < sizeWeightOpp; i++)
{
listWeightOpp.add(startWeightOpp + stepWeightOpp * i);
}
}
public void Compute() throws IOException
......@@ -29,23 +58,28 @@ public class OptimizeWeights {
pw.write("WinRate,\tThreshold,\tWeightOwn,\tWeightOpp\n");
System.out.println("WinRate,\tThreshold,\tWeightOwn,\tWeightOpp");
for(float weightOpp : aryWeightsOpp)
for (int badPlacementThreshold : listThreshold)
{
Result result = Simulate(badPlacementThreshold, weightOwn, weightOpp);
result.Print(pw);
results.add(result);
for (float weightOwn : listWeightOwn)
{
for (float weightOpp : listWeightOpp)
{
Result result = Simulate(badPlacementThreshold, weightOwn, weightOpp);
result.Print(pw);
results.add(result);
}
}
}
pw.close();
}
private Result Simulate(int badPlacementThreshold, float weightOwn, float weightOpp)
{
// USER INPUT
int numGames = 10000;
int numGames = 50000;
Player p1 = new BasicPlayer();
Player p2 = new OptimizeTurnPlayer(badPlacementThreshold, weightOwn, weightOpp);
Player p1 = new OptimizeTurnPlayerDefault( false);
Player p2 = new OptimizeTurnPlayer(badPlacementThreshold, weightOwn, weightOpp, false);
Statistics stats = new Statistics(p1, p2);
Random rand = new Random();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment