// Create a RepFR open-stim word list from a list of repetitions and counts, // and a list of candidate words. public static StimWordList Generate( RepCounts rep_cnts, List <string> input_words, bool do_stim, double top_percent_spaced = 0.2) { var shuffled = Shuffle(input_words); var repeats = new List <RepWordList>(); var singles = new RepWordList(); var shuf = new BoundedInt(shuffled.Count, "Words required exceeded input word list size."); foreach (var rc in rep_cnts) { if (rc.rep == 1) { for (int i = 0; i < rc.count; i++) { singles.Add(shuffled[shuf.i++]); } } else if (rc.rep > 1 && rc.count > 0) { var rep_words = new RepWordList(rc.rep); for (int i = 0; i < rc.count; i++) { rep_words.Add(shuffled[shuf.i++]); } repeats.Add(rep_words); } } return(Generate(repeats, singles, do_stim, top_percent_spaced)); }
public FRExperiment(InterfaceManager _manager) : base(_manager) { // Repetition specification: int[] repeats = manager.GetSetting("wordRepeats").ToObject <int[]>(); int[] counts = manager.GetSetting("wordCounts").ToObject <int[]>(); if (repeats.Length != counts.Length) { throw new Exception("Word Repeats and Counts not aligned"); } for (int i = 0; i < repeats.Length; i++) { if (rep_counts == null) { rep_counts = new RepCounts(repeats[i], counts[i]); } else { rep_counts = rep_counts.RepCnt(repeats[i], counts[i]); } } words_per_list = rep_counts.TotalWords(); unique_words_per_list = rep_counts.UniqueWords(); blank_words = new List <string>(Enumerable.Repeat(string.Empty, words_per_list)); string source_list = manager.fileManager.GetWordList(); source_words = new List <string>(); //skip line for csv header foreach (var line in File.ReadLines(source_list).Skip(1)) { source_words.Add(line); } // copy wordpool to session directory // TODO: we should just do a direct file copy... string path = System.IO.Path.Combine(manager.fileManager.SessionPath(), "wordpool.txt"); if (!System.IO.File.Exists(path)) { using (TextWriter tw = new StreamWriter(path)) { tw.WriteLine("word"); // header foreach (String s in source_words) { tw.WriteLine(s); } } } // load state if previously existing dynamic loadedState = LoadState((string)manager.GetSetting("participantCode"), (int)manager.GetSetting("session")); if (loadedState != null) { state = loadedState; currentSession = LoadSession((string)manager.GetSetting("participantCode"), (int)manager.GetSetting("session")); // log experiment resume manager.Do(new EventBase <string, Dictionary <string, object> >(manager.ReportEvent, "experiment resumed", null)); ReportEvent("experiment resume", null); state.listIndex++; } else { currentSession = GenerateSession(); state.listIndex = 0; } state.runIndex = 0; state.wordIndex = 0; state.mainLoopIndex = 0; state.micTestIndex = 0; stateMachine["Run"] = new List <Action> { DoIntroductionPrompt, DoIntroductionVideo, DoRepeatVideo, DoMicrophoneTest, DoRepeatMicTest, DoQuitorContinue, MainLoop, Quit }; stateMachine["MainLoop"] = new List <Action> { DoNextListPrompt, DoStartTrial, DoRest, DoCountdownVideo, DoEncodingDelay, DoEncoding, DistractorTimeout, DoDistractor, DoRecallPrompt, DoRecall, DoEndTrial }; stateMachine["MicrophoneTest"] = new List <Action> { DoMicTestPrompt, DoRecordTest, DoPlaybackTest }; Start(); // TODO: some of these functions could be re imagined with wrappers, where the // state machine has functions that take parameters and return functions, such // as using a single function for the 'repeatlast' state that takes a prompt // to show. This would separate experiment and state machine logic, so state // variables are incremented in wrappers rather than experiment functions. // It's not clear whether the reality of this improves clarity or reusability, // so I've defferred this. If it makes sense to do this or make more use of // wrapper functions that add state machine information, please do. Dictionary <string, object> data = new Dictionary <string, object>(); data.Add("session", (int)manager.GetSetting("session")); SendHostPCMessage("SESSION", data); Do(new EventBase(Run)); }