package com.github.donkirkby.vograbulary;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.Button;
import android.widget.TextView;
import com.github.donkirkby.vograbulary.anagrams.AnagramsGameModel;
import com.github.donkirkby.vograbulary.anagrams.AnagramsPlayer;
import com.github.donkirkby.vograbulary.anagrams.InvalidWordException;
public class AnagramsActivity extends VograbularyActivity {
private static final double TILE_IN_WORD_SCALE_FACTOR = 0.6;
// private static final float MIN_DRAG_ROTATION = -8f; // degrees
// private static final float MAX_DRAG_ROTATION = 8f;
// private static final int ANIMATION_DURATION = 400; // milliseconds
// private static final int TILE_SHADOW_RADIUS = 10;
// private static final int COLOR_INVISIBLE = 0x00000000;
// private static final int PLACEHOLDER_UNUSED = -1;
//// private final static double MIN_HEIGHT_TO_WIDTH = 1.4;
//
private AnagramsGameModel mGameModel;
//
private List<LetterDisplay> mUnclaimed = new ArrayList<>();
private List<LetterDisplay> mActiveWord = new ArrayList<>();
private List<LetterDisplay> mCapturedWord;
private HashMap<AnagramsPlayer, Rect> mPlayerBuildingAreas =
new HashMap<>();
private HashMap<AnagramsPlayer, List<List<LetterDisplay>>> mPlayerWords =
new HashMap<>();
private AnagramsPlayer mActivePlayer;
private int mLongestWordSize;
private int mMaxWordCount; // most words owned by a single player
// private LetterDisplay mPlaceHolderTile;
// private int mPlaceHolderIndex = PLACEHOLDER_UNUSED;
//
private int mTileWidthInWord;
private int mTileWidthInGrid;
//
// private int mGridTop;
// private int mWordTop;
// private int mAddToWordThreshold;
//
// private static Random mRand = new Random();
//
// private enum DragAnimation {
// NONE, EXPANDING, CONTRACTING
// };
//
// private DragAnimation mDragAnimation;
// private ExpandContractAnimation mExpandContractAnimation;
//
// private int mEvenTileColor;
// private int mOddTileColor;
// private int mPlayer1Color;
// private int mPlayer2Color;
// private int mPlayer1SurroundedColor;
// private int mPlayer2SurroundedColor;
// private int mTextColor;
// private int mNextColor;
// private int mClearColor;
// private int mDropShadowColor;
//
private Button mSubmitButton;
private Button mNextButton;
private Button mClearButton;
private Button mPlayer1Button;
private Button mPlayer2Button;
private TextView mMessage;
private TextView mPlayer1Score;
private TextView mPlayer2Score;
private AndroidLetterDisplayFactory letterDisplayFactory;
private LetterDisplay.LetterDisplayListener letterListener =
new LetterDisplay.LetterDisplayListener() {
@Override
public void onClick(LetterDisplay letter) {
onClickLetter(letter);
}
};
//
// public AnagramsBoard(Context context, AnagramsGameModel gameModel) {
// super(context);
// mGameModel = gameModel;
// init();
// }
//
// public AnagramsBoard(Context context, AttributeSet attrs) {
// super(context, attrs);
// init();
// }
//
// public AnagramsBoard(Context context, AttributeSet attrs, int defStyle) {
// super(context, attrs, defStyle);
// init();
// }
//
private ViewGroup rootLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_anagrams);
// Resources res = getResources();
// mEvenTileColor = res.getColor(R.color.tile_even);
// mOddTileColor = res.getColor(R.color.tile_odd);
// mPlayer1Color = res.getColor(R.color.player1);
// mPlayer2Color = res.getColor(R.color.player2);
// mPlayer1SurroundedColor = res.getColor(R.color.player1_surrounded);
// mPlayer2SurroundedColor = res.getColor(R.color.player2_surrounded);
// mTextColor = res.getColor(R.color.tile_text);
// mNextColor = Color.GREEN;
// mClearColor = Color.rgb(200, 0, 200);
// mDropShadowColor = res.getColor(R.color.tile_dropshadow);
rootLayout = (ViewGroup)findViewById(R.id.anagramsLayout);
mPlayer1Button = (Button)findViewById(R.id.player1);
mPlayer2Button = (Button)findViewById(R.id.player2);
mNextButton = (Button)findViewById(R.id.next);
mSubmitButton = (Button)findViewById(R.id.submit);
mClearButton = (Button)findViewById(R.id.clear);
mMessage = (TextView)findViewById(R.id.message);
mPlayer1Score = (TextView)findViewById(R.id.score1);
mPlayer2Score = (TextView)findViewById(R.id.score2);
letterDisplayFactory = new AndroidLetterDisplayFactory(rootLayout);
mGameModel = new AnagramsGameModel();
mGameModel.setWordList(loadWordList());
String letterSource =
"AAAAAAAAAAAAAAAABBBBCCCCDDDDDDDDEEEEEEEEEEEEEEEEEEEEEEFFFF" +
"GGGGGGHHHHHHIIIIIIIIIIIIIIJJKKLLLLLLLLMMMMNNNNNNNNNN" +
"OOOOOOOOOOOOOOPPPPQQRRRRRRRRRRRRSSSSSSSSTTTTTTTTTTUUUUUUUU" +
"VVWWXXYYYYZZ";
char[] letters = letterSource.toCharArray();
// shuffle
for (int i = letters.length - 1; i > 0; i--) {
// int from remainder of deck
int r = (int) (Math.random() * (i + 1));
char swap = letters[r];
letters[r] = letters[i];
letters[i] = swap;
}
mGameModel.setDeck(new String(letters));
mGameModel.addPlayer(new AnagramsPlayer());
mGameModel.addPlayer(new AnagramsPlayer());
final List<AnagramsPlayer> players = mGameModel.getPlayers();
for (AnagramsPlayer player : players) {
List<List<LetterDisplay>> playerWordList = new ArrayList<>();
mPlayerWords.put(player, playerWordList);
List<String> words = mGameModel.getWords(player);
for (String word : words) {
List<LetterDisplay> wordTiles = new ArrayList<>();
playerWordList.add(wordTiles);
for (int i = 0; i < word.length(); i++) {
LetterDisplay tile = addTile(word.substring(i, i + 1));
wordTiles.add(tile);
}
}
}
for (int i = 0; i < 4; i++) {
mGameModel.revealLetter();
}
String unclaimed = mGameModel.getUnclaimedLetters();
for (int i = 0; i < unclaimed.length(); i++) {
mUnclaimed.add(addTile(unclaimed.substring(i, i + 1)));
}
// mPlaceHolderTile = addTile("");
mPlayer1Button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mActivePlayer == null) {
setActivePlayer(players.get(0));
}
}
});
mPlayer2Button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mActivePlayer == null) {
setActivePlayer(players.get(1));
}
}
});
mSubmitButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mActivePlayer != null) {
submitWord();
}
}
});
mNextButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mActivePlayer == null) {
revealLetter();
}
}
});
mClearButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mActivePlayer != null) {
setActivePlayer(null);
}
}
});
setActivePlayer(null);
mPlayer1Score.setText(String.valueOf(players.get(0).getScore()));
mPlayer2Score.setText(String.valueOf(players.get(1).getScore()));
rootLayout.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
private int previousWidth;
private int previousHeight;
@Override
public void onGlobalLayout() {
int width = rootLayout.getWidth();
int height = rootLayout.getHeight();
if (width != previousWidth || height != previousHeight) {
previousWidth = width;
previousHeight = height;
layoutBoard();
}
}
});
layoutBoard();
}
private LetterDisplay addTile(String letter) {
LetterDisplay tile = letterDisplayFactory.create(letter);
tile.addClickListener(letterListener);
// tile.setDragListener(this);
return tile;
}
private void layoutBoard() {
mLongestWordSize = 7; // Always leave room for minimum letters.
mMaxWordCount = Math.max(5, // Always leave room for minimum words.
(mUnclaimed.size() + 2) / 3); // leave room for all unclaimed
// letters.
for (List<List<LetterDisplay>> words : mPlayerWords.values()) {
// leave room for building a new word.
mMaxWordCount = Math.max(mMaxWordCount, words.size() + 1);
for (List<LetterDisplay> word : words) {
mLongestWordSize = Math.max(mLongestWordSize, word.size());
}
}
int displayWidth = rootLayout.getWidth();
int displayHeight = rootLayout.getHeight();
int tileWidth = displayWidth
/ 2
/ (int) Math.round(mLongestWordSize + 2
/ TILE_IN_WORD_SCALE_FACTOR);
int tileHeight = displayHeight / (mMaxWordCount + 1);
if (tileHeight > (int) (tileWidth / TILE_IN_WORD_SCALE_FACTOR)) {
tileHeight = (int) (tileWidth / TILE_IN_WORD_SCALE_FACTOR);
} else {
tileWidth = (int) (tileHeight * TILE_IN_WORD_SCALE_FACTOR);
}
mTileWidthInGrid = tileHeight;
mTileWidthInWord = tileWidth;
AnagramsPlayer player1 = mGameModel.getPlayers().get(0);
AnagramsPlayer player2 = mGameModel.getPlayers().get(1);
mPlayerBuildingAreas.put(player1, new Rect(tileWidth, 0, displayWidth / 2 - 2
* tileHeight, tileHeight));
mPlayerBuildingAreas.put(player2, new Rect(displayWidth / 2 + 2
* tileHeight, 0, displayWidth, tileHeight));
for (int i = 0; i < mUnclaimed.size(); ++i) {
int row = i / 3;
int col = i % 3;
int x = (displayWidth + (2 * col - 3) * mTileWidthInGrid) / 2;
int y = tileHeight * row;
LetterDisplay letterDisplay = mUnclaimed.get(i);
letterDisplay.animateTo(x, y);
letterDisplay.setHomeLeft(x);
letterDisplay.setHomeTop(y);
}
layoutPlayerWords(mGameModel.getPlayers().get(0), tileWidth, tileHeight);
layoutPlayerWords(
mGameModel.getPlayers().get(1),
displayWidth / 2 + 2 * tileHeight,
tileHeight);
}
private void layoutPlayerWords(
AnagramsPlayer player,
int left,
int tileHeight) {
int y = 0;
for (List<LetterDisplay> word : mPlayerWords.get(player)) {
y += tileHeight;
int x = left;
for (LetterDisplay tile : word) {
tile.animateTo(x, y);
x += mTileWidthInWord;
}
}
}
public void onClickLetter(LetterDisplay t) {
Rect buildingArea = getActiveBuildingArea();
if (buildingArea == null) {
List<LetterDisplay> word = findOwningWord(t);
for (AnagramsPlayer player : mGameModel.getPlayers()) {
List<List<LetterDisplay>> words = mPlayerWords.get(player);
if (words.contains(word)) {
setActivePlayer(player);
return;
}
}
return;
}
if (buildingArea.contains(t.getCentreX(), t.getCentreY())) {
removeTileFromWord(t);
t.animateTo(t.getHomeLeft(), t.getHomeTop());
} else {
addTileToWord(t);
List<LetterDisplay> owningWord = findOwningWord(t);
if (owningWord != null) {
mCapturedWord = owningWord;
}
}
}
//
// /**
// * Pass touch event to widgets, but if that's not a hit, see if a player
// * is ringing in by touching the background.
// */
// @Override
// public boolean onTouchEvent(MotionEvent m) {
// if (super.onTouchEvent(m)) {
// return true;
// }
// else {
// if (mActivePlayer == null) {
// for (AnagramsPlayer player : mGameModel.getPlayers()) {
// Rect buildingArea = mPlayerBuildingAreas.get(player);
// if (buildingArea.contains(
// (int) m.getX(),
// buildingArea.centerY())) {
// setActivePlayer(player);
// return true;
// }
// }
// }
// return false;
// }
// }
//
private List<LetterDisplay> findOwningWord(LetterDisplay tile) {
for (AnagramsPlayer player : mGameModel.getPlayers()) {
for (List<LetterDisplay> word : mPlayerWords.get(player)) {
if (word.contains(tile)) {
return word;
}
}
}
return null;
}
// @Override
// public void onDragStart(Widget widget) {
//
// mDragAnimation = DragAnimation.NONE;
// mPlaceHolderIndex = PLACEHOLDER_UNUSED;
//
// LetterDisplay tile = (LetterDisplay) widget;
//
// removeTileFromWord(tile);
//
// tile.setShadow(TILE_SHADOW_RADIUS, mDropShadowColor);
//
// float angle = (mRand.nextFloat() * (Math.abs(MIN_DRAG_ROTATION) + Math
// .abs(MAX_DRAG_ROTATION))) + MIN_DRAG_ROTATION;
// tile.cancelAllAnimations();
// tile.addAnimation(new RotationAnimation(tile, ANIMATION_DURATION, angle));
// }
//
// @Override
// public void onDragEnd(Widget widget) {
//
// LetterDisplay tile = (LetterDisplay) widget;
//
// tile.setShadow(0, 0);
//
// tile.cancelAllAnimations();
// tile.addAnimation(new RotationAnimation(tile, ANIMATION_DURATION, 0));
//
// if (widget.getY() <= mAddToWordThreshold
// && mPlaceHolderIndex != PLACEHOLDER_UNUSED) {
// mActiveWord.add(mPlaceHolderIndex, tile);
// } else {
// animateToPosition(tile, tile.mPositionInGrid_x,
// tile.mPositionInGrid_y, Tile.widthInWord);
// }
//
// // remove the place holder tile
// mActiveWord.remove(mPlaceHolderTile);
// mPlaceHolderIndex = PLACEHOLDER_UNUSED;
// presentWord();
//
// }
//
// @Override
// public void onDrag(Widget widget, int x, int y) {
//
// LetterDisplay tile = (LetterDisplay) widget;
//
// // Reposition tile according to drag coordinates
// tile.setX(x);
// tile.setY(y);
//
// // When dragged above the grid, resize the tile to fit in the word
// if (y < mGridTop && mDragAnimation != DragAnimation.CONTRACTING) {
//
// mDragAnimation = DragAnimation.CONTRACTING;
// expandContractTile(tile, Tile.widthInWord);
//
// } else if (y >= mGridTop && mDragAnimation != DragAnimation.EXPANDING) {
//
// mDragAnimation = DragAnimation.EXPANDING;
// expandContractTile(tile, Tile.widthInGrid);
//
// }
//
// // When dragged above the grid, make space in the word for the tile
// if (y < mGridTop) {
//
// int word_begin = (int) (getWidth() / 2 - (Tile.widthInWord / 2.0)
// * mActiveWord.size());
// int word_end = word_begin + Tile.widthInWord * mActiveWord.size();
//
// int index;
// if (x < word_begin) {
// index = 0;
// } else if (x > word_end) {
// index = mActiveWord.size();
// } else {
// index = (int) (x - (word_begin - Tile.widthInWord / 2.0))
// / Tile.widthInWord;
// }
//
// if (index != mPlaceHolderIndex) {
// mPlaceHolderIndex = index;
// mActiveWord.remove(mPlaceHolderTile);
//
// mActiveWord.add(Math.min(index, mActiveWord.size()), mPlaceHolderTile);
// presentWord();
// }
// }
// }
//
// private void expandContractTile(LetterDisplay tile, int newWidth) {
// if (mExpandContractAnimation != null)
// tile.cancelAnimation(mExpandContractAnimation);
// mExpandContractAnimation = new ExpandContractAnimation(tile,
// ANIMATION_DURATION, newWidth);
// tile.addAnimation(mExpandContractAnimation);
// }
private void addTileToWord(LetterDisplay tile) {
mActiveWord.remove(tile);
mActiveWord.add(tile);
presentWord();
}
private void removeTileFromWord(LetterDisplay tile) {
mActiveWord.remove(tile);
presentWord();
}
private void returnAllTilesToGrid() {
ListIterator<LetterDisplay> it = mActiveWord.listIterator();
while (it.hasNext()) {
LetterDisplay t = it.next();
it.remove();
t.animateTo(t.getHomeLeft(), t.getHomeTop());
}
}
private void presentWord() {
Rect buildingArea = getActiveBuildingArea();
if (buildingArea == null) {
return;
}
if (mActiveWord.size() > mLongestWordSize) {
mLongestWordSize = mActiveWord.size();
layoutBoard();
}
for (int i = 0; i < mActiveWord.size(); ++i) {
LetterDisplay t = mActiveWord.get(i);
int x = buildingArea.left + mTileWidthInWord * i;
int y = buildingArea.top;
t.animateTo(x, y);
}
}
private Rect getActiveBuildingArea() {
Rect buildingArea =
mActivePlayer == null
? null
: mPlayerBuildingAreas.get(mActivePlayer);
return buildingArea;
}
private void setActivePlayer(AnagramsPlayer player) {
mActivePlayer = player;
if (player == null) {
returnAllTilesToGrid();
mCapturedWord = null;
mPlayer1Button.setVisibility(View.VISIBLE);
mPlayer2Button.setVisibility(View.VISIBLE);
mSubmitButton.setVisibility(View.INVISIBLE);
mNextButton.setVisibility(View.VISIBLE);
mClearButton.setVisibility(View.INVISIBLE);
} else {
if (player == mGameModel.getPlayers().get(0)) {
mPlayer2Button.setVisibility(View.INVISIBLE);
} else {
mPlayer1Button.setVisibility(View.INVISIBLE);
}
mSubmitButton.setVisibility(View.VISIBLE);
mNextButton.setVisibility(View.INVISIBLE);
mClearButton.setVisibility(View.VISIBLE);
}
}
private void submitWord() {
try {
if (mCapturedWord != null) {
mGameModel.changeWord(buildWord(mCapturedWord),
buildWord(mActiveWord), mActivePlayer);
for (AnagramsPlayer player : mGameModel.getPlayers()) {
mPlayerWords.get(player).remove(mCapturedWord);
}
} else {
mGameModel.makeWord(buildWord(mActiveWord), mActivePlayer);
}
mPlayerWords.get(mActivePlayer).add(mActiveWord);
for (LetterDisplay tile : mActiveWord) {
mUnclaimed.remove(tile);
}
mActiveWord = new ArrayList<LetterDisplay>();
setActivePlayer(null);
mPlayer1Score.setText(String.valueOf(
mGameModel.getPlayers().get(0).getScore()));
mPlayer2Score.setText(String.valueOf(
mGameModel.getPlayers().get(1).getScore()));
layoutBoard();
} catch (InvalidWordException ex) {
mMessage.setText(ex.getMessage());
}
}
private String buildWord(List<LetterDisplay> tiles) {
StringBuilder word = new StringBuilder();
for (LetterDisplay tile : tiles) {
word.append(tile.getLetter());
}
String wordText = word.toString();
return wordText;
}
private void revealLetter() {
if (mGameModel.isDeckEmpty()) {
return;
}
char letter = mGameModel.revealLetter();
LetterDisplay tile = addTile(String.valueOf(letter));
mUnclaimed.add(tile);
mMaxWordCount = Math.max(mMaxWordCount, mUnclaimed.size());
layoutBoard();
if (mGameModel.isDeckEmpty()) {
mNextButton.setVisibility(View.INVISIBLE);
}
}
}