[virtualcommons-svn] commit/foraging: alllee: refactoring group formation and round logic / workflo
Status: Beta
Brought to you by:
alllee
From: Bitbucket <com...@bi...> - 2011-09-24 01:01:54
|
1 new changeset in foraging: http://bitbucket.org/virtualcommons/foraging/changeset/d5a8038be1d8/ changeset: d5a8038be1d8 user: alllee date: 2011-09-24 03:01:40 summary: refactoring group formation and round logic / workflow. still some issues to work out, namely when group formation should actually occur. affected #: 5 files (-1 bytes) --- a/src/main/java/edu/asu/commons/foraging/conf/RoundConfiguration.java Thu Sep 22 08:14:50 2011 -0700 +++ b/src/main/java/edu/asu/commons/foraging/conf/RoundConfiguration.java Fri Sep 23 18:01:40 2011 -0700 @@ -3,6 +3,7 @@ import java.awt.Dimension; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Properties; @@ -632,5 +633,11 @@ public double getQuizCorrectAnswerReward() { return getDoubleProperty("quiz-correct-answer-reward", getParentConfiguration().getQuizCorrectAnswerReward()); } + + @Override + public String toString() { + List<RoundConfiguration> allParameters = getParentConfiguration().getAllParameters(); + return String.format("Round %d of %d -- %s", allParameters.indexOf(this) + 1, allParameters.size(), getProperties()); + } } --- a/src/main/java/edu/asu/commons/foraging/facilitator/Facilitator.java Thu Sep 22 08:14:50 2011 -0700 +++ b/src/main/java/edu/asu/commons/foraging/facilitator/Facilitator.java Fri Sep 23 18:01:40 2011 -0700 @@ -11,12 +11,12 @@ import edu.asu.commons.event.ConfigurationEvent; import edu.asu.commons.event.EndRoundRequest; import edu.asu.commons.event.EventTypeProcessor; +import edu.asu.commons.event.FacilitatorMessageEvent; import edu.asu.commons.event.SetConfigurationEvent; import edu.asu.commons.facilitator.BaseFacilitator; import edu.asu.commons.foraging.conf.RoundConfiguration; import edu.asu.commons.foraging.conf.ServerConfiguration; import edu.asu.commons.foraging.event.BeginChatRoundRequest; -import edu.asu.commons.foraging.event.FacilitatorCensoredChatRequest; import edu.asu.commons.foraging.event.FacilitatorEndRoundEvent; import edu.asu.commons.foraging.event.FacilitatorSanctionUpdateEvent; import edu.asu.commons.foraging.event.FacilitatorUpdateEvent; @@ -76,6 +76,11 @@ facilitatorWindow.updateDebriefing(event); } }); + addEventProcessor(new EventTypeProcessor<FacilitatorMessageEvent>(FacilitatorMessageEvent.class) { + public void handle(FacilitatorMessageEvent event) { + facilitatorWindow.addMessage(event.getMessage()); + } + }); addEventProcessor(new EventTypeProcessor<QuizCompletedEvent>(QuizCompletedEvent.class) { public void handle(QuizCompletedEvent event) { facilitatorWindow.quizCompleted(event); --- a/src/main/java/edu/asu/commons/foraging/facilitator/FacilitatorWindow.java Thu Sep 22 08:14:50 2011 -0700 +++ b/src/main/java/edu/asu/commons/foraging/facilitator/FacilitatorWindow.java Fri Sep 23 18:01:40 2011 -0700 @@ -213,7 +213,9 @@ } JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, informationScrollPane, messagePanel); add(splitPane, BorderLayout.CENTER); - splitPane.setDividerLocation(0.3d); + double proportion = 0.6d; + splitPane.setDividerLocation(proportion); + splitPane.setResizeWeight(proportion); } private void setInstructions(String contents) { --- a/src/main/java/edu/asu/commons/foraging/server/ForagingServer.java Thu Sep 22 08:14:50 2011 -0700 +++ b/src/main/java/edu/asu/commons/foraging/server/ForagingServer.java Fri Sep 23 18:01:40 2011 -0700 @@ -22,6 +22,7 @@ import edu.asu.commons.event.ClientMessageEvent; import edu.asu.commons.event.EndRoundRequest; import edu.asu.commons.event.EventTypeProcessor; +import edu.asu.commons.event.FacilitatorMessageEvent; import edu.asu.commons.event.FacilitatorRegistrationRequest; import edu.asu.commons.event.RoundStartedMarkerEvent; import edu.asu.commons.event.SetConfigurationEvent; @@ -183,7 +184,7 @@ protected StateMachine getStateMachine() { return stateMachine; } - + private RoundConfiguration getCurrentRoundConfiguration() { return getConfiguration().getCurrentParameters(); } @@ -213,6 +214,7 @@ initializeFacilitatorHandlers(); } + // FIXME: remove this as we phase out the 3d environment private void initializeRoundProcessor() { if (serverDataModel.getRoundConfiguration().is2dExperiment()) { roundProcessor = new Command() { @@ -302,10 +304,10 @@ ClientData clientData = clients.get(event.getId()); clientData.addCorrectQuizAnswers(event.getNumberOfCorrectAnswers()); if (numberOfSubmittedQuizzes >= clients.size()) { - // we're done, notify the sleeping queue. + // we're done, notify the quizSignal logger.info("Received all quizzes, notifying quiz signal"); + transmit(new FacilitatorMessageEvent(facilitatorId, "Received all quizzes, ready to start round.")); Utils.notify(quizSignal); - numberOfSubmittedQuizzes = 0; } } @@ -478,78 +480,6 @@ default: logger.severe("tried to sanction with EnforcementMechanism.NONE"); } - - // TODO: reimplement - // - // - // int srcEnforcementType = sourceClient.getEnforcementData().getResultIndex(); - // int tgtEnforcementType = targetClient.getEnforcementData().getResultIndex(); - // - // if(srcEnforcementType == tgtEnforcementType) { - // System.out.println("This condition should be always true"); - // switch(srcEnforcementType) { - // /* - // * No sanctioning just harvest - // */ case NO_SANCTIONS: - // System.out.println("This code should never be reached"); - // - // break; - // - // /* - // * Harvest and sanction - // * Reduce other by 2 but also own by 1 - // */ - // case HARVEST_WITH_SANCTION: - // sourceClient.sanctionCost(); - // targetClient.monitorSanctionPenalty(1); - // // add sanction request to the target client so they can figure out who just sanctioned them - // targetClient.getLatestSanctions().add(request); - // transmit(new ClientMessageEvent(sourceClient.getId(), - // String.format("Subtracting %d tokens from # %d at the cost of %d to yourself." , - // getCurrentRoundConfiguration().getSanctionPenalty(1), - // targetClient.getAssignedNumber(), - // getCurrentRoundConfiguration().getSanctionCost()))); - // transmit(new ClientMessageEvent(targetClient.getId(), - // String.format("# %d subtracted %d tokens from you.", sourceClient.getAssignedNumber(), getCurrentRoundConfiguration().getSanctionPenalty(1)))); - // break; - // - // - // /* - // * One participant is a moniter who sanctions but cannot harvest - // * Moniter can give penalty by subtract 1 from sanctionee - // * Nothing taken from Moniter but receives 25% tokens from each - // */ case RANDOM_SANCTIONER: - // //sourceClient.sanctionCost(); - // targetClient.monitorSanctionPenalty(0); - // // add sanction request to the target client so they can figure out who just sanctioned them - // targetClient.getLatestSanctions().add(request); - // transmit(new ClientMessageEvent(sourceClient.getId(), - // String.format("Subtracting %d tokens from # %d at the cost of 0 to yourself." , - // getCurrentRoundConfiguration().getSanctionPenalty(0), - // targetClient.getAssignedNumber()))); - // transmit(new ClientMessageEvent(targetClient.getId(), - // String.format("# %d subtracted %d tokens from you.", sourceClient.getAssignedNumber(), getCurrentRoundConfiguration().getSanctionPenalty(0)))); - // break; - // - // /* - // * Harvest and sanction for 48 secs in sequence - // * One participant is a moniter who sanctions but cannot harvest - // * Moniter can give penalty by subtract 1 from sanctionee - // * Nothing taken from Moniter but receives 25% tokens from each - // */ case CIRCULAR_MONITERING: - // //sourceClient.sanctionCost(); - // targetClient.monitorSanctionPenalty(0); - // // add sanction request to the target client so they can figure out who just sanctioned them - // targetClient.getLatestSanctions().add(request); - // transmit(new ClientMessageEvent(sourceClient.getId(), - // String.format("Subtracting %d tokens from # %d at the cost of 0 to yourself." , - // getCurrentRoundConfiguration().getSanctionPenalty(), - // targetClient.getAssignedNumber()))); - // transmit(new ClientMessageEvent(targetClient.getId(), - // String.format("# %d subtracted %d tokens from you.", sourceClient.getAssignedNumber(), getCurrentRoundConfiguration().getSanctionPenalty()))); - // break; - // } - // } } private void handleRealTimeSanctionRequest(RealTimeSanctionRequest request) { @@ -642,17 +572,16 @@ addEventProcessor(new EventTypeProcessor<BeginRoundRequest>(BeginRoundRequest.class) { public void handle(BeginRoundRequest event) { if (event.getId().equals(facilitatorId)) { - if (getCurrentRoundConfiguration().isFirstRound()) { - // shuffle groups - // set up the Client Group relationships ONLY IF we are in the first round... - // kind of a hack. - shuffleParticipants(); - initializeResourceDispenser(); + if (isReadyToStartRound()) { + logger.info("Begin round request from facilitator - starting round."); + experimentStarted = true; + Utils.notify(roundSignal); + System.out.println("Notified round signal"); } - logger.info("Begin round request from facilitator - starting round."); - experimentStarted = true; - Utils.notify(roundSignal); - System.out.println("Notified round signal"); + else { + transmit(new FacilitatorMessageEvent(facilitatorId, + String.format("Couldn't start round, waiting on %d of %d quizzes", numberOfSubmittedQuizzes, clients.size()))); + } } else { logger.warning("Ignoring begin round request from id: " + event.getId()); @@ -708,12 +637,13 @@ public void handle(BeginChatRoundRequest request) { if (getCurrentRoundConfiguration().isChatEnabled()) { // FIXME: need to handle properly corner case where chat is enabled before the first round - // at that point the clients haven't been added to any groups yet. - // probably the best way to handle this is to have the clients added - // to groups when the show instructions request is handled. + // - at that point the clients haven't been added to any groups yet. + // another way to handle this is to have the clients added + // to groups when the show instructions request is handled.. + initializeGroups(); + /* if (getCurrentRoundConfiguration().isFirstRound()) { shuffleParticipants(); - initializeResourceDispenser(); } for (Map.Entry<Identifier, ClientData> entry : clients.entrySet()) { @@ -734,12 +664,20 @@ // just store communication traffic in a separate text file. } + */ } } }); // FIXME: handle reconfiguration requests from facilitator } + protected boolean isReadyToStartRound() { + if (getCurrentRoundConfiguration().isQuizEnabled()) { + return numberOfSubmittedQuizzes >= clients.size(); + } + return true; + } + private void relayChatRequest(ChatRequest request) { Identifier source = request.getSource(); Identifier target = request.getTarget(); @@ -795,19 +733,27 @@ Utils.sleep(SERVER_SLEEP_INTERVAL); break; case WAITING: + // FIXME: there is an inherent nastiness going on with this model of control flow + // the problem is this: when we first spin up the server, there are no connected clients. control flow + // enters here, we initialize the round (with no participants, etc.) and then wait on the quiz signal + + // the issue is that we need to initialize the groups at some clear, well-defined time. + // we have to do it after all the clients are connected, so perhaps showInstructions can be the time to do it? + // the previous way which I've been slowly refactoring was to do it on the beginning of the first round (as a special case) + // in the handler for BeginRoundRequest) and to do it at the end of every round. Probably better to do it in round initialization + // initialize persister first so we store all relevant events. // persister MUST be initialized early so that we store pre-round events like QuizResponseEvent, ChatEvent, and the various Ranking // requests. - initializeRound(); - - getLogger().info("Round is initialized: now waiting for facilitator signal to start next round."); + persister.initialize(getCurrentRoundConfiguration()); + getLogger().info("Initialized persister, waiting for facilitator signal to start next round."); if (getCurrentRoundConfiguration().isQuizEnabled()) { getLogger().info("Waiting for all quizzes to be submitted."); Utils.waitOn(quizSignal); } // then wait for the signal from the facilitator to actually start the round (a chat session might occur or a voting session). Utils.waitOn(roundSignal); - // actually start the round once we receive the facilitator signal. + startRound(); break; default: @@ -933,6 +879,7 @@ } private void cleanupRound() { + numberOfSubmittedQuizzes = 0; serverDataModel.cleanupRound(); for (ClientData clientData : clients.values()) { clientData.reset(); @@ -945,17 +892,9 @@ serverState = ServerState.WAITING; return; } - RoundConfiguration currentRoundConfiguration = getCurrentRoundConfiguration(); RoundConfiguration nextRoundConfiguration = getConfiguration().nextRound(); serverDataModel.setRoundConfiguration(nextRoundConfiguration); initializeRoundProcessor(); - // reset the group linkages - if (shouldShuffleParticipants(currentRoundConfiguration, nextRoundConfiguration)) { - shuffleParticipants(); - } - else { - initializeClientPositions(); - } logger.info("Advancing to round # " + getConfiguration().getCurrentRoundNumber()); // send the next round configuration to each client for (Identifier id : clients.keySet()) { @@ -964,14 +903,16 @@ transmit(new SetConfigurationEvent<RoundConfiguration>(facilitatorId, nextRoundConfiguration)); } - private boolean shouldShuffleParticipants(RoundConfiguration currentRoundConfiguration, RoundConfiguration nextRoundConfiguration) { + private boolean shouldShuffleParticipants() { + RoundConfiguration currentRoundConfiguration = getCurrentRoundConfiguration(); + RoundConfiguration previousRoundConfiguration = getConfiguration().getPreviousRoundConfiguration(); // when do we _have_ to shuffle participants? // 1. when randomize-groups is set for the next round // 2. when we move from a private property round to a open access round // 3. in general, when the clients per group in the current round is different from the // clients per group in the next round (FIXME: is this too broad or can #2 just be a special case of this?) - return nextRoundConfiguration.shouldRandomizeGroup() - || (currentRoundConfiguration.getClientsPerGroup() != nextRoundConfiguration.getClientsPerGroup()); + return currentRoundConfiguration.shouldRandomizeGroup() + || (previousRoundConfiguration.getClientsPerGroup() != currentRoundConfiguration.getClientsPerGroup()); } private void shuffleParticipants() { @@ -993,13 +934,19 @@ clientData.initializePosition(); } } - - private void initializeRound() { - persister.initialize(getCurrentRoundConfiguration()); - initializeResourceDispenser(); - } - - private void initializeResourceDispenser() { + + private void initializeGroups() { + // reset group linkages if necessary + if (shouldShuffleParticipants()) { + logger.info("Shuffling participants"); + shuffleParticipants(); + } + else { + logger.info("Didn't need to shuffle participants : " + getCurrentRoundConfiguration()); + // shuffleParticipants automatically initializes the client positions + // if we don't shuffle, we need to manually re-initialize them. + initializeClientPositions(); + } // set up the resource dispenser, generates the initial resource distributions for the // groups, must be done after creating the client group relationships. resourceDispenser.initialize(); @@ -1007,6 +954,10 @@ private void startRound() { RoundConfiguration roundConfiguration = getCurrentRoundConfiguration(); + // actually start the round once we receive the facilitator signal. + getLogger().info("Initializing groups."); + // FIXME: what if we want groups before the round actually begins..? + initializeGroups(); // send RoundStartedEvents to all connected clients for (Map.Entry<Identifier, ClientData> entry : clients.entrySet()) { Identifier id = entry.getKey(); --- a/src/main/resources/configuration/asu-experiments/fall-2011/pretest/server.xml Thu Sep 22 08:14:50 2011 -0700 +++ b/src/main/resources/configuration/asu-experiments/fall-2011/pretest/server.xml Fri Sep 23 18:01:40 2011 -0700 @@ -15,17 +15,18 @@ <entry key="number-of-rounds">7</entry><entry key="facilitator-instructions"><![CDATA[ -<h2>Facilitator Instructions</h2> -<hr><p> This facilitator interface allows you to control the experiment. In general you - will be invoking this sequence: - + will be following a sequence similar to this: <ol><li>Show instructions</li><li>Start round</li> - <li>Show trust game as necessary</li> - <li>Start standalone chat round, as necessary</li> + <li>After round is over + <ol> + <li>show trust game if necessary</li> + <li>start standalone chat round if necessary</li> + </ol> + </li><li>Goto 1.</li></ol></p> Repository URL: https://bitbucket.org/virtualcommons/foraging/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email. |