00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 #include "Component/ModelManager.H"
00039 #include "Image/Image.H"
00040 #include "Psycho/PsychoDisplay.H"
00041 #include "Psycho/EyeTrackerConfigurator.H"
00042 #include "Psycho/EyeTracker.H"
00043 #include "Psycho/PsychoOpts.H"
00044 #include "Component/EventLog.H"
00045 #include "Component/ComponentOpts.H"
00046 #include "Raster/Raster.H"
00047 #include "Util/MathFunctions.H"
00048 #include "Util/Types.H"
00049 #include "GameBoard/basic-graphics.H"
00050 #include <sys/types.h>
00051 #include <dirent.h>
00052 #include <errno.h>
00053 #include <vector>
00054 #include <string>
00055 #include <iostream>
00056 #include <SDL/SDL.h>
00057 #include <SDL/SDL_image.h>
00058 #include <stdio.h>
00059 #include <stdlib.h>
00060 #include <sstream>
00061 #include <time.h>
00062 #include "Image/DrawOps.H"
00063 #include "GameBoard/resize.h"
00064 #include <iostream>
00065 #include <fstream>
00066 #include <set>
00067 #include <algorithm>
00068
00069
00070 #ifndef INVT_HAVE_LIBSDL_IMAGE
00071 #include <cstdio>
00072 int main()
00073 {
00074 fprintf(stderr, "The SDL_image library must be installed to use this program\n");
00075 return 1;
00076 }
00077
00078 #else
00079
00080
00081
00082 using namespace std;
00083
00084
00085
00086 ModelManager manager("Psycho-Concurrent-Digit");
00087 nub::soft_ref<PsychoDisplay> d(new PsychoDisplay(manager));
00088 map<uint,uint> testMap ;
00089 map<string,string> argMap ;
00090 map<string,vector<SDL_Rect*>*> clipsmap;
00091
00092
00093
00094
00095 template <class T> std::string stringify(T i)
00096 {
00097 ostringstream o ;
00098 o << i ;
00099 return o.str();
00100 }
00101
00102
00103
00104
00105 bool itIsInThere(int x , vector<int> bag){
00106 for( uint i=0 ; i < bag.size(); i++ ){
00107 if(x == bag[i]) return true ;
00108 }
00109 return false ;
00110 }
00111
00112
00113
00114
00115 string digitMemorizationTask(uint l, int maxForDigit=10 ,float wp = 1.0f, float hp = 1.0f, int displayFrame = 10 , int delayFrame = 30 ){
00116 d->clearScreen() ;
00117 vector<int> pickedones = vector<int>() ;
00118 string test = string("") ;
00119 string tp = string("") ;
00120 int widthRange = (int)((float)(d->getWidth()) * wp);
00121 int heightRange = (int)((float)(d->getHeight()) * hp);
00122 int wMargin = (d->getWidth() - widthRange)/2 ;
00123 int hMargin = (d->getHeight() - heightRange) / 2 ;
00124 for(uint i = 0 ; i < l ; i++){
00125 int nd;
00126 do{ nd= rand()% maxForDigit ; }while(itIsInThere(nd,pickedones) && pickedones.size() < 11) ;
00127 pickedones.push_back(nd);
00128 tp = stringify(nd) ;
00129 test += tp ;
00130 }
00131
00132 int x = (rand()%widthRange) + wMargin;
00133 int y = (rand()%heightRange ) + hMargin ;
00134 d->displayText(test,Point2D<int>(x,y),PixRGB<byte>(0,0,0),PixRGB<byte>(128,128,128),true) ;
00135 d->waitFrames(displayFrame*l) ;
00136 d->clearScreen() ;
00137 return test ;
00138 }
00139
00140
00141
00142
00143
00144 void scramble(vector<string>& v){
00145 vector<string> tv = vector<string>() ;
00146 while(v.size()>0){
00147 tv.push_back(v[0]);
00148 v.erase(v.begin());
00149 }
00150 int i = 0 ;
00151 while(tv.size()>0){
00152 i = rand()%tv.size() ;
00153 v.push_back(tv[i]);
00154 tv.erase(tv.begin()+i);
00155 }
00156 }
00157
00158
00159
00160
00161
00162 SDL_Surface* getButtonImage(string label , PixRGB<byte> txtcolor=PixRGB<byte>(0,0,0) , PixRGB<byte> bgcolor=PixRGB<byte>(255,255,255) ,Point2D<int> size = Point2D<int>(100,100) ,PixRGB<byte> bordercolor=PixRGB<byte>(0,0,0) , int border=3){
00163 Image<PixRGB<byte> > textIm(d->getWidth(),d->getHeight(),ZEROS);
00164 textIm.clear(bgcolor);
00165 writeText(textIm, Point2D<int>((size.i - label.length()*10)/2,(size.j-20) /2),label.c_str(),txtcolor,bgcolor);
00166 SDL_Surface *surf = d->makeBlittableSurface(textIm , true);
00167 Uint32 bc = d->getUint32color(bordercolor);
00168 drawRectangle(surf,bc,0,0,size.i -1,size.j -1 ,border);
00169 SDL_Surface* blank =getABlankSurface(size.i , size.j);
00170 SDL_Rect clip;
00171 clip.x = 0 ;
00172 clip.y = 0 ;
00173 clip.w = size.i ;
00174 clip.h = size.j ;
00175 apply_surface(0,0,*surf,*blank,clip);
00176 dumpSurface(surf) ;
00177 return blank ;
00178 }
00179
00180
00181
00182
00183
00184
00185 SDL_Surface* getKeyPad(map<string , SDL_Rect>& buttmap){
00186 SDL_Surface* pad= getABlankSurface(d->getWidth()/4,d->getHeight()/3);
00187 SDL_Rect clip;
00188 clip.x=0;
00189 clip.y=0;
00190 clip.w= pad->w / 3 ;
00191 clip.h = pad->h / 4 ;
00192
00193 for( int i = 1 ; i < 10 ; i++){
00194 SDL_Surface* but = getButtonImage(stringify(i),PixRGB<byte>(0,0,0),PixRGB<byte>(255,255,255),Point2D<int>(pad->w / 3 , pad->h / 4),PixRGB<byte>(255, 98 , 25),3);
00195 SDL_Rect cl ;
00196 cl.x = ((i-1)%3)*(pad->w)/3 ; cl.y= ((i-1)/3)*((pad->h)/4) ;
00197 cl.w = clip.w ;
00198 cl.h = clip.h ;
00199 apply_surface( cl.x , cl.y ,*but,*pad,clip);
00200 buttmap[stringify(i)] = cl ;
00201 dumpSurface(but);
00202 }
00203 SDL_Rect cl1 ;
00204 cl1.x = 0 ; cl1.y= 3*((pad->h)/4) ;
00205 cl1.w = clip.w ;
00206 cl1.h = clip.h ;
00207 buttmap["z"] = cl1 ;
00208 SDL_Surface* but = getButtonImage(string("<-"),PixRGB<byte>(0,0,0),PixRGB<byte>(255,255,255),Point2D<int>(pad->w / 3 , pad->h / 4),PixRGB<byte>(255, 98 , 25),3);
00209 apply_surface(0, 3*((pad->h)/4),*but,*pad,clip);
00210 dumpSurface(but);
00211 SDL_Rect cl2 ;
00212 cl2.x = (pad->w)/3 ; cl2.y= 3*((pad->h)/4) ;
00213 cl2.w = clip.w ;
00214 cl2.h = clip.h ;
00215 buttmap["0"] = cl2 ;
00216 but = getButtonImage(string("0"),PixRGB<byte>(0,0,0),PixRGB<byte>(255,255,255),Point2D<int>(pad->w / 3 , pad->h / 4),PixRGB<byte>(255, 98 , 25),3);
00217 apply_surface((pad->w)/3, 3*((pad->h)/4),*but,*pad,clip);
00218 dumpSurface(but);
00219 SDL_Rect cl3 ;
00220 cl3.x = 2*(pad->w)/3 ; cl3.y= 3*((pad->h)/4) ;
00221 cl3.w = clip.w ;
00222 cl3.h = clip.h ;
00223 buttmap["o"] = cl3 ;
00224 but = getButtonImage(string("Ok"),PixRGB<byte>(0,0,0),PixRGB<byte>(255,255,255),Point2D<int>(pad->w / 3 , pad->h / 4),PixRGB<byte>(255, 98 , 25),3);
00225 apply_surface(2*(pad->w)/3, 3*((pad->h)/4),*but,*pad,clip);
00226 dumpSurface(but);
00227 return pad ;
00228 }
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238 string getPressedButtonCommand(map<string , SDL_Rect>& buttmap,Point2D<int> offset=Point2D<int>(0,0)){
00239 int quit = 0 ;
00240 string s ;
00241 SDL_Event event ;
00242 while( quit!=2 ){
00243 while( SDL_PollEvent( &event ) ) {
00244 if(event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT ){
00245 for( map<string , SDL_Rect>::iterator it = buttmap.begin() ; it!=buttmap.end() ; ++it){
00246 if(event.button.x >= (it->second).x + offset.i && event.button.x <= (it->second).x + (it->second).w + offset.i && event.button.y >= (it->second).y+ offset.j && event.button.y <= (it->second).y + (it->second).h + offset.j) {
00247 quit = 2 ;
00248 s = it->first ;
00249 break;
00250 }
00251
00252 }
00253 }
00254
00255 }
00256 }
00257 return s ;
00258
00259 }
00260
00261
00262
00263
00264
00265
00266
00267 string getDigitSequenceFromSubject(uint maxl = 7 ){
00268 d->showCursor(true) ;
00269
00270 map<string , SDL_Rect>* buttmap = new map<string , SDL_Rect>();
00271
00272 SDL_Surface * keypad = getKeyPad(*buttmap);
00273
00274 SDL_Rect offset ;
00275 offset.x = (d->getWidth() - keypad->w) /2;
00276 offset.y = (d-> getHeight() - keypad->h) /2;
00277
00278 d->displaySDLSurfacePatch(keypad , &offset,NULL , -2,false, true);
00279
00280 string p = string("") ;
00281
00282 string tp = string("");
00283
00284 while( tp.compare("o")!=0 ){
00285
00286 SDL_Surface* dp = getButtonImage(p ,PixRGB<byte>(195,60,12) ,PixRGB<byte>(255,255,255) ,Point2D<int>(d->getWidth()/6,d->getHeight() /15) ,PixRGB<byte>(0,25,180) , 4) ;
00287 SDL_Rect offs ; offs.x = (d->getWidth() - dp->w) /2 ; offs.y = d->getHeight()/6 ;
00288 d->displaySDLSurfacePatch(dp , &offs , NULL , -2 , false ,true ) ;
00289
00290 tp = getPressedButtonCommand(*buttmap,Point2D<int>(offset.x,offset.y)) ;
00291 dumpSurface(dp) ;
00292 if(tp.compare("z")==0 && p.size()>=0 ) {
00293 if (p.size()>0) p = p.substr(0,p.size()-1) ;
00294 }else{
00295 if(p.size() < maxl && tp.compare("o")!=0) {
00296 p +=tp ;
00297 }
00298
00299 }
00300
00301 }
00302 buttmap = 0 ;
00303 dumpSurface(keypad) ;
00304 d->clearScreen() ;
00305 return p ;
00306
00307 }
00308
00309
00310
00311
00312
00313
00314
00315 string ascSort(string st)
00316 {
00317 string res = "" ;
00318 vector<string> v = vector<string>();
00319 for(uint i = 0 ; i < st.size() ; i++) v.push_back(st.substr(i,1)) ;
00320
00321 std::sort(v.begin(), v.end());
00322
00323 for ( uint i = 0 ; i < v.size() ; i++ ){
00324 res += v[i] ;
00325 }
00326 return res;
00327 }
00328
00329
00330
00331
00332
00333 string desSort(string st)
00334 {
00335 string res = "" ;
00336 vector<string> v = vector<string>();
00337 for(uint i = 0 ; i < st.size() ; i++) v.push_back(st.substr(i,1)) ;
00338 std::sort(v.begin(), v.end());
00339 std::reverse(v.begin(), v.end());
00340 for ( uint i = 0 ; i < v.size() ; i++ ){
00341 res += v[i] ;
00342 }
00343 return res;
00344 }
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354 bool isAnswerCorrect(string test , string answer , int mode){
00355
00356 if(mode == 0 && answer.compare(test)==0) return true ;
00357
00358 if(mode == 1 && answer.compare(ascSort(test))==0) return true ;
00359
00360 if(mode == 2 && answer.compare(desSort(test))==0) return true ;
00361
00362 return false;
00363 }
00364
00365
00366
00367 int addArgument(const string st,const string delim="="){
00368 int i = st.find(delim) ;
00369 argMap[st.substr(0,i)] = st.substr(i+1);
00370
00371 return 0 ;
00372 }
00373
00374 std::string getArgumentValue(string arg){
00375 return argMap[arg] ;
00376 }
00377
00378 std::string getUsageComment(){
00379
00380 string com = string("\nlist of arguments : \n");
00381
00382 com += "\ndelay-interval=[>1]:[>1] (the interval for random delay after stroop task) {default=10}\n";
00383 com += "\nfixation-blink=[y/n] (show the blink for fixation after stroop task or no) {defaule y}\n";
00384 com += "\nlogfile=[logfilename.psy] {default = psycho-stroop-concurrent.psy}\n" ;
00385 com += "\nmemo=[a_string_without_white_space]\n";
00386 com += "\nmode=[1] {default = 1}\n";
00387 com += "\nstart-digit-size=[<1](number of words in the stroop task){default=6} \n" ;
00388 com += "\nmax-digit-size=[>6](the maximum digits that will be used for test){default=10} \n";
00389 com += "\naccuracy-threshold=[>0 and <1.0] (the threshold for accuracy){default=.85}\n" ;
00390 com += "\nsubject=[subject_name] \n" ;
00391 com += "\ntest-rounds=[>1] (number of tests for each string size) {default=10}\n";
00392 com += "\ndigit-onset=[>1] (number of frames that the digit will remain onset for each digit){default=10}\n";
00393 com += "\ndigit-offset=[>1](number of frames that between two consequent digit onset){default=30}\n";
00394 com += "\nwidth-range=[1..100](the percentage of the width of screen for showing the digits){default=100}\n";
00395 com += "\nheight-range=[1..100](the percentage of the height of screen for showing the digits){default=100}\n";
00396 return com ;
00397 }
00398
00399
00400 extern "C" int main(const int argc, char** argv)
00401 {
00402
00403 MYLOGVERB = LOG_INFO;
00404
00405 argMap["mode"] = "1" ;
00406 argMap["logfile"]="psycho-digit-concurrent.psy" ;
00407 argMap["start-digit-size"]="6" ;
00408 argMap["max-digit-size"]="10" ;
00409 argMap["accuracy-threshold"]=".85";
00410 argMap["test-rounds"]="10";
00411 argMap["delay-interval"]="60:160" ;
00412 argMap["subject"]="" ;
00413 argMap["memo"]="" ;
00414 argMap["fixation-blink"]="y" ;
00415 argMap["digit-onset"]="10" ;
00416 argMap["digit-offset"]="30" ;
00417 argMap["width-range"]="100" ;
00418 argMap["height-range"]="100" ;
00419
00420 manager.addSubComponent(d);
00421 nub::soft_ref<EventLog> el(new EventLog(manager));
00422 manager.addSubComponent(el);
00423 d->setEventLog(el);
00424
00425 if (manager.parseCommandLine(argc, argv,
00426 "at least one argument needed", 1, -1)==false){
00427 cout<<getUsageComment()<<endl;
00428 return(1);
00429 }
00430
00431 for(uint i = 0 ; i < manager.numExtraArgs() ; i++){
00432 addArgument(manager.getExtraArg(i),std::string("=")) ;
00433 }
00434
00435 manager.setOptionValString(&OPT_EventLogFileName, argMap["logfile"]);
00436
00437
00438
00439
00440 manager.start();
00441 for(map<string,string>::iterator it= argMap.begin(); it!= argMap.end() ; ++it) d->pushEvent("arg:"+ it->first+" value:"+it->second ) ;
00442
00443 d->clearScreen();
00444 d->displayISCANcalib();
00445 d->waitForMouseClick();
00446
00447
00448 d->displayText("Here the experiment starts! click to start!");
00449 d->waitForMouseClick();
00450 d->clearScreen();
00451
00452 int mode = atoi(argMap["mode"].c_str()) ;
00453 float accuracyThreshold = atof(argMap["accuracy-threshold"].c_str());
00454
00455
00456
00457 if(mode==1 || true){
00458 int numOfTests = atoi(argMap["test-rounds"].c_str()) ;
00459 int startStringSize = atoi(argMap["start-digit-size"].c_str()) ;
00460 int maxStringSize = atoi(argMap["max-digit-size"].c_str());
00461 string::size_type position = argMap["delay-interval"].find(":");
00462 int minDel = atoi(argMap["delay-interval"].substr(0,position).c_str()) ;
00463 int maxDel = atoi(argMap["delay-interval"].substr(position+1).c_str()) ;
00464 float wr = ((float)(atoi(argMap["width-range"].c_str())))/100.0f;
00465 float hr = ((float)(atoi(argMap["height-range"].c_str())))/100.0f;
00466 int onsetDel = atoi(argMap["digit-onset"].c_str()) ;
00467 int offsetDel = atoi(argMap["digit-offset"].c_str()) ;
00468 float accuracy=1.0f;
00469 int currentStringSize = startStringSize ;
00470 while(accuracy>accuracyThreshold && currentStringSize <= maxStringSize){
00471
00472 int correctCount = 0 ;
00473 for(int i = 0 ; i < numOfTests ; i++){
00474 d->pushEvent("**************************************") ;
00475 d->showCursor(true);
00476 d->displayText("click one of the mouse buttons to start!");
00477 d->waitForMouseClick() ;
00478 d->showCursor(false);
00479
00480 string testString ;
00481 testString = digitMemorizationTask(currentStringSize, 10 , wr , hr , onsetDel , offsetDel) ;
00482
00483 d->pushEvent("the memorization sequence is : "+testString) ;
00484 d->waitFrames((rand()%(maxDel - minDel)) +minDel);
00485 string answer = getDigitSequenceFromSubject(testString.size());
00486 bool af = false ;
00487 af = isAnswerCorrect(testString,answer,0);
00488 d->pushEvent("subject keyed : "+answer);
00489 if(af){
00490 d->pushEvent("answer was correct");
00491 correctCount++ ;
00492 }else{
00493 d->pushEvent("answer was incorrect");
00494 }
00495
00496 }
00497 accuracy = float(correctCount)/float(numOfTests);
00498 d->pushEvent("string size:" + stringify(currentStringSize)+" accuracy :"+stringify(accuracy));
00499 currentStringSize++ ;
00500
00501 }
00502 d->pushEvent("the appropriate test size :" + stringify((currentStringSize-1)));
00503 }
00504
00505
00506
00507 d->clearScreen();
00508 d->displayText("Experiment complete. Thank you!");
00509 d->waitForMouseClick();
00510
00511
00512 manager.stop();
00513
00514
00515
00516 return 0;
00517 }
00518
00519 #endif // INVT_HAVE_LIBSDL_IMAGE
00520