/*
*
* Copyright 2011, Ibrahim Arief
*
* This file is part of Bambu Game Backend.
*
* Bambu Game Backend 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.
*
* Bambu Game Backend 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 Bambu Game Backend. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.appspot.bambugame.server.rest;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TimeZone;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.appspot.bambugame.server.HangmanQuestionSuggestionCommand;
import com.appspot.bambugame.server.PlurkService;
import com.appspot.bambugame.server.data.GlobalGameConfig;
import com.appspot.bambugame.server.data.HangmanPlurkQuestion;
import com.appspot.bambugame.server.data.HangmanQuestion;
import com.appspot.bambugame.server.data.HangmanQuestionSuggestion;
import com.appspot.bambugame.server.data.PlurkPlayerDailyPoint;
import com.appspot.bambugame.server.data.ScramblePlurkAnswerers;
import com.google.appengine.api.datastore.QueryResultIterator;
import com.google.appengine.api.memcache.MemcacheService;
import com.google.appengine.api.memcache.MemcacheServiceFactory;
import com.google.jplurk.Qualifier;
import com.google.jplurk.exception.PlurkException;
import com.googlecode.objectify.NotFoundException;
import com.googlecode.objectify.Objectify;
import com.googlecode.objectify.ObjectifyService;
public class HangmanGameValidatorServlet extends HttpServlet
{
/**
*
*/
private static final long serialVersionUID = -8957362320144318364L;
public static final String cLastMonitoredPlurkID = "__GAME_CONFIG_LAST_MONITORED_PLURK_ID";
public void doGet(HttpServletRequest req, HttpServletResponse resp)
{
try
{
Objectify tObjectify = ObjectifyService.begin();
Long tScramblePlurkQuestionID = null;
try
{
GlobalGameConfig tLastMonitoredPlurkID = tObjectify.get( GlobalGameConfig.class, GlobalGameConfig.getConfigDatastoreKey( cLastMonitoredPlurkID ) );
tScramblePlurkQuestionID = tLastMonitoredPlurkID.getLongValue();
}
catch (NotFoundException ex)
{
tObjectify.put( GlobalGameConfig.withKey( cLastMonitoredPlurkID ).withValue( null ) );
}
if (tScramblePlurkQuestionID != null)
{
analyzeAliveQuestionIDResponses(tScramblePlurkQuestionID, tObjectify);
}
else
{
plurkNewQuestion();
}
handlePrivatePlurks();
}
catch (Exception ex)
{
ex.printStackTrace();
System.out.println("Exception " + ex.getClass() + ", " + ex.getMessage() + " : " + Arrays.deepToString( ex.getStackTrace() ));
}
}
public void handlePrivatePlurks() throws JSONException, PlurkException
{
JSONObject tPrivatePlurks = PlurkService.getInstance().getPlurks( null, -1, false, false, true );
System.out.println("Private plurks response : " + tPrivatePlurks);
JSONArray tPrivatePlurkArray = tPrivatePlurks.getJSONArray( "plurks" );
for (int i = 0; i < tPrivatePlurkArray.length(); i++)
{
JSONObject tPrivatePlurkObject = tPrivatePlurkArray.getJSONObject( i );
handlePrivatePlurk(tPrivatePlurkObject);
}
}
public void handlePrivatePlurk(JSONObject pPrivatePlurkObject)//, JSONObject pPlurkerDataObject)
{
try
{
String tPlurkRawContent = pPrivatePlurkObject.getString( "content_raw" ).toLowerCase().trim();
long tPlurkID = pPrivatePlurkObject.getLong( "plurk_id" );
if (tPlurkRawContent.startsWith( "!suggest" ))
{
JSONObject tPrivatePlurkResponse = PlurkService.getInstance().responseGet( String.valueOf( tPlurkID ) ); //getPlurkService().using( Responses.class ).get( tPlurkID );
JSONArray tPrivatePlurkResponseArray = tPrivatePlurkResponse.getJSONArray("responses");
System.out.println("Suggestion private plurk response is : " + tPrivatePlurkResponse);
HangmanQuestionSuggestionCommand tSuggestionCommand = new HangmanQuestionSuggestionCommand( tPrivatePlurkResponseArray );
System.out.println("Suggestion command status is : " + tSuggestionCommand.toString());
if (!tSuggestionCommand.hasGreetingBeingPlurked())
{
for (int i = 0; i < HangmanQuestionSuggestionCommand.cGreetingResponseStringArray.length; i++)
{
PlurkService.getInstance().responseAdd( String.valueOf (tPlurkID), HangmanQuestionSuggestionCommand.cGreetingResponseStringArray[i], Qualifier.SAYS );
try { Thread.sleep(100); } catch (Exception ex) {}
}
}
if (!tSuggestionCommand.hasSentenceOfferBeingPlurked())
{
PlurkService.getInstance().responseAdd( String.valueOf (tPlurkID), HangmanQuestionSuggestionCommand.cSentenceOfferResponseString, Qualifier.SAYS );
return;
}
if (!tSuggestionCommand.hasQuestionBeenSubmittedByUser()) return;
if (!tSuggestionCommand.isSubmittedQuestionValid())
{
if (!tSuggestionCommand.hasInvalidReasonBeenPlurked())
{
// sorry, the sentence is not valid due to..
String tInvalidReason = HangmanQuestionSuggestionCommand.cInvalidReasonResponseString + tSuggestionCommand.getQuestionInvalidityReason();
PlurkService.getInstance().responseAdd( String.valueOf (tPlurkID), tInvalidReason, Qualifier.SAYS );
try { Thread.sleep(100); } catch (Exception ex) {}
PlurkService.getInstance().responseAdd( String.valueOf (tPlurkID), "please re-type the question by using the !question command again", Qualifier.SAYS );
}
return;
}
// at this point, the question would be valid
if (!tSuggestionCommand.hasConfirmationBeenPlurked())
{
// plurk confirmation
String tConfirmationString = HangmanQuestionSuggestionCommand.cNeedConfirmationResponseStringStart +
"the question is " +
tSuggestionCommand.getValidQuestionString() +
" and with hint " +
tSuggestionCommand.getValidHintString() +
HangmanQuestionSuggestionCommand.cNeedConfirmationResponseStringEnd;
PlurkService.getInstance().responseAdd( String.valueOf (tPlurkID), tConfirmationString, Qualifier.SAYS );
try { Thread.sleep(100); } catch (Exception ex) {}
PlurkService.getInstance().responseAdd( String.valueOf (tPlurkID), "or type !newquestion to cancel and re-start the question submission", Qualifier.SAYS );
return;
}
if (!tSuggestionCommand.hasConfirmationBeenGivenByUser())
{
return;
}
// at this point, if the question is not stored yet, we should store the question given by the user
if (!tSuggestionCommand.hasQuestionBeenAccepted())
{
// store at datastore
String tSuggesterUserName = tPrivatePlurkResponse.getJSONObject("friends").getJSONObject( "" + tSuggestionCommand.getSubmitterID() ).getString( "nick_name" );
HangmanQuestionSuggestion tSuggestion = new HangmanQuestionSuggestion(tSuggestionCommand.getValidQuestionString(),
tSuggestionCommand.getValidHintString(),
null, // extras
tSuggestionCommand.getSubmitterID(),
tSuggesterUserName,
tPlurkID);
ObjectifyService.begin().put( tSuggestion );
// print thank you
PlurkService.getInstance().responseAdd( String.valueOf (tPlurkID), HangmanQuestionSuggestionCommand.cQuestionHasBeenSubmittedResponseString, Qualifier.SAYS );
try { Thread.sleep(100); } catch (Exception ex) {}
PlurkService.getInstance().responseAdd( String.valueOf (tPlurkID), "you could also submit another question by typing !newquestion", Qualifier.SAYS );
}
}
}
catch (Exception ex)
{
System.out.println("Exception " + ex.getClass() + ", " + ex.getMessage() + " : " + Arrays.deepToString( ex.getStackTrace() ));
}
}
public void analyzeAliveQuestionIDResponses(long pPlurkQuestionID, Objectify pObjectify) throws PlurkException, JSONException
{
HangmanPlurkQuestion tPlurkQuestion = pObjectify.get( HangmanPlurkQuestion.class, pPlurkQuestionID );
if (tPlurkQuestion.LAST_RESPONSE_OFFSET == null) tPlurkQuestion.LAST_RESPONSE_OFFSET = 0;
JSONObject tPlurkResponse = PlurkService.getInstance().responseGet( String.valueOf( tPlurkQuestion.PLURK_ID ) );
JSONArray tResponseArray = tPlurkResponse.getJSONArray( "responses" );
System.out.println("Analyzing plurk ID " + tPlurkQuestion.PLURK_ID + ", plurk received " + tResponseArray.length() + " plurk responses. Full JSON response of the plurk is " + tPlurkResponse);
Set<Character> tGuessedCharacterSet = new HashSet<Character>();
Long tGuesserPlurkID = null;
boolean tIsWinBecauseOfDirectGuess = false;
Set<String> tGuesserWrongGuessStringSet = new HashSet<String>();
Set<String> tGuesserLateGuessStringSet = new HashSet<String>();
System.out.println("Plurk last response offset is : " + tPlurkQuestion.LAST_RESPONSE_OFFSET);
for (int i = tPlurkQuestion.LAST_RESPONSE_OFFSET; i < tResponseArray.length(); i++)
{
JSONObject tResponseObject = tResponseArray.getJSONObject( i );
String tResponseAnswer = tResponseObject.getString( "content_raw" ).trim().toLowerCase();
System.out.println("Validating response #" + i + ", answer from @" + tPlurkResponse.getJSONObject( "friends" ).getJSONObject( String.valueOf( tResponseObject.getLong( "user_id" ) ) ).getString( "nick_name" ) + " : " + tResponseAnswer);
if (tResponseAnswer.length() == 1)
{
Character tGuessedCharacter = tResponseAnswer.charAt( 0 );
if (Character.isLetterOrDigit( tGuessedCharacter ) && !tPlurkQuestion.hasCharacterBeenGuessed( tGuessedCharacter ))
{
tGuessedCharacterSet.add( tGuessedCharacter );
tPlurkQuestion.addGuessedCharacter( tGuessedCharacter );
if (tPlurkQuestion.hasQuestionBeenGuessed() && tGuesserPlurkID == null)
{
tGuesserPlurkID = tResponseObject.getLong( "user_id" );
}
if (tPlurkQuestion.hasQuestionBeenHanged())
{
break;
}
}
}
else if (tResponseAnswer.startsWith( "!guess " ))
{
String tPlurkerGuessString = tResponseAnswer.substring( "!guess".length() );
if (tPlurkQuestion.isGuessStringCorrect(tPlurkerGuessString) && tGuesserPlurkID == null)
{
tGuesserPlurkID = tResponseObject.getLong( "user_id" );
tIsWinBecauseOfDirectGuess = true;
}
else if (tPlurkQuestion.isGuessStringCorrect(tPlurkerGuessString) && tGuesserPlurkID != null)
{
String tPlurkerNameString = tPlurkResponse.getJSONObject( "friends" ).getJSONObject( String.valueOf( tResponseObject.getLong( "user_id" ) ) ).getString( "nick_name" );
tGuesserLateGuessStringSet.add( tPlurkerNameString + "|" + tPlurkerGuessString );
System.out.println("Adding [" + tPlurkerNameString + "|" + tPlurkerGuessString + "] to the late map " + tGuesserLateGuessStringSet.toString());
}
else
{
String tPlurkerNameString = tPlurkResponse.getJSONObject( "friends" ).getJSONObject( String.valueOf( tResponseObject.getLong( "user_id" ) ) ).getString( "nick_name" );
tGuesserWrongGuessStringSet.add( tPlurkerNameString + "|" + tPlurkerGuessString );
System.out.println("Adding [" + tPlurkerNameString + "|" + tPlurkerGuessString + "] to the map " + tGuesserWrongGuessStringSet.toString());
}
}
}
if (tGuesserPlurkID != null) // we have a winner here!
{
JSONObject tWinnerJSONObject = tPlurkResponse.getJSONObject( "friends" ).getJSONObject( String.valueOf( tGuesserPlurkID ) );
int tAnswererAnswerCount = incrementAnswererAnswerCount( tGuesserPlurkID, tWinnerJSONObject.getString( "nick_name" ) );
if (tIsWinBecauseOfDirectGuess)
{
postCongratulatoryMessage(tPlurkQuestion, tWinnerJSONObject, tIsWinBecauseOfDirectGuess, tAnswererAnswerCount);
}
else
{
postCharacterGuessesResponse(tPlurkQuestion, tGuessedCharacterSet);
try { Thread.sleep( 100 ); } catch (Exception ex) {}
postCongratulatoryMessage(tPlurkQuestion, tWinnerJSONObject, tIsWinBecauseOfDirectGuess, tAnswererAnswerCount);
}
try { Thread.sleep( 100 ); } catch (Exception ex) {}
tPlurkQuestion.IS_SOLVED = Boolean.TRUE;
// reset the monitored ID
pObjectify.put( GlobalGameConfig.withKey( cLastMonitoredPlurkID ).withValue( null ) );
if (tPlurkQuestion.SENTENCE.equalsIgnoreCase( "You have been trolled" ))
{
PlurkService.getInstance().responseAdd( String.valueOf (tPlurkQuestion.PLURK_ID), "(troll)", Qualifier.GIVES);
}
}
else if (!tGuessedCharacterSet.isEmpty()) // no winner yet, post new guesses result if someone made a guess
{
postCharacterGuessesResponse(tPlurkQuestion, tGuessedCharacterSet);
}
if (!tGuesserWrongGuessStringSet.isEmpty())
{
for (String tWrongGuess : tGuesserWrongGuessStringSet)
{
String tPlurkerName = tWrongGuess.substring( 0, tWrongGuess.indexOf( "|" ) );
String tPlurkerAnswer = tWrongGuess.substring( tWrongGuess.indexOf( "|" ) + 1 ).trim();
PlurkService.getInstance().responseAdd( String.valueOf (tPlurkQuestion.PLURK_ID), "sorry @" + tPlurkerName + ", the answer is not `" + tPlurkerAnswer + "`", Qualifier.SAYS );
}
}
if (!tGuesserLateGuessStringSet.isEmpty())
{
for (String tLateGuess : tGuesserLateGuessStringSet)
{
String tPlurkerName = tLateGuess.substring( 0, tLateGuess.indexOf( "|" ) );
String tPlurkEmote = "(troll)";
if (tPlurkerName.equalsIgnoreCase( "ruicilita" )) tPlurkEmote = "(cozy)";
PlurkService.getInstance().responseAdd( String.valueOf (tPlurkQuestion.PLURK_ID), "the answer is correct @" + tPlurkerName + ", but you are too late. " + tPlurkEmote, Qualifier.SAYS );
}
}
if (tPlurkQuestion.hasQuestionBeenHanged()) // if question has been hanged
{
PlurkService.getInstance().responseAdd( String.valueOf (tPlurkQuestion.PLURK_ID), "Whoops, you guys ran out of tries, this question is closed now. (yarr) Remember, there are only 10 incorrect guesses allowed per question.", Qualifier.SAYS );
try { Thread.sleep( 100 ); } catch (Exception ex) {}
PlurkService.getInstance().responseAdd( String.valueOf (tPlurkQuestion.PLURK_ID), "*Psst.. The answer is actually '" + tPlurkQuestion.SENTENCE + "', but don't tell anyone that I told you that* [nj]", Qualifier.SAYS );
try { Thread.sleep( 100 ); } catch (Exception ex) {}
if (tPlurkQuestion.EXTRAS != null)
{
PlurkService.getInstance().responseAdd( String.valueOf (tPlurkQuestion.PLURK_ID), "(music) " + tPlurkQuestion.EXTRAS, Qualifier.SHARES );
}
// reset the monitored ID
pObjectify.put( GlobalGameConfig.withKey( cLastMonitoredPlurkID ).withValue( null ) );
}
updatePlurkQuestionAtPlurk(tPlurkQuestion);
// update last offset with the length of response
tPlurkQuestion.LAST_RESPONSE_OFFSET = tResponseArray.length();
pObjectify.put( tPlurkQuestion );
}
protected int incrementAnswererAnswerCount(long pAnswererPlurkID, String pAnswererPlurkNickName)
{
Objectify tObjectify = ObjectifyService.begin();
ScramblePlurkAnswerers tAnswerer = null;
try
{
tAnswerer = tObjectify.get( ScramblePlurkAnswerers.class, pAnswererPlurkID );
}
catch (NotFoundException ex)
{
// expected case
tAnswerer = new ScramblePlurkAnswerers();
tAnswerer.PLURK_USER_NAME = pAnswererPlurkNickName;
tAnswerer.PLURK_USER_ID = pAnswererPlurkID;
tAnswerer.NUMBER_OF_CORRECT_ANSWERS = 0;
}
tAnswerer.NUMBER_OF_CORRECT_ANSWERS = tAnswerer.NUMBER_OF_CORRECT_ANSWERS + 1;
if (tAnswerer.PLURK_USER_NAME == null) tAnswerer.PLURK_USER_NAME = pAnswererPlurkNickName;
if (tAnswerer.PLURK_USER_NAME != null && tAnswerer.PLURK_USER_NAME.isEmpty()) tAnswerer.PLURK_USER_NAME = pAnswererPlurkNickName;
tObjectify.put( tAnswerer );
// now we add to the daily point score
PlurkPlayerDailyPoint tAnswererDailyPoint = null;
long tyyyyMMddDate = Long.parseLong( new SimpleDateFormat( "yyyyMMdd" ).format( Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) ).getTime() ) );
long tDailyPointKey = Long.parseLong( pAnswererPlurkID + "" + tyyyyMMddDate );
try
{
tAnswererDailyPoint = tObjectify.get( PlurkPlayerDailyPoint.class, tDailyPointKey );
}
catch (NotFoundException ex)
{
// expected
tAnswererDailyPoint = new PlurkPlayerDailyPoint(pAnswererPlurkID, tyyyyMMddDate, pAnswererPlurkNickName);
}
tAnswererDailyPoint.POINT = tAnswererDailyPoint.POINT + 10;
tObjectify.put( tAnswererDailyPoint );
return tAnswerer.NUMBER_OF_CORRECT_ANSWERS;
}
public void updatePlurkQuestionAtPlurk(HangmanPlurkQuestion pPlurkQuestion) throws PlurkException
{
String tUpdatedQuestionSentence = getQuestionSentence( pPlurkQuestion );
PlurkService.getInstance().plurkEdit( String.valueOf(pPlurkQuestion.PLURK_ID), tUpdatedQuestionSentence );
}
public void postCongratulatoryMessage(HangmanPlurkQuestion pPlurkQuestion, JSONObject pQuestionAnswererJSONObject, boolean pIsWinBecauseOfDirectGuess, int pAnswererAnswerCount) throws PlurkException, JSONException
{
String tQuestionAnswererNickName = pQuestionAnswererJSONObject.getString( "nick_name" );
String tAnswererGenderString = pQuestionAnswererJSONObject.getLong( "gender" ) == 0 ? "Her" : "His";
String tMessage = "congratulations to @" + tQuestionAnswererNickName + ", " + tAnswererGenderString + " direct guess is correct! :D " + tAnswererGenderString + " score is now " + (pAnswererAnswerCount * 10) + ".";
if (!pIsWinBecauseOfDirectGuess)
{
tMessage = "congratulations to @" + tQuestionAnswererNickName + ", " + tAnswererGenderString + " letter guess completes the answer! :D " + tAnswererGenderString + " score is now " + (pAnswererAnswerCount * 10) + ".";
}
PlurkService.getInstance().responseAdd( String.valueOf (pPlurkQuestion.PLURK_ID), tMessage, Qualifier.GIVES );
if (pPlurkQuestion.EXTRAS != null)
{
PlurkService.getInstance().responseAdd( String.valueOf (pPlurkQuestion.PLURK_ID), "(music) " + pPlurkQuestion.EXTRAS, Qualifier.SHARES );
}
}
public void postCharacterGuessesResponse(HangmanPlurkQuestion pPlurkQuestion, Set<Character> tGuessedCharacterSet) throws PlurkException
{
StringBuilder tStringBuilder = new StringBuilder();
tStringBuilder.append( "Guessed character" );
if (tGuessedCharacterSet.size() == 1)
{
Character tCurrentChar = tGuessedCharacterSet.iterator().next();
tStringBuilder.append( " is " + tCurrentChar );
tStringBuilder.append( pPlurkQuestion.isGuessCharacterCorrect( tCurrentChar ) ? " [Correct]" : " [Incorrect]" );
}
else if (tGuessedCharacterSet.size() > 1)
{
tStringBuilder.append( "s are : " );
Iterator<Character> tGuessedCharacterIterator = tGuessedCharacterSet.iterator();
List<Character> tCorrectGuessList = new ArrayList<Character>();
List<Character> tIncorrectGuessList = new ArrayList<Character>();
while (tGuessedCharacterIterator.hasNext())
{
Character tCurrentChar = tGuessedCharacterIterator.next();
if (pPlurkQuestion.isGuessCharacterCorrect( tCurrentChar ) )
{
tCorrectGuessList.add( tCurrentChar );
}
else
{
tIncorrectGuessList.add( tCurrentChar );
}
}
if (!tCorrectGuessList.isEmpty())
{
for (Character tCorrectChar : tCorrectGuessList)
{
tStringBuilder.append( tCorrectChar + ", ");
}
tStringBuilder.append( " [Correct]" );
}
if (!tIncorrectGuessList.isEmpty())
{
for (Character tIncorrectChar : tIncorrectGuessList)
{
tStringBuilder.append( tIncorrectChar + ", ");
}
tStringBuilder.append( " [Incorrect]" );
}
}
tStringBuilder.append( ". Remaining lives : [" + pPlurkQuestion.getLivesRemainingInPercent() + "]" );
PlurkService.getInstance().responseAdd( String.valueOf (pPlurkQuestion.PLURK_ID), tStringBuilder.toString(), Qualifier.SAYS );
try
{
try { Thread.sleep( 100 ); } catch (Exception ex) {}
PlurkService.getInstance().responseAdd( String.valueOf (pPlurkQuestion.PLURK_ID), "current sentence is : " + getCoreQuestionSentence( pPlurkQuestion ), Qualifier.SAYS );
}
catch (Exception ex)
{
System.out.println("Exception " + ex.getClass().getName() + " occurred, " + ex.getMessage() + " : " + Arrays.deepToString( ex.getStackTrace() ) );
} // anti-flood protection
}
public static final String cHangmanQuestionsMemcacheKey = "HANGMAN_QUESTIONS_KEY";
public static final String cHangmanForceReloadKey = "HANGMAN_SHOULD_FORCE_QUESTION_RELOAD_KEY";
protected static MemcacheService mMemcacheService = null;
@SuppressWarnings( "unchecked" )
protected Long getRandomQuestionID()
{
if (mMemcacheService == null) mMemcacheService = MemcacheServiceFactory.getMemcacheService();
boolean tShouldForceReload = false;
if (mMemcacheService.contains( cHangmanForceReloadKey ) && mMemcacheService.get( cHangmanForceReloadKey ) != null)
{
tShouldForceReload = Boolean.parseBoolean( String.valueOf( mMemcacheService.get( cHangmanForceReloadKey ) ) );
}
else
{
mMemcacheService.put( cHangmanForceReloadKey, Boolean.FALSE );
}
List<String> tHangmanQuestionKeyCountList = null;
if (mMemcacheService.contains( cHangmanQuestionsMemcacheKey ) && !tShouldForceReload)
{
tHangmanQuestionKeyCountList = (List<String>) mMemcacheService.get( cHangmanQuestionsMemcacheKey );
System.out.println("Fetching hangman question key list from cache : " + tHangmanQuestionKeyCountList);
}
else
{
tHangmanQuestionKeyCountList = getHangmanQuestionCountList();
mMemcacheService.put( cHangmanQuestionsMemcacheKey, tHangmanQuestionKeyCountList );
System.out.println("Expensively fetching hangman quesstion key list from datastore : " + tHangmanQuestionKeyCountList);
// reset the force reload to false
mMemcacheService.put( cHangmanForceReloadKey, Boolean.FALSE );
}
if (tHangmanQuestionKeyCountList.isEmpty()) return null;
System.out.println("Before sorting : " + tHangmanQuestionKeyCountList );
Collections.sort( tHangmanQuestionKeyCountList );
System.out.println("After sorting : " + tHangmanQuestionKeyCountList );
List<Long> tSmallestAppearanceCountSubGroupKeyList = filterWithOnlySmallestAppearanceCountGroup( tHangmanQuestionKeyCountList );
int tSelectedIndex = (int) Math.floor( Math.random() * ((double) tSmallestAppearanceCountSubGroupKeyList.size()) );
String tPickedUpString = tHangmanQuestionKeyCountList.get( tSelectedIndex );
System.out.println("Picked up string [" + tSelectedIndex + "] : " + tPickedUpString);
int tAppearanceCount = Integer.parseInt( tPickedUpString.substring( 0, tPickedUpString.indexOf( "|" ) ) );
long tQuestionID = Long.parseLong( tPickedUpString.substring( tPickedUpString.indexOf( "|" ) + 1 ) );
tAppearanceCount++;
StringBuilder tCountBuilder = new StringBuilder("" + tAppearanceCount);
while (tCountBuilder.length() < 9) tCountBuilder.insert( 0, '0' );
tHangmanQuestionKeyCountList.set( tSelectedIndex, tCountBuilder.toString() + "|" + tQuestionID );
mMemcacheService.put( cHangmanQuestionsMemcacheKey, tHangmanQuestionKeyCountList ); // re-put in memcache
return tQuestionID;
}
protected List<Long> filterWithOnlySmallestAppearanceCountGroup(List<String> pHangmanQuestionKeyCountList)
{
List<Long> tReturnList = new ArrayList<Long>();
if (pHangmanQuestionKeyCountList.isEmpty()) return tReturnList;
String tInitialQuestionString = pHangmanQuestionKeyCountList.get( 0 );
int tInitialAppearanceCount = Integer.parseInt( tInitialQuestionString.substring( 0, tInitialQuestionString.indexOf( "|" ) ) );
tReturnList.add( Long.parseLong( tInitialQuestionString.substring( tInitialQuestionString.indexOf( "|" ) + 1 ) ) );
for (int i = 1; i < pHangmanQuestionKeyCountList.size(); i++)
{
String tHangmanQuestionKeyCountString = pHangmanQuestionKeyCountList.get( i );
int tAppearanceCount = Integer.parseInt( tHangmanQuestionKeyCountString.substring( 0, tHangmanQuestionKeyCountString.indexOf( "|" ) ) );
if (tAppearanceCount == tInitialAppearanceCount)
{
tReturnList.add( Long.parseLong( tHangmanQuestionKeyCountString.substring( tHangmanQuestionKeyCountString.indexOf( "|" ) + 1 ) ) );
}
else
{
break;
}
}
return tReturnList;
}
protected List<String> getHangmanQuestionCountList()
{
Objectify tObjectify = ObjectifyService.begin();
QueryResultIterator<HangmanQuestion> tQueryResultIterable = tObjectify.query( HangmanQuestion.class ).fetch().iterator();
List<String> tCountSentenceString = new ArrayList<String>();
while (tQueryResultIterable.hasNext())
{
HangmanQuestion tQuestion = tQueryResultIterable.next();
StringBuilder tQuestionCountBuilder = new StringBuilder("" + tQuestion.APPEARANCE_COUNT);
while (tQuestionCountBuilder.length() < 9) tQuestionCountBuilder.insert( 0, '0' );
tCountSentenceString.add( tQuestionCountBuilder.toString() + "|" + tQuestion.ID );
}
return tCountSentenceString;
}
public void plurkNewQuestion() throws PlurkException, JSONException
{
Long tRandomQuestionID = getRandomQuestionID();
if (tRandomQuestionID == null) return; // this means there are no questions in the datastore
Objectify tObjectify = ObjectifyService.begin();
HangmanQuestion tQuestion = tObjectify.get( HangmanQuestion.class, tRandomQuestionID );
HangmanPlurkQuestion tPlurkQuestion = new HangmanPlurkQuestion( 0, tQuestion.SENTENCE, tQuestion.HINT, tQuestion.EXTRAS );
JSONObject tAddResponse = PlurkService.getInstance().plurkAdd( getQuestionSentence( tPlurkQuestion ), Qualifier.ASKS );
tPlurkQuestion.PLURK_ID = tAddResponse.getLong( "plurk_id" );
tObjectify.put( tPlurkQuestion );
System.out.print("Updating appearance count of question " + tQuestion.SENTENCE + " with ID " + tQuestion.ID + " from " + tQuestion.APPEARANCE_COUNT);
tQuestion.APPEARANCE_COUNT = tQuestion.APPEARANCE_COUNT + 1;
System.out.println(" to " + tQuestion.APPEARANCE_COUNT);
tObjectify.put( tQuestion );
tObjectify.put( GlobalGameConfig.withKey( cLastMonitoredPlurkID ).withValue( tPlurkQuestion.PLURK_ID ) );
try { Thread.sleep( 100 ); } catch (Exception ex) {}
// add response about how to play
PlurkService.getInstance().responseAdd( String.valueOf (tPlurkQuestion.PLURK_ID), "write one-letter response to guess a letter. To directly guess the answer, write !guess<space><your guess>.", Qualifier.SAYS );
}
public String getCoreQuestionSentence(HangmanPlurkQuestion pPlurkQuestion)
{
String[] tSentenceWordArray = pPlurkQuestion.SENTENCE.trim().split( " " );
StringBuilder tSentenceStringBuilder = new StringBuilder();
for (int i = 0; i < tSentenceWordArray.length; i++)
{
String tSentenceWord = tSentenceWordArray[i];
for (int j = 0; j < tSentenceWord.length(); j++)
{
Character tSentenceChar = tSentenceWord.charAt( j );
Character tAppendedChar = pPlurkQuestion.hasCharacterBeenGuessed( tSentenceChar ) ? tSentenceChar : '_';
// special handling for special characters print out
if (HangmanPlurkQuestion.cSpeciallyAcceptedChars.contains( tSentenceChar) )
{
tAppendedChar = tSentenceChar;
}
tSentenceStringBuilder.append( tAppendedChar + " " );
}
if (i < tSentenceWordArray.length - 1) // if not the last one
{
tSentenceStringBuilder.append( "[sp] " );
}
}
return tSentenceStringBuilder.toString();
}
public String getQuestionSentence(HangmanPlurkQuestion pPlurkQuestion)
{
int tNumberOfWords = pPlurkQuestion.getNumberOfWords();
StringBuilder tSentenceStringBuilder = new StringBuilder("[" + tNumberOfWords + " word" + (tNumberOfWords > 1 ? "s" : "") + "] [" + pPlurkQuestion.getLivesRemainingInPercent() + "]");
tSentenceStringBuilder.append( getCoreQuestionSentence( pPlurkQuestion ) );
tSentenceStringBuilder.append( " (hint: " + pPlurkQuestion.HINT + ")" );
return tSentenceStringBuilder.toString();
}
}