/* * Copyright 2015 S. Webber * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.oakgp.examples.gridwar; import org.oakgp.Assignments; import org.oakgp.node.Node; import org.oakgp.rank.tournament.TwoPlayerGame; import org.oakgp.util.Random; /** Game engine for Grid War. */ class GridWar implements TwoPlayerGame { static final int GRID_WIDTH = 4; /** Number of possible directions a player can move in - up, down, left or right. */ private static final int NUMBER_OF_POSSIBLE_DIRECTIONS = 4; /** The maximum number of moves without a winner before the game is considered a draw. */ private static final int MAX_MOVES = 24; /** The reward assigned to a winning player. */ private static final int WIN = 1; /** The penalty assigned to a losing player. */ private static final int LOSE = -WIN; /** The reward assigned to both players of a drawn game. */ private static final int NO_WINNER = 0; private final Random random; GridWar(Random random) { this.random = random; } @Override public double evaluate(Node playerLogic1, Node playerLogic2) { Player[] players = createPlayers(playerLogic1, playerLogic2); int moveCtr = 0; int currentPlayerIdx = 0; while (moveCtr++ < MAX_MOVES) { Player player = players[currentPlayerIdx]; Player opponent = players[1 - currentPlayerIdx]; int moveOutcome = processNextMove(player, opponent); if (moveOutcome != NO_WINNER) { return currentPlayerIdx == 0 ? moveOutcome : -moveOutcome; } // each player takes it in turn to move currentPlayerIdx = 1 - currentPlayerIdx; } // no winner within maximum number of moves - draw return NO_WINNER; } private Player[] createPlayers(Node playerLogic1, Node playerLogic2) { // randomly position player 1 int x = random.nextInt(GRID_WIDTH); int y = random.nextInt(GRID_WIDTH); Player player1 = new Player(x, y, playerLogic1); // randomly position player 2, ensuring they do not occupy the same or an adjacent square to player 1 Player player2 = new Player((x + 2) % GRID_WIDTH, (y + 2) % GRID_WIDTH, playerLogic2); return new Player[] { player1, player2 }; } private static int processNextMove(Player player, Player opponent) { Assignments assignments = createAssignments(player, opponent); int nextMove = getNextMove(player, assignments); if (isRepeatedMove(player, nextMove)) { // duplicate move - lose return LOSE; } player.updateState(nextMove); if (isWon(player, opponent)) { // entered square already occupied by opponent - win return WIN; } return NO_WINNER; } private static int getNextMove(Player player, Assignments assignments) { int result = (int) player.getLogic().evaluate(assignments); // normalise the result to ensure it is in the valid range of possible moves return Math.abs(result % NUMBER_OF_POSSIBLE_DIRECTIONS); } private static Assignments createAssignments(Player playerToMoveNext, Player opponent) { return Assignments.createAssignments(playerToMoveNext.getX(), playerToMoveNext.getY(), playerToMoveNext.getPreviousMove(), opponent.getX(), opponent.getY(), opponent.getPreviousMove()); } private static boolean isRepeatedMove(Player currentPlayer, int nextMove) { return currentPlayer.getPreviousMove() == nextMove; } private static boolean isWon(Player player, Player opponent) { return player.getX() == opponent.getX() && player.getY() == opponent.getY(); } }