You are on page 1of 18

import

import
import
import
import
import
import
import

java.io.BufferedReader;
java.io.BufferedWriter;
java.io.File;
java.io.FileReader;
java.io.FileWriter;
java.io.IOException;
java.util.Arrays;
java.util.LinkedList;

/**
*
* @author Ajay
*/
public class mancala {
public static void main(String[] args) throws IOException {
File f = new File("next_state.txt");
if (!f.exists()) {
f.createNewFile();
}
try (BufferedWriter writer = new BufferedWriter(new
FileWriter(f))) {
//Clears out existing file contents
writer.write("");
if (args.length > 1) {
String inputFile = args[1] != null ? args[1] : "";
if(!inputFile.contains(".txt"))
{
inputFile = inputFile.concat(".txt");
}
parseInputAndProcess(inputFile, writer);
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
static ProblemState prbState;
static void parseInputAndProcess(String fileName, BufferedWriter
writer) throws Exception {
try {
BufferedReader reader = new BufferedReader(new
FileReader(fileName));
int task = Integer.parseInt(reader.readLine());
int player = Integer.parseInt(reader.readLine());
int cutOffDepth = Integer.parseInt(reader.readLine());
String player2StateRaw = reader.readLine().trim();
String[] temp = player2StateRaw.split(" ");
int[] player2State = new int[temp.length];
for (int i = 0; i < temp.length; i++) {
player2State[i] = Integer.parseInt(temp[i]);
}

String player1StateRaw = reader.readLine().trim();


temp = player1StateRaw.split(" ");
int[] player1State = new int[temp.length];
for (int i = 0; i < temp.length; i++) {
player1State[i] = Integer.parseInt(temp[i]);
}
int numOfStonesInPlayer2Mancala =
Integer.parseInt(reader.readLine());
int numOfStonesInPlayer1Mancala =
Integer.parseInt(reader.readLine());
prbState = new ProblemState(task, player, cutOffDepth, null);
prbState.state = new MancalaState(player1State, player2State,
numOfStonesInPlayer1Mancala, numOfStonesInPlayer2Mancala, player);
long start = System.nanoTime();
playMancala(prbState, writer);
long end = System.nanoTime();
float totalTime = (end-start)/1000000;
totalTime = totalTime / 1000;
System.out.println(totalTime);
} catch (IOException | NumberFormatException e) {
throw e;
}
}
private static void playMancala(ProblemState prb, BufferedWriter
writer) throws Exception {
try {
MancalaState mancalaState = null;
switch (prb.taskType) {
case 1:
mancalaState = Greedy.processGreedy(prbState.state);
break;
case 2:
mancalaState =
MiniMax.processMinimax(prbState.state);
break;
case 3:
default:
mancalaState =
AlphaBeta.processAlphaBeta(prbState.state);
break;
case 4:
break;
}
if (mancalaState != null) {
writer.append(mancalaState.toString());
}
} catch (Exception e) {
throw e;
}
}
}

class ProblemState {
int taskType;
int player;
int cutOffDepth;
MancalaState state;
public ProblemState(int taskType, int player, int cutOffDepth,
MancalaState state) {
this.taskType = taskType;
this.player = player;
this.cutOffDepth = cutOffDepth;
this.state = state;
}
}
class Action {
int stones;
int pit;
public Action(int stones, int pit) {
this.stones = stones;
this.pit = pit;
}
}
class MancalaState {
String nodeName;
String nodeData;
int[] player1State;
int[] player2State;
int numOfStonesInPlayer1Mancala;
int numOfStonesInPlayer2Mancala;
int player;
int rootPlayer;
int numOfPits;
boolean hasToPlayAgain = false;
int depth;
boolean playerSwitched = false;
// Used to find next state in Minimax and Alpha Beta
MancalaState child = null;
int eval = Integer.MAX_VALUE;
boolean isGameOver = false;
boolean isLeafNode = false;
// Alpha Beta related properties
int alpha = Integer.MIN_VALUE;
int beta = Integer.MAX_VALUE;
public MancalaState(MancalaState state) {

this.player1State = state.player1State.clone();
this.player2State = state.player2State.clone();
this.numOfStonesInPlayer1Mancala =
state.numOfStonesInPlayer1Mancala;
this.numOfStonesInPlayer2Mancala =
state.numOfStonesInPlayer2Mancala;
this.player = state.player;
this.numOfPits = state.player1State.length;
this.nodeName = state.nodeName;
this.rootPlayer = state.rootPlayer;
this.eval = state.eval;
this.alpha = state.alpha;
this.beta = state.beta;
}
public MancalaState(MancalaState state, int alpha, int beta) {
this(state);
this.alpha = alpha;
this.beta = beta;
}
public MancalaState(int[] player1State, int[] player2State, int
numOfStonesInPlayer1Mancala, int numOfStonesInPlayer2Mancala, int player)
{
this.player1State = player1State.clone();
this.player2State = player2State.clone();
this.numOfStonesInPlayer1Mancala = numOfStonesInPlayer1Mancala;
this.numOfStonesInPlayer2Mancala = numOfStonesInPlayer2Mancala;
this.player = player;
this.rootPlayer = player;
this.numOfPits = player1State.length;
this.hasToPlayAgain = false;
firstInit();
}
public int evaluation() {
return this.rootPlayer == 1 ? this.numOfStonesInPlayer1Mancala this.numOfStonesInPlayer2Mancala
: this.numOfStonesInPlayer2Mancala this.numOfStonesInPlayer1Mancala;
}
public void calculateEval() {
this.eval = this.evaluation();
}
private void firstInit(){
this.depth = 0;
this.hasToPlayAgain = true;
this.nodeName = "root";
this.eval = Integer.MIN_VALUE;
}
private int numOfStonesInPlayer1Pit() {

int retVal = 0;
for (int i : this.player1State) {
retVal += i;
}
return retVal;
}
private int numOfStonesInPlayer2Pit() {
int retVal = 0;
for (int i : this.player2State) {
retVal += i;
}
return retVal;
}
public LinkedList<Action> GetActions() {
LinkedList<Action> actions = new LinkedList<>();
if (this.player == 1) {
for (int i = 0; i < player1State.length; i++) {
if (player1State[i] != 0) {
actions.add(new Action(player1State[i], i));
}
}
} else {
for (int i = 0; i < player2State.length; i++) {
if (player2State[i] != 0) {
actions.add(new Action(player2State[i], i));
}
}
}
return actions;
}
public MancalaState ExcuteAction(Action action, int depth) {
MancalaState state = new MancalaState(this);
state.depth = depth;
try {
int last = Integer.MAX_VALUE;
state.eval = state.depth % 2 == 0 ? Integer.MIN_VALUE :
Integer.MAX_VALUE;
if (state.player == 1) {
state.nodeName = "B" + (action.pit + 2);
// Updating all the pits and mancalas if stones complete
rotations
state.player1State[action.pit] = 0;
int numOfRevolutionRequired = action.stones /
((state.numOfPits * 2) + 1);
state.updateStonesInMancala(numOfRevolutionRequired);
action.stones -= numOfRevolutionRequired *
((state.numOfPits * 2) + 1);

// After revolution if no stones are left then last stone


was put in empt pit. Then empty that one and opposite pit
if(numOfRevolutionRequired == 1 && action.stones == 0){
int temp = state.player2State[action.pit] + 1;
state.numOfStonesInPlayer1Mancala += temp;
state.player1State[action.pit] = 0;
state.player2State[action.pit] = 0;
}
// Fill pits to the right
if (action.stones != 0) {
for (int i = action.pit + 1; i < state.numOfPits &&
action.stones != 0; i++) {
state.player1State[i] += 1;
--action.stones;
if (action.stones == 0) {
last = i;
}
}
}
// Fill Player's mancala
if (action.stones != 0) {
state.numOfStonesInPlayer1Mancala += 1;
--action.stones;
if (action.stones == 0) {
state.hasToPlayAgain = true;
}
}
// Fill Opposition's pits
if (action.stones != 0) {
for (int i = state.numOfPits - 1; i >= 0 &&
action.stones != 0; i--) {
state.player2State[i] += 1;
--action.stones;
}
}
// Fill pits to the left
if (action.stones != 0) {
for (int i = 0; i < action.pit && action.stones != 0;
i++) {
state.player1State[i] += 1;
--action.stones;
if (action.stones == 0) {
last = i;
}
}
}
// Check where the last stone was put
if (last <= state.numOfPits - 1 && last >= 0) {

if (state.player1State[last] == 1) {
int temp = state.player2State[last] + 1;
state.numOfStonesInPlayer1Mancala += temp;
state.player2State[last] = 0;
state.player1State[last] = 0;
}
}
} else {
state.nodeName = "A" + (action.pit + 2);
// Updating all the pits and mancalas if stones complete
rotations
state.player2State[action.pit] = 0;
int numOfRevolutionRequired = action.stones /
((state.numOfPits * 2) + 1);
state.updateStonesInMancala(numOfRevolutionRequired);
action.stones -= numOfRevolutionRequired *
((state.numOfPits * 2) + 1);
// After revolution if no stones are left then last stone
was put in empt pit. Then empty that one and opposite pit
if(numOfRevolutionRequired == 1 && action.stones == 0){
int temp = state.player1State[action.pit] + 1;
state.numOfStonesInPlayer2Mancala += temp;
state.player1State[action.pit] = 0;
state.player2State[action.pit] = 0;
}
// Fill pits to the left
if (action.stones != 0) {
for (int i = action.pit - 1; i >= 0 && action.stones
!= 0; i--) {
state.player2State[i] += 1;
--action.stones;
if (action.stones == 0) {
last = i;
}
}
}
// Fill Player's mancala
if (action.stones != 0) {
state.numOfStonesInPlayer2Mancala += 1;
--action.stones;
if (action.stones == 0) {
state.hasToPlayAgain = true;
}
}
// Fill Opposition's pits
if (action.stones != 0) {

for (int i = 0; i < state.numOfPits && action.stones


!= 0; i++) {
state.player1State[i] += 1;
--action.stones;
}
}
// Fill pits to the right
if (action.stones != 0) {
for (int i = state.numOfPits - 1; i >= 0 &&
action.stones != 0; i--) {
state.player2State[i] += 1;
--action.stones;
if (action.stones == 0) {
last = i;
}
}
}
// Check where the last stone was put
if (last <= state.numOfPits - 1 && last >= 0) {
if (state.player2State[last] == 1) {
int temp = state.player1State[last] + 1;
state.numOfStonesInPlayer2Mancala += temp;
state.player1State[last] = 0;
state.player2State[last] = 0;
}
}
}
// Special condition, where if my move makes all my pits zero
then all the stones in opponents pits will
// go to his mancala, thereby reducing the evaluation.
if (state.numOfStonesInPlayer1Pit() == 0) {
state.numOfStonesInPlayer2Mancala +=
state.numOfStonesInPlayer2Pit();
for (int i = 0; i < numOfPits; i++) {
state.player2State[i] = 0;
}
state.isGameOver = true;
}
else if (state.numOfStonesInPlayer2Pit() == 0) {
state.numOfStonesInPlayer1Mancala +=
state.numOfStonesInPlayer1Pit();
for (int i = 0; i < state.numOfPits; i++) {
state.player1State[i] = 0;
}
state.isGameOver = true;
}
if (state.depth == mancala.prbState.cutOffDepth &&
!state.hasToPlayAgain) {
state.isLeafNode = true;

if (state.eval == Integer.MAX_VALUE || state.eval ==


Integer.MIN_VALUE) {
state.eval = state.evaluation();
}
} else {
if (state.hasToPlayAgain) {
state.eval = state.eval == Integer.MAX_VALUE ?
Integer.MIN_VALUE : Integer.MAX_VALUE;
}
}
state.updateNodedata();
return state;
} catch (Exception e) {
System.out.println(e.getMessage());
return null;
}
}
public void updateNodedata(int depth) {
StringBuilder sb = new StringBuilder();
sb.append(this.nodeName);
sb.append(",").append(depth);
sb.append(",").append(this.eval == Integer.MAX_VALUE ? "Infinity"
: (this.eval == Integer.MIN_VALUE ? "-Infinity" : this.eval));
if (mancala.prbState.taskType == 3) {
sb.append(",").append(this.alpha == Integer.MIN_VALUE ? "Infinity" : this.alpha);
sb.append(",").append(this.beta == Integer.MAX_VALUE ?
"Infinity" : this.beta);
}
sb.append(System.getProperty("line.separator"));
this.nodeData = sb.toString();
}
public void updateNodedata() {
this.updateNodedata(this.depth);
}
private void updateStonesInMancala(int number) {
for (int i = 0; i < player1State.length; i++) {
player1State[i] += number;
}
for (int i = 0; i < player2State.length; i++) {
player2State[i] += number;
}
if(this.player == 1)
numOfStonesInPlayer1Mancala += number;
else numOfStonesInPlayer2Mancala += number;
}
@Override
public String toString() {

return buildStringData(player2State, player1State,


numOfStonesInPlayer2Mancala, numOfStonesInPlayer1Mancala);
}
private String buildStringData(int[] player2State, int[]
player1State, int player2Mancala, int player1Mancala) {
StringBuilder sb = new StringBuilder();
String p2 = Arrays.toString(player2State).replace(',', '
').replace("[", "").replace("]", "");
String p1 = Arrays.toString(player1State).replace(',', '
').replace("[", "").replace("]", "");
sb.append(p2).append(System.getProperty("line.separator"));
sb.append(p1).append(System.getProperty("line.separator"));
sb.append(player2Mancala).append(System.getProperty("line.separator"));
sb.append(player1Mancala);
return sb.toString();
}
}
class Greedy {
public static MancalaState processGreedy(MancalaState currentState) {
return findGreedySolution(currentState);
}
private static MancalaState findGreedySolution(MancalaState state) {
LinkedList<MancalaState> list = new LinkedList<>();
LinkedList<MancalaState> leafNodes = new LinkedList<>();
MancalaState optimalState = null;
MancalaState temp;
list.add(state);
do {
MancalaState top = list.remove();
if (top.hasToPlayAgain) {
for (Action action : top.GetActions()) {
temp = top.ExcuteAction(action, 0);
list.add(temp);
if (!temp.hasToPlayAgain || temp.isGameOver) {
leafNodes.add(temp);
}
}
}
} while (!list.isEmpty());
for (MancalaState leafNode : leafNodes) {
if(optimalState == null)
optimalState = leafNode;
if (leafNode.evaluation() > optimalState.evaluation()) {
optimalState = leafNode;
}
}
return optimalState == null ? state : optimalState;
}

}
class MiniMax {
static BufferedWriter writer;
private static void init() throws IOException {
try {
File f = new File("traverse_log.txt");
if (!f.exists()) {
f.createNewFile();
}
writer = new BufferedWriter(new FileWriter(f));
writer.write("Node,Depth,Value");
writer.append(System.getProperty("line.separator"));
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
public static MancalaState processMinimax(MancalaState state) throws
IOException {
if (writer == null) {
init();
}
state.updateNodedata();
writer.append(state.nodeData);
MancalaState temp = MIN_VALUE(state);
MancalaState optimalState = null;
boolean found = false;
while(!found){
optimalState = temp.child;
if(optimalState != null && optimalState.child != null){
temp = optimalState;
optimalState = optimalState.child;
}
else found = true;
}
writer.close();
return optimalState == null ? state : optimalState;
}
private static MancalaState MAX_VALUE(MancalaState state) throws
IOException {
if (state.hasToPlayAgain) {
for (Action a : state.GetActions()) {
MancalaState temp = state.ExcuteAction(a, state.depth);
writer.append(temp.nodeData);
MancalaState t = MAX_VALUE(temp);

printEvaluatedValForGameOver(t, temp.nodeData);
state.eval = min(state.eval, t.eval);
if (state.playerSwitched) {
state.updateNodedata(state.depth - 1);
} else {
state.updateNodedata();
}
writer.append(state.nodeData);
}
return state;
}
if (state.depth == mancala.prbState.cutOffDepth) {
return state;
}
if (!state.hasToPlayAgain) {
MancalaState t = new MancalaState(state);
t.depth = state.depth + 1;
if (state.player == 1) {
t.player = 2;
} else {
t.player = 1;
}
t.playerSwitched = true;
t.hasToPlayAgain = true;
MancalaState temp = MIN_VALUE(t);
state.eval = max(state.eval, temp.eval);
return state;
}
return state;
}
private static MancalaState MIN_VALUE(MancalaState state) throws
IOException {
if (state.hasToPlayAgain) {
for (Action a : state.GetActions()) {
MancalaState temp = state.ExcuteAction(a, state.depth ==
0 ? 1 : state.depth);
writer.append(temp.nodeData);
MancalaState t = MIN_VALUE(temp);
printEvaluatedValForGameOver(t, temp.nodeData);
max(state, t);
if (state.playerSwitched) {
state.updateNodedata(state.depth - 1);
} else {
state.updateNodedata();
}

writer.append(state.nodeData);
}
return state;
}
if (state.depth == mancala.prbState.cutOffDepth) {
return state;
}
if (!state.hasToPlayAgain) {
MancalaState t = new MancalaState(state);
t.depth = state.depth + 1;
if (state.player == 1) {
t.player = 2;
} else {
t.player = 1;
}
t.playerSwitched = true;
t.hasToPlayAgain = true;
MancalaState temp = MAX_VALUE(t);
state.eval = min(state.eval, temp.eval);
return state;
}
return state;
}
private static int min(int s1, int s2) {
return s1 < s2 ? s1 : s2;
}
private static int max(int s1, int s2) {
if (s1 == Integer.MAX_VALUE) {
return s2;
} else if (s2 == Integer.MAX_VALUE) {
return s1;
} else {
return s1 > s2 ? s1 : s2;
}
}
private static void max(MancalaState s1, MancalaState s2) {
if (s1.eval == Integer.MAX_VALUE) {
s1.eval = s2.eval;
s1.child = s2;
} else {
if(s2.eval > s1.eval)
{
s1.eval = s2.eval;
s1.child = s2;
}
}

}
private static void printEvaluatedValForGameOver(MancalaState state,
String prevData) throws IOException
{
if(state.isGameOver){
state.calculateEval();
if (state.playerSwitched) {
state.updateNodedata(state.depth - 1);
} else {
state.updateNodedata();
}
if(!prevData.endsWith(state.nodeData)){
writer.append(state.nodeData);
}
}
}
}
class AlphaBeta {
static BufferedWriter writer;
private static void init() throws IOException {
try {
File f = new File("traverse_log.txt");
if (!f.exists()) {
f.createNewFile();
}
writer = new BufferedWriter(new FileWriter(f));
writer.write("Node,Depth,Value,Alpha,Beta");
writer.append(System.getProperty("line.separator"));
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
public static MancalaState processAlphaBeta(MancalaState state)
throws IOException
{
if (writer == null) {
init();
}
state.updateNodedata();
writer.append(state.nodeData);
MancalaState temp = Min_Value(state);
MancalaState optimalState = null;
boolean found = false;
while(!found){
optimalState = temp.child;
if(optimalState != null && optimalState.child != null){
temp = optimalState;
optimalState = optimalState.child;

}
else found = true;
}
writer.close();
return optimalState == null ? state : optimalState;
}
private static MancalaState Max_Value(MancalaState state) throws
IOException
{
if (state.hasToPlayAgain) {
for (Action a : state.GetActions()) {
MancalaState temp = state.ExcuteAction(a, state.depth);
writer.append(temp.nodeData);
MancalaState t = Max_Value(temp);
printEvaluatedValForGameOver(t, temp.nodeData);
// Player at max level having another chance. [Min node]
if(!state.playerSwitched && mancala.prbState.player !=
state.player && !state.isLeafNode){
state.eval = min(state.eval, t.eval);
if(state.alpha >= min(state.beta, t.eval)){
state.updateNodedata();
writer.append(state.nodeData);
state.beta = min(state.beta, t.eval);
}
else if(state.alpha < state.beta){
state.beta = min(state.beta, t.eval);
state.updateNodedata();
writer.append(state.nodeData);
}
}
// Player at min level [Max node]
else if(state.playerSwitched && !state.isLeafNode){
state.eval = min(state.eval, temp.eval);
if(state.alpha >= min(state.eval, t.eval)){
state.updateNodedata(state.depth-1);
writer.append(state.nodeData);
state.beta = min(state.beta, temp.eval);
}
else if(state.alpha < state.beta){
state.beta = min(state.beta, temp.eval);
state.updateNodedata(state.depth-1);
writer.append(state.nodeData);
}
}
if(state.alpha >= state.beta)
return state;
}
return state;

}
if (state.depth == mancala.prbState.cutOffDepth) {
return state;
}
if (!state.hasToPlayAgain) {
MancalaState t = new MancalaState(state);
t.depth = state.depth + 1;
if (state.player == 1) {
t.player = 2;
} else {
t.player = 1;
}
t.playerSwitched = true;
t.hasToPlayAgain = true;
MancalaState temp = Min_Value(t);
state.eval = temp.eval;
state.beta = temp.beta;
state.alpha = temp.alpha;
return state;
}
return state;
}
private static MancalaState Min_Value(MancalaState state) throws
IOException
{
if (state.hasToPlayAgain) {
for (Action a : state.GetActions()) {
MancalaState temp = state.ExcuteAction(a, state.depth ==
0 ? 1 : state.depth);
writer.append(temp.nodeData);
MancalaState t = Min_Value(temp);
printEvaluatedValForGameOver(t, temp.nodeData);
// Player at min level having another chance. [Max node]
if(!state.playerSwitched && mancala.prbState.player ==
state.player && !state.isLeafNode){
if(t.eval > state.eval){
state.eval = t.eval;
state.child = t;
state.updateNodedata();
}
if(state.beta <= max(state.alpha, t.eval)){
state.updateNodedata();
writer.append(state.nodeData);
max(state, t);

}
else if(state.alpha < state.beta){
max(state, t);
state.updateNodedata();
writer.append(state.nodeData);
}
}
// Player at max level [Min node]
else if(state.playerSwitched && !state.isLeafNode){
state.eval = max(state.eval, temp.eval);
if(state.beta <= max(state.alpha, t.eval)){
state.updateNodedata(state.depth-1);
writer.append(state.nodeData);
state.alpha = max(state.alpha, temp.eval);
}
else if(state.alpha < state.beta){
state.alpha = max(state.alpha, temp.eval);
state.updateNodedata(state.depth-1);
writer.append(state.nodeData);
}
}
if(state.beta <= state.alpha)
return state;
}
return state;
}
if (state.depth == mancala.prbState.cutOffDepth) {
return state;
}
if (!state.hasToPlayAgain) {
MancalaState t = new MancalaState(state);
t.depth = state.depth + 1;
if (state.player == 1) {
t.player = 2;
} else {
t.player = 1;
}
t.playerSwitched = true;
t.hasToPlayAgain = true;
MancalaState t1 = Max_Value(t);
state.eval = t1.eval;
state.beta = t1.beta;
state.alpha = t1.alpha;
return state;
}

return state;
}
private static int min(int s1, int s2) {
return s1 < s2 ? s1 : s2;
}
private static int max(int s1, int s2) {
if (s1 == Integer.MAX_VALUE) {
return s2;
} else if (s2 == Integer.MAX_VALUE) {
return s1;
} else {
return s1 > s2 ? s1 : s2;
}
}
private static void max(MancalaState s1, MancalaState s2) {
if(s2.eval > s1.alpha){
s1.alpha = s2.eval;
s1.child = s2;
}
}
private static void printEvaluatedValForGameOver(MancalaState state,
String prevData) throws IOException
{
if(state.isGameOver){
state.calculateEval();
if (state.playerSwitched) {
state.updateNodedata(state.depth - 1);
} else {
state.updateNodedata();
}
if(!prevData.equals(state.nodeData)){
writer.append(state.nodeData);
}
}
}
}

You might also like