package com.xtremelabs.devicewall.programs.memory; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.xtremelabs.devicewall.programs.amqp.AmqpConnectionManager; import com.xtremelabs.devicewall.programs.amqp.AmqpListener; import com.xtremelabs.devicewall.protocol.AmqpConstants; import com.xtremelabs.devicewall.protocol.CardFace; import com.xtremelabs.devicewall.protocol.Data; import com.xtremelabs.devicewall.protocol.Protocol; import com.xtremelabs.devicewall.protocol.gamecontrol.GameControlMessageType; import com.xtremelabs.devicewall.protocol.gamecontrol.request.ClientStartRequest; import com.xtremelabs.devicewall.protocol.gamecontrol.response.ServerStartResponse; import com.xtremelabs.devicewall.protocol.identifier.IdentifierMessageType; import com.xtremelabs.devicewall.protocol.identifier.data.MobileServerIdentifierData; import com.xtremelabs.devicewall.protocol.identifier.response.MapIdentifierResponse; import com.xtremelabs.devicewall.protocol.memory.Card; import com.xtremelabs.devicewall.protocol.memory.Card.CardState; import com.xtremelabs.devicewall.protocol.memory.DeviceData; import com.xtremelabs.devicewall.protocol.memory.FaceUpCard; import com.xtremelabs.devicewall.protocol.memory.MemoryAssign; import com.xtremelabs.devicewall.protocol.memory.MemoryClick; import com.xtremelabs.devicewall.protocol.memory.MemoryConfirm; import com.xtremelabs.devicewall.protocol.memory.MemoryDeserializer; import com.xtremelabs.devicewall.protocol.memory.MemoryFlip; import com.xtremelabs.devicewall.protocol.memory.MemoryMessageType; public class MemoryProgram { private AmqpConnectionManager amqpConnectionManager; private Gson sGson; private ConcurrentHashMap<Long, DeviceData> mDeviceData = new ConcurrentHashMap<Long, DeviceData>(); private volatile ArrayList<Long> mConfirmedDevices = new ArrayList<Long>(); private FaceUpCard mFaceUpCard1; private FaceUpCard mFaceUpCard2; private AmqpListener amqpListener = new AmqpListener() { @Override public void handleDelivery(String body) throws IOException { System.out.println("Memory received a message: " + body); final Protocol protocol = sGson.fromJson(body, Protocol.class); if (protocol == null) return; final Data data = protocol.getData(); final String messageType = protocol.getType(); if (IdentifierMessageType.getModelType(messageType) != IdentifierMessageType.EMPTY) { IdentifierMessageType message = IdentifierMessageType.getModelType(messageType); switch (message) { case MAP_SERVER_RESPONSE: handleMapResponse((MapIdentifierResponse) data); break; default: break; } } else if (GameControlMessageType.getModelType(messageType) != GameControlMessageType.EMPTY) { GameControlMessageType message = GameControlMessageType.getModelType(messageType); switch (message) { case CLIENT_START: final ClientStartRequest clientStartRequest = (ClientStartRequest) protocol.getData(); if (AmqpConstants.MEMORY_SERVER_APP_NAME.equals(clientStartRequest.getApp())) handleStart(); break; default: break; } } else { MemoryMessageType message = MemoryMessageType.getModelType(messageType); switch (message) { case CLICK: handleClick(protocol.getId(), (MemoryClick) data); break; case CONFIRM: handleConfirm(protocol.getId(), (MemoryConfirm) data); default: break; } } } @Override public void onConnected() { } @Override public void onDisconnected() { } }; /** * @param args */ public static void main(final String[] args) { new MemoryProgram(); } public MemoryProgram() { try { final GsonBuilder builder = new GsonBuilder(); builder.registerTypeAdapter(Protocol.class, new MemoryDeserializer()); sGson = builder.create(); amqpConnectionManager = new AmqpConnectionManager(amqpListener); } catch (IOException e) { e.printStackTrace(); } } protected void handleConfirm(final Long id, MemoryConfirm data) { mConfirmedDevices.add(id); } protected void handleStart() { amqpConnectionManager.publishToServer(IdentifierMessageType.MAP_SERVER_REQUEST.toString(), ""); } protected void handleMapResponse(MapIdentifierResponse response) { final Collection<MobileServerIdentifierData> mobileServerIdentifierData = response.getMap(); mDeviceData = new ConcurrentHashMap<Long, DeviceData>(); int numberOfCards = 0; for (MobileServerIdentifierData mobileData : mobileServerIdentifierData) { if (mobileData.isTablet()) numberOfCards += 2; else numberOfCards++; } final boolean oddNumberOfCards = numberOfCards % 2 == 1; final int numberOfPairs = numberOfCards / 2; final List<Card> cards = new ArrayList<Card>(); final CardFace[] values = CardFace.values(); for (int index = 0; index < numberOfPairs; index++) { CardFace cardFace = values[index % values.length]; cards.add(new Card(CardState.DOWN, cardFace)); cards.add(new Card(CardState.DOWN, cardFace)); } Collections.shuffle(cards); for (MobileServerIdentifierData mobileData : mobileServerIdentifierData) { if (!cards.isEmpty()) { final ArrayList<Card> deviceCards = new ArrayList<Card>(); Card card = cards.remove(0); deviceCards.add(card); if (mobileData.isTablet() && !cards.isEmpty()) { card = cards.remove(0); deviceCards.add(card); } DeviceData deviceData = new DeviceData(mobileData, deviceCards); mDeviceData.put(deviceData.getId(), deviceData); } } mConfirmedDevices = new ArrayList<Long>(); amqpConnectionManager.publishToAll(GameControlMessageType.SERVER_START.toString(), new ServerStartResponse(AmqpConstants.MEMORY_SERVER_APP_NAME).toJson().toString()); new Thread(new Runnable() { public void run() { // time to wait for clients to respond int delay = 60; while (!isSubset(mobileServerIdentifierData, mConfirmedDevices) && delay-- > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("Done waiting for confirmations: delay = " + delay + ", confirmed devices length: " + mConfirmedDevices.size() + ", full list size: " + mobileServerIdentifierData.size()); assignCards(); } }).start(); } /** * Returns true if every element id of mobileServerIdentifierData list is in * confirmed devices. * * @param mobileServerIdentifierData * List of mobile server identifiers * @param mConfirmedDevices2 * List of longs * @return true if every element id of mobileServerIdentifierData list is in * confirmed devices. */ protected boolean isSubset(Collection<MobileServerIdentifierData> mobileServerIdentifierData, ArrayList<Long> mConfirmedDevices2) { if (mConfirmedDevices2.size() <= 0) { return false; } for (Long subsetId : mConfirmedDevices2) { boolean found = false; for (MobileServerIdentifierData setId : mobileServerIdentifierData) { if (setId.getId().equals(subsetId)) { found = true; break; } } if (!found) { return false; } } return true; } // fill data structures with test data protected void assignCards() { for (final Long id : mDeviceData.keySet()) { final DeviceData deviceData = mDeviceData.get(id); final String queueName = deviceData.getQueueName(); if (queueName != null) { final MemoryAssign memoryAssign = new MemoryAssign(id); memoryAssign.setPic_idsFromCard(deviceData.getCards()); amqpConnectionManager.publishToBinding(Long.toString(id), MemoryMessageType.ASSIGN.toString(), memoryAssign.toJson().toString()); } } mFaceUpCard1 = null; mFaceUpCard2 = null; } // user touched device identified by data protected void handleClick(final Long id, MemoryClick data) { final DeviceData deviceData = mDeviceData.get(id); if (deviceData == null) return; final int cardId = data.getCardId(); final Card card = deviceData.getCard(cardId); if (card != null) { switch (card.getState()) { case DOWN: handleCardDown(deviceData, cardId, card); break; case UP: handleCardUp(); break; default: break; } } else { System.out.println("WTF that card is not a card"); } } private void handleCardUp() { if (isWin()) { // todo: restart game System.out.println("Thanks for clicking the win screen. Starting a new game..."); // send request for ids } else { System.out.println("Card already up"); } } private void handleCardDown(final DeviceData deviceData, final int cardId, final Card card) { System.out.println("Flip it up yo! deviceData: " + deviceData.getId()); if (mFaceUpCard1 == null) { mFaceUpCard1 = new FaceUpCard(card, deviceData, cardId); card.setState(CardState.UP); final String queueName = deviceData.getQueueName(); final MemoryFlip memoryFlip = new MemoryFlip(MemoryFlip.UP, cardId); final Long id = mFaceUpCard1.getDeviceData().getId(); final String udid = mFaceUpCard1.getDeviceData().getMobileServerIdentifierData().getDeviceSerial(); if (id != null) amqpConnectionManager.publishToBinding(Long.toString(id), MemoryMessageType.FLIP.toString(), memoryFlip.toJson().toString()); else if (udid != null) amqpConnectionManager.publishToBinding(udid, MemoryMessageType.FLIP.toString(), memoryFlip.toJson().toString()); else amqpConnectionManager.publishToBinding(queueName, MemoryMessageType.FLIP.toString(), memoryFlip.toJson().toString()); } else if (mFaceUpCard2 == null) { mFaceUpCard2 = new FaceUpCard(card, deviceData, cardId); card.setState(CardState.UP); final Card card1 = mFaceUpCard1.getCard(); final Card card2 = mFaceUpCard2.getCard(); final String queueName = deviceData.getQueueName(); final MemoryFlip memoryFlip = new MemoryFlip(MemoryFlip.UP, cardId); final Long id = mFaceUpCard2.getDeviceData().getId(); final String udid = mFaceUpCard2.getDeviceData().getMobileServerIdentifierData().getDeviceSerial(); if (id != null) amqpConnectionManager.publishToBinding(Long.toString(id), MemoryMessageType.FLIP.toString(), memoryFlip.toJson().toString()); else if (udid != null) amqpConnectionManager.publishToBinding(udid, MemoryMessageType.FLIP.toString(), memoryFlip.toJson().toString()); else amqpConnectionManager.publishToBinding(queueName, MemoryMessageType.FLIP.toString(), memoryFlip.toJson().toString()); if (card1.getPicId() == card2.getPicId()) { System.out.println("Match!"); } else { try { Thread.sleep(1000); } catch (InterruptedException e) { } flipCardDown(mFaceUpCard1); flipCardDown(mFaceUpCard2); System.out.println("No match, turning cards over again."); } mFaceUpCard1 = null; mFaceUpCard2 = null; } else { // this should never happen } if (isWin()) { // send win message System.out.println("Win!"); amqpConnectionManager.publishToAll(MemoryMessageType.FLIP.toString(), new MemoryFlip(MemoryFlip.WIN, new Integer(cardId)).toJson().toString()); } } private void flipCardDown(final FaceUpCard faceUpCard) { final Card card = faceUpCard.getCard(); card.setState(CardState.DOWN); final Integer cardId = faceUpCard.getCardId(); final DeviceData deviceData = faceUpCard.getDeviceData(); final String queueName = deviceData.getQueueName(); final MemoryFlip memoryFlip = new MemoryFlip(MemoryFlip.DOWN, cardId); final Long id = faceUpCard.getDeviceData().getId(); if (id != null) amqpConnectionManager.publishToBinding(Long.toString(id), MemoryMessageType.FLIP.toString(), memoryFlip.toJson().toString()); else amqpConnectionManager.publishToBinding(queueName, MemoryMessageType.FLIP.toString(), memoryFlip.toJson().toString()); } protected boolean isWin() { for (Long id : mDeviceData.keySet()) { final DeviceData deviceData = mDeviceData.get(id); for (final Card card : deviceData.getCards()) if (card.getState() == CardState.DOWN) return false; } return true; } }