/*******************************************************************************
* Solitaire
*
* Copyright (C) 2016 by Martin P. Robillard
*
* See: https://github.com/prmr/Solitaire
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*******************************************************************************/
package ca.mcgill.cs.stg.solitaire.ai;
import java.util.ArrayList;
import java.util.List;
import ca.mcgill.cs.stg.solitaire.cards.Card;
import ca.mcgill.cs.stg.solitaire.model.GameModel.StackIndex;
import ca.mcgill.cs.stg.solitaire.model.GameModel.SuitStackIndex;
import ca.mcgill.cs.stg.solitaire.model.GameModelView;
import ca.mcgill.cs.stg.solitaire.model.Move;
/**
* Makes the first possible move in this order:
* 0. Discarding if the discard pile is empty
* 1. Moving a card from the discard pile to a suit stack
* 2. Moving a card from the discard pile to a working stack
* 3. Moving a card from a working stack to a suit stack, in order
* of working stacks.
* 4. Moving from a working stack to another, if this either reveals
* a fresh card or frees up a spot for a kind.
* 5. If no moves are possible, discards.
*/
public class GreedyPlayingStrategy implements PlayingStrategy
{
// CSOFF:
@Override
public Move computeNextMove(GameModelView pModel)
{
if( pModel.isEmptyDiscardPile() && !pModel.isEmptyDeck() )
{
return pModel.getDiscardMove();
}
else
{
ArrayList<Move> moves = new ArrayList<>();
moves.addAll(movesFromWorkingStacksRevealsCard(pModel));
if( moves.size() > 0 )
{
return moves.get(0);
}
moves.addAll(movesFromDiscardPileToSuitStack(pModel));
if( moves.size() > 0 )
{
return moves.get(0);
}
moves.addAll(movesFromDiscardPileToWorkingStacks(pModel));
if( moves.size() > 0 )
{
return moves.get(0);
}
moves.addAll(movesFromWorkingStacksToSuitStacks(pModel));
if( moves.size() > 0 )
{
return moves.get(0);
}
if( !pModel.isEmptyDeck() )
{
return pModel.getDiscardMove();
}
else
{
return pModel.getNullMove();
}
}
} // CSON:
private List<Move> movesFromDiscardPileToSuitStack(GameModelView pModel)
{
ArrayList<Move> moves = new ArrayList<>();
if( !pModel.isEmptyDiscardPile())
{
for(SuitStackIndex index : SuitStackIndex.values())
{
if( pModel.isLegalMove(pModel.peekDiscardPile(), index))
{
moves.add(pModel.getCardMove(pModel.peekDiscardPile(), index));
if( pModel.isEmptySuitStack(index))
{
break; // we take the first possible blank space
}
}
}}
return moves;
}
private List<Move> movesFromDiscardPileToWorkingStacks(GameModelView pModel)
{
ArrayList<Move> moves = new ArrayList<>();
if( !pModel.isEmptyDiscardPile() )
{
for(StackIndex index : StackIndex.values())
{
if( pModel.isLegalMove(pModel.peekDiscardPile(), index))
{
moves.add(pModel.getCardMove(pModel.peekDiscardPile(), index));
}
}
}
return moves;
}
private List<Move> movesFromWorkingStacksToSuitStacks(GameModelView pModel)
{
ArrayList<Move> moves = new ArrayList<>();
for(StackIndex index : StackIndex.values())
{
Card[] stack = pModel.getStack(index);
if( stack.length > 0 )
{
Card card = stack[stack.length-1];
for(SuitStackIndex index2 : SuitStackIndex.values())
{
if( pModel.isLegalMove(card, index2))
{
moves.add(pModel.getCardMove(card, index2));
if( pModel.isEmptySuitStack(index2))
{
break; // we take the first possible blank space
}
}
}
}
}
return moves;
}
private List<Move> movesFromWorkingStacksRevealsCard(GameModelView pModel)
{
ArrayList<Move> moves = new ArrayList<>();
for(StackIndex index : StackIndex.values())
{
Card[] stack = pModel.getStack(index);
for(int i = 0; i < stack.length; i++ )
{
if( pModel.isVisibleInWorkingStack(stack[i]) && i > 0 && !pModel.isVisibleInWorkingStack(stack[i-1]) )
{
for( StackIndex index2 : StackIndex.values() )
{
if( pModel.isLegalMove(stack[i], index2))
{
moves.add(pModel.getCardMove(stack[i], index2));
}
}
}
else if( pModel.isVisibleInWorkingStack(stack[i]) && i == 0 )
{
for( StackIndex index2 : StackIndex.values() )
{
// we don't want to just move a card around
if( pModel.isLegalMove(stack[i], index2) && pModel.getStack(index2).length > 0)
{
moves.add(pModel.getCardMove(stack[i], index2));
}
}
}
}
}
return moves;
}
}