private static Dictionary <int, PlayerData> parseOneTwoThreeDatafile(TwoA twoA, string adaptId, string gameId, List <DataRecord> dataRecordList, Dictionary <string, ScenarioData> scenarioDatabase)
        {
            using (StreamReader reader = new StreamReader(Path.Combine(contentPath, "user_data.txt"))) {
                string line       = null;
                bool   headerFlag = true;

                char[] separators = new char[] { '\t' };

                Dictionary <int, PlayerData> playerDatabase = new Dictionary <int, PlayerData>();

                int lastCounted     = 0;
                int counter         = 0;
                int counterInterval = 100000;

                while ((line = reader.ReadLine()) != null)
                {
                    if (headerFlag)
                    {
                        // [SC] skip header
                        headerFlag = false;
                        continue;
                        //TrialID	UserID	MirrorID	ItemID	SetLevel	C1	C2	C3	RT	Correct
                    }

                    string[] cols = line.Split(separators);

                    string mirrorId = cols[2];
                    string scenarioId = cols[3];
                    int    trialId, playerId, setLevel, accuracy, rt;
                    if (!(Int32.TryParse(cols[0], out trialId) &&
                          Int32.TryParse(cols[1], out playerId) &&
                          Int32.TryParse(cols[4], out setLevel) &&
                          Int32.TryParse(cols[9], out accuracy) &&
                          Int32.TryParse(cols[8], out rt)
                          ))
                    {
                        // [SC] parsing error
                        return(null);
                    }

                    dataRecordList.Add(new DataRecord {
                        TrialID    = trialId,
                        PlayerID   = playerId,
                        MirrorID   = mirrorId,
                        ScenarioID = scenarioId,
                        SetLevel   = setLevel,
                        RT         = rt,
                        Accuracy   = accuracy
                    });

                    PlayerData playerData;
                    if (!playerDatabase.TryGetValue(playerId, out playerData))
                    {
                        playerData = new PlayerData(playerId);
                        playerDatabase.Add(playerId, playerData);
                        twoA.AddPlayer(adaptId, gameId, "" + playerId);
                    }

                    ScenarioData scenarioData = playerData.AddScenario(mirrorId, scenarioId, setLevel);
                    scenarioData.AddRecord(trialId, accuracy, rt);
                    twoA.AddScenario(adaptId, gameId, scenarioId);

                    if (!scenarioDatabase.ContainsKey(scenarioId))
                    {
                        scenarioDatabase.Add(scenarioId, new ScenarioData(mirrorId, scenarioId, setLevel));
                    }
                    ScenarioData scenarioDataPooled = scenarioDatabase[scenarioId];
                    scenarioDataPooled.AddRecord(trialId, accuracy, rt);

                    if (++counter - lastCounted == counterInterval)
                    {
                        lastCounted = counter;
                        printMsg("" + counter);
                    }
                }

                // [SC] for test purpose only

                /*printMsg(String.Format("Number of trials in the ordered list: {0}", playerOrderedList.Count));
                 *
                 * GameNode gameNode = twoA.AdaptationData.AdaptationList.First(p => p.AdaptationID.Equals(adaptId)).GameList.First(p => p.GameID.Equals(gameId));
                 * printMsg(String.Format("Player count in list and dictionary: {0}, {1} "
                 *  , gameNode.PlayerData.PlayerList.Count, gameNode.PlayerData.playerDict.Count));
                 * printMsg(String.Format("Scenario count in list and in dictionary: {0}, {1}"
                 *  , gameNode.ScenarioData.ScenarioList.Count, gameNode.ScenarioData.scenarioDict.Count));*/

                // [SC] for test purpose only

                /*foreach (KeyValuePair<int, PlayerData> playerDataPair in playerDatabase) {
                 *  PlayerData playerData = playerDataPair.Value;
                 *  printMsg(String.Format("Player key: {0}, {1}", playerDataPair.Key, playerData.PlayerID));
                 *
                 *  foreach (KeyValuePair<string, ScenarioData> scenarioDataPair in playerData.scenarioDatabase) {
                 *      ScenarioData scenarioData = scenarioDataPair.Value;
                 *      printMsg(String.Format("\tScenario key: {0}, {1}", scenarioDataPair.Key, scenarioData.ScenarioID));
                 *      printMsg(String.Format("\tScenario mirror ID: {0}, SetLevel: {1}", scenarioData.MirrorID, scenarioData.SetLevel));
                 *
                 *      foreach (ScenarioRecord record in scenarioData.scenarioRecords) {
                 *          printMsg(String.Format("\t\tTrialID: {0}, RT: {1}, Accuracy: {2}, Used: {3}", record.TrialID, record.RT, record.Accuracy, record.Used));
                 *      }
                 *  }
                 * }*/

                // [SC] for test purpose only

                /*int trialCounter = 0;
                 * foreach (KeyValuePair<int, PlayerData> playerDataPair in playerDatabase) {
                 *  PlayerData playerData = playerDataPair.Value;
                 *
                 *  foreach (KeyValuePair<string, ScenarioData> scenarioDataPair in playerData.scenarioDatabase) {
                 *      ScenarioData scenarioData = scenarioDataPair.Value;
                 *
                 *      trialCounter += scenarioData.scenarioRecords.Count;
                 *  }
                 * }
                 * if (1383964 != trialCounter) {
                 *  printMsg("Invalid number of trial records.");
                 * } else {
                 *  printMsg("All trial records parsed");
                 * }*/

                printMsg("================= Data file parsed.");

                return(playerDatabase);
            }
        }
        public static void doOneTwoThreeSim()
        {
            string adaptID = "Game difficulty - Player skill";
            string gameID  = "OneTwoThree";

            // [SC] create Bridge instance
            MyBridge bridge = new MyBridge();

            // [SC] instantiate the TwoA asset
            TwoA   twoA       = new TwoA(bridge);
            double distMean   = 0.75;
            double distSD     = 0.1;
            double lowerLimit = 0.5;
            double upperLimit = 1.0;

            twoA.SetTargetDistribution(distMean, distSD, lowerLimit, upperLimit);

            // [SC] a lis of player in order of gameplays in datafile
            List <DataRecord> dataRecordList = new List <DataRecord>();

            // [SC] contains info about scenarios such as level and mirror group
            Dictionary <string, ScenarioData> scenarioDatabase = new Dictionary <string, ScenarioData>();

            // [SC] load the data file
            Dictionary <int, PlayerData> playerDatabase = parseOneTwoThreeDatafile(twoA, adaptID, gameID, dataRecordList, scenarioDatabase);

            if (playerDatabase == null)
            {
                return;
            }

            int blockSize = 20;

            foreach (string mode in new string[] { "old", "new" })
            {
                for (int blockIndex = 0; blockIndex < blockSize; blockIndex++)
                {
                    int lastCounted     = 0;
                    int counter         = 0;
                    int counterInterval = 10000;

                    // [SC] approach 1

                    /*foreach (DataRecord dataRecord in dataRecordList) {
                     *  int playerID = dataRecord.PlayerID;
                     *
                     *  // [SC] decide which scenario this player should play
                     *  string scenarioID = twoA.TargetScenarioIDOld(adaptID, gameID, "" + playerID, true);
                     *
                     *  // [SC] obtain response time and accuracy
                     *  PlayerData playerData = playerDatabase[playerID];
                     *  ScenarioData scenarioData = playerData.GetScenario(scenarioID);
                     *  if (scenarioData == null) { // [SC] the player has not played the scenario
                     *      // [SC] use another scenario of similar set level
                     *      int setLevel = scenarioDatabase[scenarioID].SetLevel;
                     *      scenarioData = playerData.GetScenario(setLevel); // [TODO] possible error point
                     *  }
                     *  if (scenarioData == null) {
                     *      ScenarioData scenarioDataOverall = scenarioDatabase[scenarioID];
                     *      twoA.UpdateRatings(adaptID, gameID, "" + playerID, scenarioID
                     *          , scenarioDataOverall.GetAvgRT(), scenarioDataOverall.GetAvgAccuracy(), false);
                     *  }
                     *  else {
                     *      ScenarioRecord scenarioRecord = scenarioData.GetRecord();
                     *      twoA.UpdateRatings(adaptID, gameID, "" + playerID, scenarioID, scenarioRecord.RT, scenarioRecord.Accuracy, false);
                     *  }
                     *
                     *  if (++counter - lastCounted == counterInterval) {
                     *      lastCounted = counter;
                     *      printMsg("" + counter);
                     *  }
                     * }*/

                    // [SC] approach 2
                    foreach (DataRecord dataRecord in dataRecordList)
                    {
                        int playerID = dataRecord.PlayerID;

                        // [SC] decide which scenario this player should play
                        string scenarioID;
                        if (mode.Equals("old"))
                        {
                            scenarioID = twoA.TargetScenarioIDOld(adaptID, gameID, "" + playerID, true);
                        }
                        else
                        {
                            scenarioID = twoA.TargetScenarioID(adaptID, gameID, "" + playerID);
                        }

                        // [SC] obtain response time and accuracy
                        PlayerData     playerData   = playerDatabase[playerID];
                        ScenarioData   scenarioData = playerData.GetScenario(scenarioID);
                        ScenarioRecord scenarioRecord;
                        if (scenarioData == null)   // [SC] the player has not played the scenario
                        // [SC] use a random record from all players of the scenario
                        {
                            ScenarioData scenarioDataOverall = scenarioDatabase[scenarioID];
                            scenarioRecord = scenarioDataOverall.GetRandomRecord();
                        }
                        else
                        {
                            scenarioRecord = scenarioData.GetRecord();
                        }

                        twoA.UpdateRatings(adaptID, gameID, "" + playerID, scenarioID, scenarioRecord.RT, scenarioRecord.Accuracy, false);

                        if (++counter - lastCounted == counterInterval)
                        {
                            lastCounted = counter;
                            printMsg("" + counter);
                        }
                    }

                    // [SC] approach 3

                    /*foreach (DataRecord dataRecord in dataRecordList) {
                     *  //int playerID = dataRecord.PlayerID;
                     *  int playerID = dataRecordList[0].PlayerID;
                     *
                     *  // [SC] decide which scenario this player should play
                     *  string scenarioID;
                     *  if (mode.Equals("old")) {
                     *      scenarioID = twoA.TargetScenarioIDOld(adaptID, gameID, "" + playerID, true);
                     *  }
                     *  else {
                     *      scenarioID = twoA.TargetScenarioID(adaptID, gameID, "" + playerID);
                     *  }
                     *
                     *  ScenarioData scenarioDataOverall = scenarioDatabase[scenarioID];
                     *  ScenarioRecord scenarioRecord = scenarioDataOverall.GetRandomRecord();
                     *  twoA.UpdateRatings(adaptID, gameID, "" + playerID, scenarioID, scenarioRecord.RT, scenarioRecord.Accuracy, false);
                     *
                     *  if (++counter - lastCounted == counterInterval) {
                     *      lastCounted = counter;
                     *      printMsg("" + counter);
                     *  }
                     * }*/

                    // [SC] creating a file with final ratings
                    using (StreamWriter ratingfile = new StreamWriter(Path.Combine(OneTwoThreeSimResultsPath, "ratings_" + mode + "_" + blockIndex + ".txt"))) {
                        string line = ""
                                      + "\"ScenarioID\""
                                      + "\t" + "\"Rating\""
                                      + "\t" + "\"PlayCount\""
                                      + "\t" + "\"Uncertainty\""
                                      + "\t" + "\"MirrorID\""
                                      + "\t" + "\"SetLevel\"";

                        ratingfile.WriteLine(line);

                        foreach (ScenarioData scenarioData in scenarioDatabase.Values)
                        {
                            ScenarioNode scenarioNode = twoA.Scenario(adaptID, gameID, scenarioData.ScenarioID);

                            line = ""
                                   + "\"" + scenarioData.ScenarioID + "\""
                                   + "\t" + "\"" + scenarioNode.Rating + "\""
                                   + "\t" + "\"" + scenarioNode.PlayCount + "\""
                                   + "\t" + "\"" + scenarioNode.Uncertainty + "\""
                                   + "\t" + "\"" + scenarioData.MirrorID + "\""
                                   + "\t" + "\"" + scenarioData.SetLevel + "\"";

                            ratingfile.WriteLine(line);

                            // [SC] reseting scenario data
                            scenarioNode.Rating      = 0.001;
                            scenarioNode.PlayCount   = 0;
                            scenarioNode.KFactor     = 0.0075;
                            scenarioNode.Uncertainty = 1.0;
                            scenarioNode.LastPlayed  = "2012-12-31T11:59:59";
                        }
                    }

                    // [SC] creating a file with history of gameplays including player and scenario ratings
                    using (StreamWriter datafile = new StreamWriter(Path.Combine(OneTwoThreeSimResultsPath, "gameplay_" + mode + "_" + blockIndex + ".txt"))) {
                        GameplaysData  gameplays = twoA.GameplaysData;
                        TwoAAdaptation adaptNode = gameplays.Adaptation.First(p => p.AdaptationID.Equals(adaptID));
                        TwoAGame       gameNode  = adaptNode.Game.First(p => p.GameID.Equals(gameID));

                        string line = ""
                                      + "ID"
                                      + "\t" + "PlayerID"
                                      + "\t" + "ScenarioID"
                                      //+ "\t" + "Timestamp"
                                      + "\t" + "RT"
                                      + "\t" + "Accuracy"
                                      + "\t" + "PlayerRating"
                                      + "\t" + "ScenarioRating";

                        datafile.WriteLine(line);

                        int id = 1;
                        foreach (TwoAGameplay gp in gameNode.Gameplay)
                        {
                            /*line = ""
                             + "\"" + id++ + "\""
                             + "\t" + "\"" + gp.PlayerID + "\""
                             + "\t" + "\"" + gp.ScenarioID + "\""
                             + "\t" + "\"" + gp.Timestamp + "\""
                             + "\t" + "\"" + gp.RT + "\""
                             + "\t" + "\"" + gp.Accuracy + "\""
                             + "\t" + "\"" + gp.PlayerRating + "\""
                             + "\t" + "\"" + gp.ScenarioRating + "\"";*/

                            line = ""
                                   + id++
                                   + "\t" + gp.PlayerID
                                   + "\t" + gp.ScenarioID
                                   + "\t" + gp.RT
                                   + "\t" + gp.Accuracy
                                   + "\t" + Math.Round(gp.PlayerRating, 5)
                                   + "\t" + Math.Round(gp.ScenarioRating, 5);

                            datafile.WriteLine(line);
                        }

                        // [SC] clearing all gameplay
                        gameNode.Gameplay.Clear();
                    }

                    // [SC] resetting player data
                    List <PlayerNode> playerNodeList = twoA.AdaptationData.AdaptationList.First(p => p.AdaptationID.Equals(adaptID)).GameList.First(p => p.GameID.Equals(gameID)).PlayerData.PlayerList;
                    foreach (PlayerNode playerNode in playerNodeList)
                    {
                        playerNode.Rating      = 0.001;
                        playerNode.PlayCount   = 0;
                        playerNode.KFactor     = 0.0075;
                        playerNode.Uncertainty = 1.0;
                        playerNode.LastPlayed  = "2012-12-31T11:59:59";
                    }
                }
            }
        }