From 64b24cf17cd7d3f1e52b2ba0b05b477597b8846b Mon Sep 17 00:00:00 2001 From: cpicanco Date: Tue, 29 Nov 2016 01:31:03 -0300 Subject: [PATCH] fully implement prompts, real time report, and dumps --- cultural_matrix.lpi | 6 +++++- cultural_matrix.lpr | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------------------- form_matrixgame.pas | 59 ++++++++++++++++++++++++++++++----------------------------- units/csv_writer.pas | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ units/game_actors.pas | 62 ++++++++++++++++++++++++++++++++++++++++++++------------------ units/game_actors_point.pas | 14 +++++++------- units/game_control.pas | 356 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------------------------------------------------------------------------------------------------------------------------------------------- units/game_experiment.pas | 189 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------- units/game_file_methods.pas | 92 +++++++++----------------------------------------------------------------------------------- units/game_resources.pas | 6 +++++- units/string_methods.pas | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------- 11 files changed, 699 insertions(+), 404 deletions(-) create mode 100644 units/csv_writer.pas diff --git a/cultural_matrix.lpi b/cultural_matrix.lpi index b86008a..ef34a6d 100644 --- a/cultural_matrix.lpi +++ b/cultural_matrix.lpi @@ -55,7 +55,7 @@ - + @@ -117,6 +117,10 @@ + + + + diff --git a/cultural_matrix.lpr b/cultural_matrix.lpr index ec636ca..a9e4523 100644 --- a/cultural_matrix.lpr +++ b/cultural_matrix.lpr @@ -35,7 +35,9 @@ var I : integer; {$ENDIF} ID : TStringList; + ApplicationPath, F : string; + const PAdmin : array [0..3] of string = ('--admin','--adm','-admin','-adm'); PPlayer : array [0..3] of string = ('--player','--play','-player','-play'); @@ -43,50 +45,68 @@ const {$R *.res} + +{$IFDEF DEBUG} + function CreateDebugFoldersForPlayers:Boolean; + var + i : integer; + begin + Result := True; + for i := 0 to 2 do + begin + if Pos((PathDelim+'P'+IntToStr(i+1)+PathDelim), Application.ExeName) > 0 then + Break; + F := ApplicationPath+'P'+IntToStr(i+1); + WriteLn(F); + if ForceDirectoriesUTF8(F) then // ensure we have always the newer version for tests + begin + CopyFile(Application.ExeName,F+PathDelim+ApplicationName,[cffOverwriteFile]); + {$IFDEF LINUX} + FpChmod(F+PathDelim+ApplicationName,S_IRWXU); + {$ENDIF} + end + else Result := False; + end; + end; +{$ENDIF} + + function GetZMQNetworkID(var F:string):Boolean; + begin + Result := True; + ID := TStringList.Create; + if FileExists(F) then + try + ID.LoadFromFile(F); + F := Copy(ID.Text,0,Length(ID.Text)-2); + finally + ID.Free; + end + else + try + ID.Text := s_random(32); + ID.SaveToFile(F); + F := Copy(ID.Text,0,Length(ID.Text)-2); + except + on E: Exception do + begin + ID.Free; + {$IFDEF DEBUG} + ShowMessage(E.Message); + {$ENDIF} + Result := False; + end; + end; + end; + begin + ApplicationPath := ExtractFilePath(Application.ExeName); {$IFDEF DEBUG} - for i:= 0 to 2 do - begin - if Pos((PathDelim+'P'+IntToStr(i+1)+PathDelim), Application.ExeName) > 0 then - Break; - F := ExtractFilePath(Application.ExeName)+'P'+IntToStr(i+1); - WriteLn(F); - if ForceDirectoriesUTF8(F) then // ensure we have always the newer version for tests - begin - CopyFile(Application.ExeName,F+PathDelim+ApplicationName,[cffOverwriteFile]); - {$IFDEF LINUX} - FpChmod(F+PathDelim+ApplicationName,S_IRWXU); - {$ENDIF} - end - else Exit; - end; + if not CreateDebugFoldersForPlayers then Exit; {$ENDIF} Application.Initialize; - F := ExtractFilePath(Application.ExeName)+PathDelim+'id'; - ID := TStringList.Create; - if FileExists(F) then - try - ID.LoadFromFile(F); - F := Copy(ID.Text,0,Length(ID.Text)-2); - finally - ID.Free; - end - else - try - ID.Text := s_random(32); - ID.SaveToFile(F); - F := Copy(ID.Text,0,Length(ID.Text)-2); - except - on E: Exception do - begin - ID.Free; - {$IFDEF DEBUG} - ShowMessage(E.Message); - {$ENDIF} - Exit; - end; - end; - Application.CreateForm(TFormMatrixGame, FormMatrixGame); + F := ApplicationPath+PathDelim+'id'; + if not GetZMQNetworkID(F) then Exit; + Application.CreateForm(TFormMatrixGame, FormMatrixGame); FormMatrixGame.SetID(F); if Paramcount > 0 then diff --git a/form_matrixgame.pas b/form_matrixgame.pas index e64f132..47c93b4 100644 --- a/form_matrixgame.pas +++ b/form_matrixgame.pas @@ -72,14 +72,14 @@ type procedure ButtonExpStartClick(Sender: TObject); procedure ChatMemoSendKeyPress(Sender: TObject; var Key: char); procedure FormActivate(Sender: TObject); - procedure PopupNotifierClose(Sender: TObject; var CloseAction: TCloseAction - ); + procedure PopupNotifierClose(Sender: TObject; var CloseAction: TCloseAction); procedure StringGridMatrixClick(Sender: TObject); procedure StringGridMatrixDrawCell(Sender: TObject; aCol, aRow: integer; aRect: TRect; aState: TGridDrawState); procedure TimerTimer(Sender: TObject); private FGameControl : TGameControl; + FAppPath, FID: string; public procedure SetID(S : string); @@ -106,7 +106,6 @@ procedure TFormMatrixGame.StringGridMatrixDrawCell(Sender: TObject; aCol, aRow: aRect: TRect; aState: TGridDrawState); var OldCanvas: TCanvas; - RowBase : integer; procedure SaveOldCanvas; begin @@ -157,8 +156,8 @@ var TStringGrid(Sender).Canvas.Rectangle(aRect); if Assigned(FGameControl) then if FGameControl.MustDrawDots then - if (Odd(aRow + RowBase) and not Odd(aCol)) or - (not Odd(aRow + RowBase) and Odd(aCol)) then + if (Odd(aRow + FGameControl.RowBase) and not Odd(aCol)) or + (not Odd(aRow + FGameControl.RowBase) and Odd(aCol)) then DrawDots; end; //function GetTextX(S : String): Longint; @@ -167,15 +166,14 @@ var //end; begin - if Assigned(FGameControl) then - RowBase:=FGameControl.RowBase; + if not Assigned(FGameControl) then Exit; SaveOldCanvas; try //if (aRow >= RowBase) and (aCol = 10) then // DrawLines(clWhite); - if (aCol <> 0) and (aRow > (RowBase-1)) then + if (aCol <> 0) and (aRow > (FGameControl.RowBase-1)) then begin - DrawLines(GetRowColor(aRow,RowBase)); + DrawLines(GetRowColor(aRow,FGameControl.RowBase)); if (gdSelected in aState) and (goRowSelect in TStringGrid(Sender).Options)then begin @@ -226,13 +224,13 @@ procedure TFormMatrixGame.SetGameActor(AValue: TGameActor); procedure SetZMQAdmin; begin - FGameControl := TGameControl.Create(TZMQAdmin.Create(Self,FID)); + FGameControl := TGameControl.Create(TZMQAdmin.Create(Self,FID),ExtractFilePath(Application.ExeName)); GBAdmin.Visible:= True; end; procedure SetZMQPlayer; begin - FGameControl := TGameControl.Create(TZMQPlayer.Create(Self,FID)); + FGameControl := TGameControl.Create(TZMQPlayer.Create(Self,FID),ExtractFilePath(Application.ExeName)); //StringGridMatrix.Enabled := True; end; @@ -257,24 +255,27 @@ end; procedure TFormMatrixGame.FormActivate(Sender: TObject); begin - FormChooseActor := TFormChooseActor.Create(Self); - FormChooseActor.Style := '.Arrived'; - try - if FormChooseActor.ShowModal = 1 then - begin - case FormChooseActor.GameActor of - gaAdmin:FormMatrixGame.SetGameActor(gaAdmin); - gaPlayer: FormMatrixGame.SetGameActor(gaPlayer); - gaWatcher: FormMatrixGame.SetGameActor(gaWatcher); - end; - StringGridMatrix.ClearSelections; - StringGridMatrix.FocusRectVisible := False; - FGameControl.SetMatrix; - end - else Close; - finally - FormChooseActor.Free; - end; + if not Assigned(FGameControl) then + begin + FormChooseActor := TFormChooseActor.Create(Self); + FormChooseActor.Style := '.Arrived'; + try + if FormChooseActor.ShowModal = 1 then + begin + case FormChooseActor.GameActor of + gaAdmin:FormMatrixGame.SetGameActor(gaAdmin); + gaPlayer: FormMatrixGame.SetGameActor(gaPlayer); + gaWatcher: FormMatrixGame.SetGameActor(gaWatcher); + end; + StringGridMatrix.ClearSelections; + StringGridMatrix.FocusRectVisible := False; + FGameControl.SetMatrix; + end + else Close; + finally + FormChooseActor.Free; + end; + end; end; procedure TFormMatrixGame.PopupNotifierClose(Sender: TObject; diff --git a/units/csv_writer.pas b/units/csv_writer.pas new file mode 100644 index 0000000..9c0403a --- /dev/null +++ b/units/csv_writer.pas @@ -0,0 +1,98 @@ +unit csv_writer; + +{$mode objfpc}{$H+} + +interface + +uses SysUtils, Classes, LazFileUtils; + +type + + { TCSVWriter } + + TCSVWriter = class(TComponent) + private + FFileName: string; + FFile: TextFile; + FSessionNumber: integer; + procedure Close; + procedure UpdateFileName(ANewFileName : string); + function OpenNoOverride(AFilename : string):string; + public + constructor Create(AOwner: TComponent; AFileName: String); reintroduce; + destructor Destroy; override; + procedure Write(AData: array of const); + end; + + + + +implementation + +{ TCSVWriter } + +procedure TCSVWriter.Close; +begin + if FFilename <> '' then + if TextRec(FFile).Mode = 55218 then // file is opened read/write + begin + CloseFile(FFile); + end +end; + +procedure TCSVWriter.UpdateFileName(ANewFileName: string); +begin + if (ANewFileName = '') or (ANewFileName = FFilename) then Exit; + Close; + FFileName := OpenNoOverride(ANewFileName); +end; + +function TCSVWriter.OpenNoOverride(AFilename: string): string; +var + i : Integer; + FilePath, LExtension: string; +begin + if AFileName <> '' then + begin + ForceDirectoriesUTF8(ExtractFilePath(AFilename)); + FilePath := ExtractFilePath(AFilename); + LExtension := ExtractFileExt(AFilename); + i := 0; + + // ensure to never override an existing file + while FileExistsUTF8(AFilename) do begin + Inc(i); + AFilename := FilePath + StringOfChar(#48, 3 - Length(IntToStr(i))) + IntToStr(i) + LExtension; + end; + + FSessionNumber := i; + + // as override is impossible, don't mind about an Assign/Rewrite conditional + AssignFile(FFile, AFilename); + Rewrite(FFile); + {$ifdef DEBUG} + WriteLn(FFile, mt_Debug + 'Saving data to:' + AFilename ); + {$endif} + Result := AFilename; + end; +end; + +constructor TCSVWriter.Create(AOwner: TComponent; AFileName: String); +begin + inherited Create(AOwner); + FFilename := OpenNoOverride(AFilename); +end; + +destructor TCSVWriter.Destroy; +begin + Close; + inherited Destroy; +end; + +procedure TCSVWriter.Write(AData: array of const); +begin + +end; + +end. + diff --git a/units/game_actors.pas b/units/game_actors.pas index dbfeea0..329b70e 100644 --- a/units/game_actors.pas +++ b/units/game_actors.pas @@ -106,6 +106,7 @@ type destructor Destroy;override; function AsString(AID :string): string; function GenerateMessage(ForGroup: Boolean):string; + procedure Clean; virtual; procedure PresentMessage; procedure PresentPoints; property ShouldPublishMessage : Boolean read GetShouldPublishMessage; @@ -123,6 +124,7 @@ type FMeta : Boolean; //True: Consequence occurs OnEndTurn, False: Consequence occurs OnEndCycle FConsequence : TConsequence; FCriteria : TCriteria; + FName: string; FOnCriteria: TNotifyEvent; function RowMod(R:TGameRow):TGameRow; procedure CriteriaEvent; @@ -131,11 +133,14 @@ type function CriteriaString : string; function ResponseMeetsCriteriaI(R : TGameRow; C : TGameColor):Boolean; // Does response meets operant criteria? function ResponseMeetsCriteriaG(Players : TPlayers):Boolean; + function ConsequenceFromPlayerID(AID:string):string; + procedure Clean; property OnCriteria : TNotifyEvent read FOnCriteria write FOncriteria; property Fired : Boolean read FFired; property Consequence : TConsequence read FConsequence; property Criteria : TCriteria read FCriteria; property Meta : Boolean read FMeta; + property ContingencyName : string read FName write FName; end; { TContingencies } @@ -155,8 +160,9 @@ type public constructor Create(AOwner:TComponent; APStyle:TPromptStyle; APTarget : TContingencies; AMessage:string);reintroduce; function ResponsesCount : integer; - procedure AppendResponse(AID,R:string); function AsString: TStringList; overload; + procedure AppendResponse(AID,R:string); + procedure Clean;override; property Question: string read FPromptMessage; property PromptResult:string read FResult; @@ -398,6 +404,17 @@ begin // All -> (Diff,Equal,Even, Odd) or not all CriteriaEvent; end; +function TContingency.ConsequenceFromPlayerID(AID: string): string; +begin + Result := Consequence.ConsequenseByPlayerID.Values[AID]; +end; + +procedure TContingency.Clean; +begin + FFired := False; + Consequence.Clean; +end; + { TPrompt } @@ -426,6 +443,12 @@ begin FResponses[High(FResponses)] := AID+'|'+R+'|'; end; +procedure TPrompt.Clean; +begin + //inherited Clean; + FResponses := nil; +end; + function TPrompt.AsString: TStringList; var j,i : integer; @@ -454,8 +477,8 @@ var if (gscB in LCsqStyle) and (gsBasA in FPromptStyle) then begin - LCsqStyle += [gscB]; - LCsqStyle -= [gscA]; + LCsqStyle += [gscA]; + LCsqStyle -= [gscB]; end; if IsMeta then @@ -471,17 +494,22 @@ var ExtractDelimited(5,LConsequence, ['|']); end; begin + Result := TStringList.Create; // to do, sanitize FPromptStyle first Pts:= 0; if (gsAll in FPromptStyle) and (gsYes in FPromptStyle) then if AllPlayersClickedYes then for i := 0 to Length(FPromptTargets)-1 do - for j := 0 to FPromptTargets[i].Consequence.ConsequenseByPlayerID.Count do + for j := 0 to FPromptTargets[i].Consequence.ConsequenseByPlayerID.Count-1 do begin LID := FPromptTargets[i].Consequence.ConsequenseByPlayerID.Names[j]; LConsequence := FPromptTargets[i].Consequence.ConsequenseByPlayerID.Values[LID]; LCsqStyle := GetConsequenceStylesFromString(ExtractDelimited(2,LConsequence, ['|'])); + // TODO: should BasA revert appendices? right now reverting points only + //LAppendiceSingular:= + //LAppendicePlural:= + if gsContingency in FPromptStyle then if (FPromptTargets[i].Fired) and (not FPromptTargets[i].Meta) then if (gscA in LCsqStyle) or (gscB in LCsqStyle) then @@ -493,7 +521,7 @@ begin if gscG in LCsqStyle then ApplyPointsConditions(True); - Result := TStringList.Create; + Result.Add(LConsequence); end; @@ -541,7 +569,7 @@ begin FMessage := TPopupNotifier.Create(Self); FTimer := TTimer.Create(Self); FTimer.Enabled:=False; - FTimer.Interval:=6000; + FTimer.Interval:=10000; FTimer.OnTimer:=@SelfDestroy; FConsequenceByPlayerID := TStringList.Create; end; @@ -568,27 +596,25 @@ begin FMessage.Text := Result; end; +procedure TConsequence.Clean; +begin + FConsequenceByPlayerID.Clear; +end; + procedure TConsequence.PresentMessage; var PopUpPos : TPoint; begin + PopUpPos.X := FormMatrixGame.GBIndividualAB.Left; if gscA in FStyle then - begin - PopUpPos.X := FormMatrixGame.GBIndividualAB.Left-110; - PopUpPos.Y := FormMatrixGame.GBIndividualAB.Top+FormMatrixGame.GBIndividual.Height-10; - end; + PopUpPos.Y := FormMatrixGame.GBIndividualAB.Top+FormMatrixGame.GBIndividualAB.Height-20; if gscB in FStyle then - begin - PopUpPos.X := FormMatrixGame.GBIndividualAB.Left+110; - PopUpPos.Y := FormMatrixGame.GBIndividualAB.Top+FormMatrixGame.GBIndividual.Height-10; - end; + PopUpPos.Y := FormMatrixGame.GBIndividualAB.Top+FormMatrixGame.GBIndividualAB.Height+150; if gscG in FStyle then - begin - PopUpPos.X := FormMatrixGame.GBIndividualAB.Left-110; - PopUpPos.Y := FormMatrixGame.GBIndividualAB.Top+FormMatrixGame.GBIndividual.Height+100; - end; + PopUpPos.Y := FormMatrixGame.GBIndividualAB.Top+FormMatrixGame.GBIndividualAB.Height+300; + PopUpPos := FormMatrixGame.ClientToScreen(PopUpPos); FMessage.Color:=clTeal; FMessage.Title:=''; diff --git a/units/game_actors_point.pas b/units/game_actors_point.pas index d516f24..aa2be19 100644 --- a/units/game_actors_point.pas +++ b/units/game_actors_point.pas @@ -73,7 +73,7 @@ end; function TGamePoint.GetResultAsString: string; begin - Result := IntToStr(FResult); + Result := IntToStr(abs(FResult)); end; constructor TGamePoint.Create(AOwner: TComponent; AValue: integer); @@ -111,7 +111,7 @@ begin case FResult of -MaxInt..-2: Result += ' produziram a perda de '+Self.AsString+ ' pontos para o grupo'; -1 : Result += ' produziram a perda de 1 ponto para o grupo'; - 0 : Result += ' pontos do grupo não foram produzidos nem perdidos'; + 0 : Result += ' não produziram nem perderam pontos para o grupo'; 1 : Result += ' produziram 1 ponto para o grupo'; 2..MaxInt: Result += ' produziram '+Self.AsString+' pontos para o grupo' end; @@ -119,11 +119,11 @@ begin else begin case FResult of - -MaxInt..-2: Result += ' produziram a perda de '+Self.AsString+ ' ' + AAppendicePlural; - -1 : Result += ' produziram a perda de 1'+ ' ' + AAppendiceSingular; - 0 : Result += ' não produziram ' + AAppendicePlural; + -MaxInt..-2: Result += ' produziram a perda de ' + Self.AsString + ' ' + AAppendicePlural; + -1 : Result += ' produziram a perda de 1 ' + AAppendiceSingular; + 0 : Result += ' não produziram nem perderam ' + AAppendicePlural; 1 : Result += ' produziram 1 ' + AAppendiceSingular; - 2..MaxInt: Result += ' produziram '+Self.AsString+ ' ' + AAppendicePlural; + 2..MaxInt: Result += ' produziram ' + Self.AsString + ' ' + AAppendicePlural; end; end; end @@ -148,7 +148,7 @@ begin begin case FResult of -MaxInt..-2: Result += ' perdeu '+Self.AsString+ ' ' + AAppendicePlural; - -1 : Result += ' ponto 1 ' + AAppendiceSingular; + -1 : Result += ' perdeu 1 ' + AAppendiceSingular; 0 : Result += ' não perdeu nem ganhou ' + AAppendicePlural; 1 : Result += ' ganhou 1 ' + AAppendiceSingular; 2..MaxInt: Result += ' ganhou '+Self.AsString+ ' ' + AAppendicePlural; diff --git a/units/game_control.pas b/units/game_control.pas index 349abf3..a9d9d06 100644 --- a/units/game_control.pas +++ b/units/game_control.pas @@ -54,10 +54,12 @@ type private function AskQuestion(AQuestion:string):UTF8string; procedure ShowPopUp(AText:string); + procedure ShowConsequenceMessage(AID,S:string;ForGroup:Boolean); procedure DisableConfirmationButton; procedure CleanMatrix(AEnabled : Boolean); procedure EnablePlayerMatrix(AID:UTF8string; ATurn:integer; AEnabled:Boolean); private + function ShouldStartExperiment: Boolean; function ShouldEndCycle : Boolean; function ShouldAskQuestion : Boolean; @@ -71,7 +73,7 @@ type procedure EndExperiment(Sender: TObject); procedure StartExperiment; public - constructor Create(AOwner : TComponent);override; + constructor Create(AOwner : TComponent;AppPath:string);overload; destructor Destroy; override; procedure SetMatrix; procedure SendRequest(ARequest : UTF8string); @@ -145,15 +147,14 @@ begin Result := FExperiment.PlayersCount = FExperiment.Condition[FExperiment.CurrentCondition].Turn.Value; end; -function TGameControl.ShouldEndCycle: Boolean; +function TGameControl.ShouldEndCycle: Boolean; //CAUTION: MUST BE CALLED BEFORE EXPERIMENT.NEXTCYCLE begin Result := FExperiment.Condition[FExperiment.CurrentCondition].Turn.Count = FExperiment.Condition[FExperiment.CurrentCondition].Turn.Value-1; end; -function TGameControl.ShouldAskQuestion: Boolean; // end cycle, restart alias +function TGameControl.ShouldAskQuestion: Boolean; begin - // TODO: prompt only when an odd row was selected - Result := ShouldEndCycle and FExperiment.Condition[FExperiment.CurrentCondition].Contingencies[3].Fired; + Result := Assigned(FExperiment.Condition[FExperiment.CurrentCondition].Prompt) and FExperiment.Condition[FExperiment.CurrentCondition].Contingencies[3].Fired; end; procedure TGameControl.KickPlayer(AID: string); @@ -169,24 +170,11 @@ begin end; procedure TGameControl.NextCycle(Sender: TObject); -var - i, - LCount : integer; - LConsequences : string; begin - // prompt question to all players FormMatrixGame.LabelExpCountCycle.Caption:=IntToStr(FExperiment.Condition[FExperiment.CurrentCondition].Cycles.Count+1); {$IFDEF DEBUG} WriteLn('cycle:>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>'); {$ENDIF} - - - //P := FExperiment.PlayerFromID[Self.ID]; - LConsequences := FExperiment.ConsequenceStringFromChoices; - LCount := WordCount(LConsequences,['+']); - if LCount > 0 then - for i := 1 to LCount do - FZMQActor.SendMessage([K_CYCLES,ExtractDelimited(i,LConsequences,['+'])]); // as string generates the pts result end; procedure TGameControl.NextLineage(Sender: TObject); @@ -229,7 +217,7 @@ end; procedure TGameControl.StartExperiment; begin // all players arrived, lets begin - FExperiment.State:=xsRunning; + FExperiment.Play; // wait some time, we just sent a message earlier Sleep(5); @@ -445,6 +433,21 @@ begin FormMatrixGame.Timer.Enabled:=True; end; +procedure TGameControl.ShowConsequenceMessage(AID, S: string; ForGroup: Boolean); +var + LConsequence : TConsequence; +begin + LConsequence := TConsequence.Create(nil,S); + LConsequence.GenerateMessage(ForGroup); + LConsequence.PresentMessage; + if ForGroup then + LConsequence.PresentPoints + else + if Self.ID = AID then + LConsequence.PresentPoints; + +end; + procedure TGameControl.DisableConfirmationButton; begin FormMatrixGame.StringGridMatrix.Enabled:= False; @@ -467,7 +470,7 @@ begin CleanMatrix(AEnabled); end; -constructor TGameControl.Create(AOwner: TComponent); +constructor TGameControl.Create(AOwner: TComponent;AppPath:string); begin FZMQActor := TZMQActor(AOwner); inherited Create(FZMQActor.Owner); @@ -487,8 +490,11 @@ begin RowBase:= 0; MustDrawDots:=False; MustDrawDotsClear:=False; - - FExperiment := TExperiment.Create(FZMQActor.Owner); + case FActor of + gaAdmin:FExperiment := TExperiment.Create(FZMQActor.Owner,AppPath); + gaPlayer:FExperiment := TExperiment.Create(FZMQActor.Owner); + gaWatcher:FExperiment := TExperiment.Create(FZMQActor.Owner); + end; FExperiment.State:=xsWaiting; FExperiment.OnEndTurn := @NextTurn; FExperiment.OnEndCycle := @NextCycle; @@ -633,8 +639,21 @@ procedure TGameControl.ReceiveMessage(AMessage: TStringList); end; end; + procedure ShowQuestion; + begin + case FActor of + gaPlayer:FZMQActor.Request([ + FZMQActor.ID + , ' ' + , GA_PLAYER+K_QUESTION + , AskQuestion(AMessage[1]) + ]); + end; + end; + procedure ReceiveChoice; - var P : TPlayer; + var + P : TPlayer; begin P := FExperiment.PlayerFromID[AMessage[1]]; @@ -648,6 +667,8 @@ procedure TGameControl.ReceiveMessage(AMessage: TStringList); case FActor of gaPlayer:begin + + // last turn// end cycle if P.Turn = FExperiment.PlayersCount-1 then begin // update next turn @@ -657,16 +678,20 @@ procedure TGameControl.ReceiveMessage(AMessage: TStringList); FExperiment.Player[Self.ID] := P; end; - //CleanMatrix; CleanMatrix(False); + // no wait turns - EnablePlayerMatrix(Self.ID,0, True); + // if should continue then + //if StrToBool(AMessage[6]) then + //EnablePlayerMatrix(Self.ID,0, True) + // wait for server Exit; end; + // else if Self.ID = P.ID then begin // update confirmation button @@ -697,20 +722,21 @@ procedure TGameControl.ReceiveMessage(AMessage: TStringList); end; end; - procedure OnEndCycle; - var - LConsequence : TConsequence; - begin - case FActor of - gaPlayer: - begin - LConsequence := TConsequence.Create(nil,AMessage[1]); - LConsequence.GenerateMessage(True); - LConsequence.PresentPoints; - LConsequence.PresentMessage; - end; - end; - end; + //procedure OnEndCycle; + //var + // LConsequence : TConsequence; + //begin + // case FActor of + // gaPlayer: + // begin + // LConsequence := TConsequence.Create(nil,AMessage[1]); + // LConsequence.GenerateMessage(True); + // + // LConsequence.PresentPoints; + // LConsequence.PresentMessage; + // end; + // end; + //end; procedure ReceiveChat; begin @@ -736,80 +762,55 @@ procedure TGameControl.ReceiveMessage(AMessage: TStringList); end; end; - procedure ShowQuestion; + procedure QuestionMessages; + var + i : integer; + MID : string; begin case FActor of - gaPlayer:FZMQActor.Request([ - FZMQActor.ID - , ' ' - , GA_PLAYER+K_QUESTION - , AskQuestion(AMessage[1]) - ]); + gaPlayer:begin + if AMessage.Count > 1 then + begin + for i := 1 to AMessage.Count -1 do + begin + MID := ExtractDelimited(1,AMessage[i],['+']); + ShowConsequenceMessage(MID, ExtractDelimited(2,AMessage[i],['+']),MID = 'M'); + + {$IFDEF DEBUG} + WriteLn('A Prompt consequence should have shown.'); + {$ENDIF} + end; + end; + EnablePlayerMatrix(Self.ID,0, True); + WriteLn('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>'); + end; end; end; -// -// procedure ResumeActor; -// begin -// case FActor of -// gaPlayer:begin -// -// end; -// gaAdmin:begin -// -// end; -// end; -// end; - - - //procedure QuestionMessages; - //var - // LConsequence : TConsequence; - // i : integer; - // MID : string; - //begin - // case FActor of - // // AMessage[i] := - // // S + '+' + - // // IntToStr(Pts) +'|'+ - // // GetConsequenceStylesString(LCsqStyle) +'|'+ - // // ExtractDelimited(3,LConsequence, ['|']) +'|'+ - // // ExtractDelimited(4,LConsequence, ['|']) +'|'+ - // // ExtractDelimited(5,LConsequence, ['|']); - // gaPlayer:begin - // if AMessage.Count > 1 then - // begin - // for i := 1 to AMessage.Count -1 do - // begin - // MID := ExtractDelimited(1,AMessage[i],['+']); - // if (MID = 'M') or (MID = Self.ID) then - // begin - // LConsequence := TConsequence.Create(FormMatrixGame,ExtractDelimited(2,AMessage[i],['+'])); - // //LConsequence.PlayerNicname := P.Nicname; - // ShowPopUp(LConsequence.PointMessage(MID = 'M')); - // while FormMatrixGame.PopupNotifier.Visible do - // Application.ProcessMessages; + + + // procedure ResumeActor; + // begin + // case FActor of + // gaPlayer:begin // - // {$IFDEF DEBUG} - // WriteLn('A consequence should have shown.'); - // {$ENDIF} - // end; - // end; - // end; + // end; + // gaAdmin:begin + // + // end; // end; // end; - //end; - begin if MHas(K_ARRIVED) then ReceiveActor; if MHas(K_CHAT_M) then ReceiveChat; if MHas(K_CHOICE) then ReceiveChoice; - if MHas(K_MESSAGE) then ShowPopUp(AMessage[1]); + if MHas(K_MESSAGE) then ShowConsequenceMessage(AMessage[1],AMessage[2],StrToBool(AMessage[3])); if MHas(K_KICK) then SayGoodBye; if MHas(K_START) then NotifyPlayers; - if MHas(K_CYCLES) then OnEndCycle; - //if MHas(K_QUESTION) then ShowQuestion; - //if MHas(K_QMESSAGE) then QuestionMessages; + if MHas(K_QUESTION) then ShowQuestion; + if MHAS(K_RESUME) then EnablePlayerMatrix(Self.ID,0, True); + //if MHas(K_CYCLES) then OnEndCycle; + if MHas(K_QMESSAGE) then QuestionMessages; end; // Here FActor is garanted to be a TZMQAdmin @@ -900,11 +901,14 @@ procedure TGameControl.ReceiveRequest(var ARequest: TStringList); end; procedure ValidateChoice; - var P : TPlayer; - S : string; + var + LConsequences : string; + P : TPlayer; + S : string; + LEndCycle : Boolean; begin {$IFDEF DEBUG} - WriteLn('Count:>>>>>>>>>>>>>>>>>>>>>>>>>>>',FExperiment.Condition[FExperiment.CurrentCondition].Turn.Count, '<', FExperiment.Condition[FExperiment.CurrentCondition].Turn.Value); + WriteLn('Count:',FExperiment.Condition[FExperiment.CurrentCondition].Turn.Count, '<', FExperiment.Condition[FExperiment.CurrentCondition].Turn.Value); {$ENDIF} P := FExperiment.PlayerFromID[ARequest[0]]; P.Choice.Row:= GetRowFromString(ARequest[3]); // row @@ -919,65 +923,70 @@ procedure TGameControl.ReceiveRequest(var ARequest: TStringList); if Pos('$NICNAME',S) > 0 then S := ReplaceStr(S,'$NICNAME',P.Nicname); - ARequest.Append(S); // update turn + LEndCycle:=ShouldEndCycle; P.Turn := FExperiment.NextTurn; FExperiment.Player[P.ID] := P; - // broadcast choice - FZMQActor.SendMessage([K_CHOICE,P.ID,ARequest[3],ARequest[4],IntToStr(P.Turn)]); - - if ShouldEndCycle then + // append results + ARequest.Append(IntToStr(P.Turn)); + ARequest.Append(S); + if LEndCycle then begin - while FormMatrixGame.PopupNotifier.Visible do - Application.ProcessMessages; - - //if ShouldAskQuestion then // TODO: prompt only when an odd row was selected - // begin - // P.Turn := 0; - // FZMQActor.SendMessage([K_QUESTION,FExperiment.Condition[FExperiment.CurrentCondition].Prompt.Question]); - // end; + LConsequences := FExperiment.ConsequenceStringFromChoices;// AsString generates the pts result + ARequest.Append(LConsequences); + + if ShouldAskQuestion then // TODO: prompt only when an odd row was selected + ARequest.Append(FExperiment.Condition[FExperiment.CurrentCondition].Prompt.Question) + else + FExperiment.Clean; end; end; - //procedure ValidateQuestionResponse; - //var - // P : TPlayer; - // M : array of UTF8string; - // i : integer; - // LPromptConsequences : TStringList; - //begin - // P := FExperiment.PlayerFromID[ARequest[0]]; - // ARequest[2] := K_QUESTION+K_ARRIVED; - // - // // append response of each player - // FExperiment.Condition[FExperiment.CurrentCondition].Prompt.AppendResponse(P.ID,ARequest[3]); - // - // // return to experiment and present the prompt consequence, if any - // if FExperiment.Condition[FExperiment.CurrentCondition].Prompt.ResponsesCount = Experiment.PlayersCount then - // begin - // // M setup - // - // - // // generate messages - // LPromptConsequences := FExperiment.Condition[FExperiment.CurrentCondition].Prompt.AsString; - // if LPromptConsequences.Count > 0 then - // begin - // SetLength(M, 1+LPromptConsequences.Count); - // M[0] := GA_ADMIN+K_QUESTION+K_QMESSAGE; - // for i := 0 to LPromptConsequences.Count -1 do - // M[i+1] := LPromptConsequences[i] - // end; - // - // // send identified messages; each player takes only its own message and ignore the rest - // FZMQActor.SendMessage(M); - // end; - //end; + procedure ValidateQuestionResponse; + var + P : TPlayer; + M : array of UTF8string; + i : integer; + LPromptConsequences : TStringList; + begin + P := FExperiment.PlayerFromID[ARequest[0]]; + ARequest[2] := K_QUESTION+K_ARRIVED; + + // append response of each player + FExperiment.Condition[FExperiment.CurrentCondition].Prompt.AppendResponse(P.ID,ARequest[3]); + + // return to experiment and present the prompt consequence, if any + if FExperiment.Condition[FExperiment.CurrentCondition].Prompt.ResponsesCount = FExperiment.PlayersCount then + begin + + // generate messages + LPromptConsequences := FExperiment.Condition[FExperiment.CurrentCondition].Prompt.AsString; + SetLength(M, 1+LPromptConsequences.Count); + M[0] := K_QMESSAGE; + if LPromptConsequences.Count > 0 then + begin + for i := 0 to LPromptConsequences.Count-1 do + if Pos('$NICNAME',LPromptConsequences[i]) > 0 then + begin + P := FExperiment.PlayerFromID[ExtractDelimited(1,LPromptConsequences[i],['+'])]; + LPromptConsequences[i] := ReplaceStr(LPromptConsequences[i],'$NICNAME', P.Nicname); + end; + for i := 0 to LPromptConsequences.Count -1 do + M[i+1] := LPromptConsequences[i]; + end + else; + + // send identified messages; each player takes only its own message and ignore the rest + FZMQActor.SendMessage(M); + FExperiment.Clean; + end; + end; begin if MHas(K_LOGIN) then ReplyLoginRequest; if MHas(K_CHOICE) then ValidateChoice; - //if MHas(K_QUESTION) then ValidateQuestionResponse; + if MHas(K_QUESTION) then ValidateQuestionResponse; end; // Here FActor is garanted to be a TZMQPlayer, reply by: @@ -1020,31 +1029,56 @@ procedure TGameControl.ReceiveReply(AReply: TStringList); LConsequence : TConsequence; LCount, i : integer; - M : string; //P : TPlayer; begin if Self.ID = AReply[0] then begin //P := FExperiment.PlayerFromID[Self.ID]; - LCount := WordCount(AReply[5],['+']); {$IFDEF DEBUG} WriteLn('LCount:',LCount); {$ENDIF} + FZMQActor.SendMessage([K_CHOICE,AReply[0],AReply[3],AReply[4],AReply[5]]); + + LCount := WordCount(AReply[6],['+']); if LCount > 0 then for i := 1 to LCount do begin - LConsequence := TConsequence.Create(nil,ExtractDelimited(i,AReply[5],['+'])); - M := LConsequence.GenerateMessage(False); + LConsequence := TConsequence.Create(nil,ExtractDelimited(i,AReply[6],['+'])); + LConsequence.GenerateMessage(False); if LConsequence.ShouldPublishMessage then - FZMQActor.SendMessage([K_MESSAGE,M]) + FZMQActor.SendMessage([K_MESSAGE,Self.ID,ExtractDelimited(i,AReply[6],['+']),BoolToStr(False)]) else - LConsequence.PresentMessage; - LConsequence.PresentPoints; + begin + LConsequence.PresentMessage; + LConsequence.PresentPoints; + end; {$IFDEF DEBUG} WriteLn('A consequence should have shown.'); {$ENDIF} + //Sleep(1000); end; + if AReply.Count > 7 then + begin + LCount := WordCount(AReply[7],['+']); + if LCount > 0 then + for i := 1 to LCount do + begin + LConsequence := TConsequence.Create(nil,ExtractDelimited(i,AReply[7],['+'])); + LConsequence.GenerateMessage(True); + FZMQActor.SendMessage([K_MESSAGE,'',ExtractDelimited(i,AReply[7],['+']),BoolToStr(True)]); + + {$IFDEF DEBUG} + WriteLn('A metaconsequence should have shown.'); + {$ENDIF} + //Sleep(1000); + end; + + if AReply.Count > 8 then + FZMQActor.SendMessage([K_QUESTION,AReply[8]]) + else + FZMQActor.SendMessage([K_RESUME]); + end; end; end; @@ -1053,13 +1087,13 @@ procedure TGameControl.ReceiveReply(AReply: TStringList); // // wait //end; - procedure ResumePlayer; - begin - - end; + //procedure ResumePlayer; + //begin + // + //end; begin - if MHas(K_RESUME+K_ARRIVED) then ResumePlayer; + //if MHas(K_RESUME+K_ARRIVED) then ResumePlayer; if MHas(K_LOGIN+K_ARRIVED) then LoginAccepted; if MHas(K_CHOICE+K_ARRIVED) then ChoiceValidated; //if MHas(K_QUESTION+K_ARRIVED) then QuestionValidated; diff --git a/units/game_experiment.pas b/units/game_experiment.pas index 1679c73..9206079 100644 --- a/units/game_experiment.pas +++ b/units/game_experiment.pas @@ -30,28 +30,23 @@ type TExperiment = class(TComponent) private - FExperimentStart : Boolean; FExperimentAim, FExperimentName, FFilename, - FResearcher : UTF8string; - FOnConsequence: TNotifyEvent; - FOnInterlocking: TNotifyEvent; - FOnEndTurn: TNotifyEvent; - FOnEndCondition: TNotifyEvent; - FOnEndCycle: TNotifyEvent; - FOnEndExperiment: TNotifyEvent; - FOnEndGeneration: TNotifyEvent; - FMatrixType: TGameMatrixType; - FRegData : TRegData; + FResearcher : string; + FExperimentStart : Boolean; FGenPlayersAsNeeded : Boolean; - FPlayers : TPlayers; - FCurrentCondition : integer; - FConditions : TConditions; FResearcherCanChat: Boolean; FResearcherCanPlay: Boolean; FSendChatHistoryForNewPlayers: Boolean; FShowChat: Boolean; + FMatrixType: TGameMatrixType; + private + FLastReportColNames : string; + FRegData : TRegData; + FPlayers : TPlayers; + FCurrentCondition : integer; + FConditions : TConditions; FState: TExperimentState; FTurnsRandom : TStringList; function GetCondition(I : Integer): TCondition; @@ -90,36 +85,50 @@ type procedure SetSendChatHistoryForNewPlayers(AValue: Boolean); procedure SetState(AValue: TExperimentState); private + FOnConsequence: TNotifyEvent; + FOnInterlocking: TNotifyEvent; + FOnEndTurn: TNotifyEvent; + FOnEndCondition: TNotifyEvent; + FOnEndCycle: TNotifyEvent; + FOnEndExperiment: TNotifyEvent; + FOnEndGeneration: TNotifyEvent; procedure Consequence(Sender : TObject); procedure Interlocking(Sender : TObject); + procedure WriteReportHeader; + procedure WriteReportRowNames; + procedure WriteReportRow; public constructor Create(AOwner:TComponent);override; - constructor Create(AFilename: string; AOwner:TComponent); overload; + constructor Create(AOwner:TComponent; AppPath:string);overload; + constructor Create(AOwner:TComponent; AFilename, AppPath:string); overload; destructor Destroy; override; function LoadFromFile(AFilename: string):Boolean; function LoadFromGenerator:Boolean; - function AppendCondition : integer; overload; - function AppendCondition(ACondition : TCondition) : integer;overload; - function AppendContingency(ACondition : integer) : integer;overload; - function AppendContingency(ACondition : integer;AContingency : TContingency) : integer;overload; - function AppendPlayer : integer;overload; - function AppendPlayer(APlayer : TPlayer) : integer; overload; procedure SaveToFile(AFilename: string); overload; procedure SaveToFile; overload; procedure Clean; procedure Play; + property ExperimentAim : string read FExperimentAim write FExperimentAim; + property ExperimentName : string read FExperimentName write FExperimentName; + property GenPlayersAsNeeded : Boolean read FGenPlayersAsNeeded write FGenPlayersAsNeeded; property ResearcherCanPlay : Boolean read FResearcherCanPlay write SetResearcherCanPlay; property ResearcherCanChat : Boolean read FResearcherCanChat write SetResearcherCanChat; - property Researcher : UTF8string read FResearcher write FResearcher; + property Researcher : string read FResearcher write FResearcher; + property ShowChat : Boolean read FShowChat write FShowChat; + property SendChatHistoryForNewPlayers : Boolean read FSendChatHistoryForNewPlayers write SetSendChatHistoryForNewPlayers; + property MatrixType : TGameMatrixType read FMatrixType write SetMatrixType; + public + function AppendCondition : integer; overload; + function AppendCondition(ACondition : TCondition) : integer;overload; + function AppendContingency(ACondition : integer) : integer;overload; + function AppendContingency(ACondition : integer;AContingency : TContingency) : integer;overload; + function AppendPlayer : integer;overload; + function AppendPlayer(APlayer : TPlayer) : integer; overload; property Condition[I : Integer]: TCondition read GetCondition write SetCondition; property ConditionsCount : integer read GetConditionsCount; property CurrentCondition : integer read FCurrentCondition write FCurrentCondition; property Contingency[C, I : integer] : TContingency read GetContingency write SetContingency; property ContingenciesCount[C:integer]:integer read GetContingenciesCount; - property ExperimentAim : UTF8string read FExperimentAim write FExperimentAim; - property ExperimentName : UTF8string read FExperimentName write FExperimentName; - property GenPlayersAsNeeded : Boolean read FGenPlayersAsNeeded write FGenPlayersAsNeeded; - property InterlockingsIn[i:integer]:integer read GetInterlockingsIn; property Player[I : integer] : TPlayer read GetPlayer write SetPlayer; property PlayerFromID[S : UTF8string ] : TPlayer read GetPlayer write SetPlayer; property PlayersCount : integer read GetPlayersCount; @@ -127,11 +136,10 @@ type property PlayerIndexFromID[s : UTF8string]: integer read GetPlayerIndexFromID; property PlayerAsString[P:TPlayer]: UTF8string read AliasPlayerAsString; property PlayerFromString[s : UTF8string]: TPlayer read AliasPlayerFromString; + public + property InterlockingsIn[i:integer]:integer read GetInterlockingsIn; property ConsequenceStringFromChoice[P:Tplayer]:UTF8String read GetConsequenceStringFromChoice; property ConsequenceStringFromChoices: UTF8String read GetConsequenceStringFromChoices; - property ShowChat : Boolean read FShowChat write FShowChat; - property SendChatHistoryForNewPlayers : Boolean read FSendChatHistoryForNewPlayers write SetSendChatHistoryForNewPlayers; - property MatrixType : TGameMatrixType read FMatrixType write SetMatrixType; property NextTurnPlayerID : UTF8string read GetNextTurnPlayerID; property NextTurn : integer read GetNextTurn; property NextCycle : integer read GetNextCycle; @@ -143,7 +151,6 @@ type property OnEndGeneration : TNotifyEvent read FOnEndGeneration write SetOnEndGeneration; property OnEndCondition : TNotifyEvent read FOnEndCondition write SetOnEndCondition; property OnEndExperiment : TNotifyEvent read FOnEndExperiment write SetOnEndExperiment; - public property OnConsequence : TNotifyEvent read FOnConsequence write SetOnConsequence; property OnInterlocking : TNotifyEvent read FOnInterlocking write SetOnInterlocking; end; @@ -489,6 +496,96 @@ begin if Assigned(FOnInterlocking) then FOnInterlocking(Sender); end; +procedure TExperiment.WriteReportHeader; +var + LHeader : string; +begin + // header + LHeader := VAL_RESEARCHER+':'+#9+FResearcher + LineEnding + + VAL_EXPERIMENT+':' + #9 + FExperimentName + LineEnding + + VAL_BEGIN_TIME+':' + #9 + DateTimeToStr(Date) + #9 + TimeToStr(Time) + LineEnding + LineEnding; + FRegData.SaveData(LHeader); + WriteReportRowNames; +end; + +procedure TExperiment.WriteReportRowNames; +var + c,j,i: integer; + LHeader : string; +begin + c:= CurrentCondition; + // column names, line 1 + LHeader := 'Experimento'+#9+#9; + for i:=0 to Condition[c].Turn.Value-1 do // player's response + LHeader += 'P'+IntToStr(i+1)+#9+#9; + + for i:=0 to ContingenciesCount[c]-1 do + if not Contingency[c,i].Meta then + begin + LHeader += Contingency[c,i].ContingencyName; + for j:=0 to Condition[c].Turn.Value-1 do + LHeader += #9; + end; + + LHeader += VAL_INTERLOCKING+'s'; + for i:=0 to ContingenciesCount[c]-1 do + if Contingency[c,i].Meta then + LHeader += #9; + + LHeader += LineEnding; + + + // column names, line 2 + LHeader += 'Condição'+#9+'Ciclo'+#9; + for i:=0 to Condition[c].Turn.Value-1 do + LHeader += 'Linha'+#9+'Cor'+#9; + + for i:=0 to ContingenciesCount[c]-1 do + if not Contingency[c,i].Meta then + for j:=0 to Condition[c].Turn.Value-1 do + LHeader += 'P'+IntToStr(j+1)+#9; + + for i:=0 to ContingenciesCount[c]-1 do + if Contingency[c,i].Meta then + LHeader += Contingency[c,i].ContingencyName+#9; + LHeader += LineEnding; + + FLastReportColNames := LHeader; + FRegData.SaveData(LHeader); +end; + +procedure TExperiment.WriteReportRow; +var + c,j,i: integer; + LHeader : string; +begin + c:= CurrentCondition; + + LHeader := IntToStr(c+1)+#9+IntToStr(Condition[c].Cycles.Count+1)+#9; + for i:=0 to Condition[c].Turn.Value-1 do + LHeader += GetRowString(FPlayers[i].Choice.Row)+#9+GetColorString(FPlayers[i].Choice.Color)+#9; + + for i:=0 to ContingenciesCount[c]-1 do + if not Contingency[c,i].Meta then + for j:=0 to Condition[c].Turn.Value-1 do + if Contingency[c,i].ConsequenceFromPlayerID(FPlayers[j].ID) <> '' then + LHeader += '1'+#9 + else + LHeader += '0'+#9; + + for i:=0 to ContingenciesCount[c]-1 do + if Contingency[c,i].Meta then + if Contingency[c,i].Fired then + LHeader += '1'+#9 + else + LHeader += '0'+#9; + LHeader += LineEnding; + + FLastReportColNames := LHeader; + FRegData.SaveData(LHeader); + +end; + constructor TExperiment.Create(AOwner: TComponent); begin inherited Create(AOwner); @@ -497,7 +594,17 @@ begin CheckNeedForRandomTurns; end; -constructor TExperiment.Create(AFilename: string;AOwner:TComponent); +constructor TExperiment.Create(AOwner: TComponent;AppPath:string); +begin + inherited Create(AOwner); + FTurnsRandom := TStringList.Create; + LoadExperimentFromResource(Self); + CheckNeedForRandomTurns; + FRegData := TRegData.Create(Self, AppPath+VAL_RESEARCHER+'es'+PathDelim+Researcher+PathDelim+ExperimentName+PathDelim+'000.dat'); + WriteReportHeader; +end; + +constructor TExperiment.Create(AOwner:TComponent;AFilename,AppPath:string); begin inherited Create(AOwner); FTurnsRandom := TStringList.Create; @@ -583,13 +690,31 @@ begin end; procedure TExperiment.Clean; +var c,i : integer; begin + WriteReportRow; + for i := 0 to PlayersCount -1 do + begin + FPlayers[i].Choice.Row:=grNone; + FPlayers[i].Choice.Color:=gcNone; + end; + c := CurrentCondition; + for i := 0 to ContingenciesCount[c]-1 do + Contingency[c,i].Clean; + + Condition[c].Prompt.Clean; + FRegData.CloseAndOpen; end; procedure TExperiment.Play; +var i : integer; begin - + for i := 0 to Condition[CurrentCondition].Turn.Value-1 do + begin + //TRegData.Save Header; + end; + FState:=xsRunning; end; end. diff --git a/units/game_file_methods.pas b/units/game_file_methods.pas index 79f2fe5..5e184d9 100644 --- a/units/game_file_methods.pas +++ b/units/game_file_methods.pas @@ -76,7 +76,7 @@ begin ResearcherCanPlay:=False; ResearcherCanChat:=True; SendChatHistoryForNewPlayers:=True; - ExperimentName:='Test Experiment'; + ExperimentName:='test_experiment'; ExperimentAim:='This is a test experiment.'; GenPlayersAsNeeded:=True; CurrentCondition := 0; @@ -98,12 +98,16 @@ begin SetLength(Contingencies, 4); LConcequence := TConsequence.Create(AExperiment,1,[gscPoints, gscB, gscMessage,gscBroadcastMessage],['$NICNAME','queijo','queijos']); Contingencies[0] := TContingency.Create(AExperiment,LConcequence,LCriteria1,False); + Contingencies[0].ContingencyName := 'CRF 1B'; LConcequence := TConsequence.Create(AExperiment,3,[gscPoints, gscA, gscMessage,gscBroadcastMessage],['$NICNAME','pão','pães']); Contingencies[1] := TContingency.Create(AExperiment,LConcequence,LCriteria2,False); + Contingencies[1].ContingencyName := 'CRF 1A'; LConcequence := TConsequence.Create(AExperiment,1,[gscPoints, gscG, gscMessage],['','item escolar','itens escolares']); Contingencies[2] := TContingency.Create(AExperiment,LConcequence,LCriteria3,True); + Contingencies[2].ContingencyName := 'MCRF 1G'; LConcequence := TConsequence.Create(AExperiment,-1,[gscPoints, gscG, gscMessage],['','item escolar','itens escolares']); Contingencies[3] := TContingency.Create(AExperiment,LConcequence,LCriteria4,True); + Contingencies[3].ContingencyName := 'MPUN -1G'; Prompt := TPrompt.Create( AExperiment @@ -129,57 +133,6 @@ var // if not (APath[Length(APath)] = PathDelim) then APath:= APath + PathDelim; //end; - function GetEndCriteria(S:string) : TEndConditionCriterium; - begin - case StrToIntDef(ExtractDelimited(1,S,[',']),2) of - 0: Result.Value := gecAbsoluteCycles; - 1: Result.Value := gecInterlockingPorcentage; - 2: Result.Value := gecWhichComeFirst; - end; - Result.AbsoluteCycles := StrToIntDef(ExtractDelimited(2,S,[',']), 20); - Result.InterlockingPorcentage := StrToIntDef(ExtractDelimited(3,S,[',']),10); - Result.LastCycles := StrToIntDef(ExtractDelimited(4,S,[',']), 10); - end; - - function GetPoints(S: string) : TPoints; - begin - Result.A := StrToIntDef(ExtractDelimited(1,S,[',']),0); - Result.B := StrToIntDef(ExtractDelimited(2,S,[',']),0); - Result.G := StrToIntDef(ExtractDelimited(3,S,[',']),0); - end; - - - function GetChoiceFromString(S:string) : TPlayerChoice; - begin - Result.Row := GetRowFromString(ExtractDelimited(1,S,[','])); - Result.Color := GetGameColorFromString(ExtractDelimited(2,S,[','])); - end; - - function GetPPointsFromString(S:string) : TPlayerPoints; - begin - Result.A := StrToIntDef(ExtractDelimited(1,S,[',']),0); - Result.B := StrToIntDef(ExtractDelimited(2,S,[',']),0); - end; - - function GetStatusFromString(S : string): TGamePlayerStatus; - begin - case ExtractDelimited(1,S,[',']) of - 'esperando': Result := gpsWaiting; - 'jogou': Result := gpsPlayed; - 'jogando': Result := gpsPlaying; - end; - end; - - function GetPromptStyle(S:string):TPromptStyle; - var - i : integer; - begin - // Yes,All,Metacontingency,RecoverLostPoints, - Result := []; - for i := 1 to 4 do - Result := Result + GetPromptStyleFromString(ExtractDelimited(i,S,[','])); - end; - procedure ReadExperiment; begin // Experiment; @@ -231,33 +184,6 @@ var LConsequence : TConsequence; LCriteria:TCriteria; - function GetCriteriaFromString(S:string):TCriteria; - var - LS : string; - i, - LCount: integer; - begin - LS := ExtractDelimited(1,S,['|']); - LCount := WordCount(LS,[#0,',']); - Result.Rows := []; - for i := 1 to LCount do - Result.Rows += [GetRowFromString(ExtractDelimited(i,LS,[',']))]; - - case ExtractDelimited(2,S,['|'])of - 'NONE':Result.Style:=gtNone; - 'CORES':Result.Style:=gtColorsOnly; - 'E':Result.Style:=gtRowsAndColors; - 'LINHAS':Result.Style:=gtRowsOnly; - 'OU':Result.Style:=gtRowsOrColors; - end; - - LS := ExtractDelimited(3,S,['|']); - LCount := WordCount(LS,[#0,',']); - Result.Colors := []; - for i := 1 to LCount do - Result.Colors += [GetGameColorFromString(ExtractDelimited(i,LS,[',']))]; - end; - procedure SetLCK(i:integer); begin if IsMeta then @@ -304,10 +230,10 @@ var {$ENDIF} s1 := DEF_END; end; - EndCriterium := GetEndCriteria(s1); + EndCriterium := GetEndCriteriaFromString(s1); ConditionName := ReadString(LS,KEY_COND_NAME,LS); - Points.Count := GetPoints(ReadString(LS, KEY_POINTS_COUNT,DEF_POINTS)); - Points.OnStart := GetPoints(ReadString(LS, KEY_POINTS_ONSTART,DEF_POINTS)); + Points.Count := GetPointsFromString(ReadString(LS, KEY_POINTS_COUNT,DEF_POINTS)); + Points.OnStart := GetPointsFromString(ReadString(LS, KEY_POINTS_ONSTART,DEF_POINTS)); Turn.Count:= ReadInteger(LS, KEY_TURN_COUNT,1); Turn.Value:= ReadInteger(LS, KEY_TURN_VALUE,2); Turn.Random:= ReadBool(LS, KEY_TURN_RANDOM,False); @@ -322,7 +248,7 @@ var Prompt := TPrompt.Create( AExperiment - , GetPromptStyle(ReadString(LS,KEY_PROMPT_STYLE,'todos,sim,metacontingência,recuperar pontos,')) + , GetPromptStyleFromString(ReadString(LS,KEY_PROMPT_STYLE,'todos,sim,metacontingência,recuperar pontos,')) , Contingencies , ReadString(LS,KEY_PROMPT_MESSAGE,DEF_PROMPTMESSAGE) ); diff --git a/units/game_resources.pas b/units/game_resources.pas index 94f0084..6b18edd 100644 --- a/units/game_resources.pas +++ b/units/game_resources.pas @@ -72,8 +72,12 @@ resourcestring KEY_CONSEQUE_MESSAGE_APPENDS = '.Consequência.Mensagem.Sufixo.Singular'; KEY_CONSEQUE_MESSAGE_APPENDP = '.Consequência.Mensagem.Sufixo.Plural'; - + VAL_CONSEQUENCE = 'Cosequência'; VAL_RESEARCHER = 'Pesquisador'; + VAL_EXPERIMENT = 'Experimento'; + VAL_INTERLOCKING = 'Entrelaçamento'; + + VAL_BEGIN_TIME = 'Começo'; DEF_END = '2,20,10,10,'; // which come first, 20 cycles | 10% entrelaçamentos in the last 10 cycles DEF_POINTS = '0,0,0,'; diff --git a/units/string_methods.pas b/units/string_methods.pas index 9994902..e9418d2 100644 --- a/units/string_methods.pas +++ b/units/string_methods.pas @@ -19,8 +19,6 @@ uses , game_resources ; -function GetAndDelFirstValue(var S: string;Sep:Char=','):string; deprecated 'Use ExtracteDelimited from strutils instead'; - function GetRowString(ARow : TGameRow) : string; function GetRowFromString(S : string):TGameRow; @@ -31,6 +29,7 @@ function GetGameColorFromString(S : string) : TGameColor; function GetPromptStyleFromString(S : string) : TPromptStyle; function GetPromptStyleString(AStyle : TPromptStyle) : string; +function GetGamePromptStyleFromString(S : string) : TGamePromptStyle; function GetConsequenceStyleFromString(s : string):TGameConsequenceStyle; function GetConsequenceStyleString(AStyle : TGameConsequenceStyle): string; @@ -42,10 +41,19 @@ function GetCriteriaFromString(S : string) : TCriteria; function GetCriteriaStyleString(AStyle: TGameStyle) : string; function GetStatusString(AStatus : TGamePlayerStatus): string; +function GetStatusFromString(S : string): TGamePlayerStatus; + +function GetPPointsFromString(S:string) : TPlayerPoints; function GetPPointsString(APPoints : TPlayerPoints) : string; -function GetChoiceString(AChoice : TPlayerChoice) : string; +function GetPointsFromString(S: string) : TPoints; function GetPointsString(APoints : TPoints) : string; + +function GetChoiceString(AChoice : TPlayerChoice) : string; +function GetChoiceFromString(S:string) : TPlayerChoice; + function GetEndCriteriaString(AEndCriterium:TEndConditionCriterium) : string; +function GetEndCriteriaFromString(S:string) : TEndConditionCriterium; + function GetPlayerFromString(s: string): TPlayer; function GetPlayerAsString(P: TPlayer): string; @@ -54,6 +62,57 @@ implementation uses strutils; +function GetEndCriteriaFromString(S:string) : TEndConditionCriterium; +begin + case StrToIntDef(ExtractDelimited(1,S,[',']),2) of + 0: Result.Value := gecAbsoluteCycles; + 1: Result.Value := gecInterlockingPorcentage; + 2: Result.Value := gecWhichComeFirst; + end; + Result.AbsoluteCycles := StrToIntDef(ExtractDelimited(2,S,[',']), 20); + Result.InterlockingPorcentage := StrToIntDef(ExtractDelimited(3,S,[',']),10); + Result.LastCycles := StrToIntDef(ExtractDelimited(4,S,[',']), 10); +end; + +function GetPointsFromString(S: string) : TPoints; +begin + Result.A := StrToIntDef(ExtractDelimited(1,S,[',']),0); + Result.B := StrToIntDef(ExtractDelimited(2,S,[',']),0); + Result.G := StrToIntDef(ExtractDelimited(3,S,[',']),0); +end; + + +function GetChoiceFromString(S:string) : TPlayerChoice; +begin + Result.Row := GetRowFromString(ExtractDelimited(1,S,[','])); + Result.Color := GetGameColorFromString(ExtractDelimited(2,S,[','])); +end; + +function GetPPointsFromString(S:string) : TPlayerPoints; +begin + Result.A := StrToIntDef(ExtractDelimited(1,S,[',']),0); + Result.B := StrToIntDef(ExtractDelimited(2,S,[',']),0); +end; + +function GetStatusFromString(S : string): TGamePlayerStatus; +begin + case ExtractDelimited(1,S,[',']) of + 'esperando': Result := gpsWaiting; + 'jogou': Result := gpsPlayed; + 'jogando': Result := gpsPlaying; + end; +end; + +function GetPromptStyleFromString(S:string):TPromptStyle; +var + i : integer; +begin + // Yes,All,Metacontingency,RecoverLostPoints, + Result := []; + for i := 1 to 4 do + Result := Result + [GetGamePromptStyleFromString(ExtractDelimited(i,S,[',']))]; +end; + function GetAndDelFirstValue(var S: string;Sep:Char=','): string; begin Result := Copy(S, 0, pos(Sep, S)-1); @@ -128,18 +187,18 @@ begin end; -function GetPromptStyleFromString(S: string): TPromptStyle; +function GetGamePromptStyleFromString(S: string): TGamePromptStyle; begin // todos,sim,metacontingência,recuperar pontos, case UpperCase(S) of //'NENHUM','NONE': Result:=[gsNone]; - 'TODOS', 'ALL' : Result:=[gsAll]; - 'SIM', 'YES','S','Y': Result:=[gsYes]; - 'NÃO','NAO','N' : Result:=[gsNo]; - 'CONTINGÊNCIA','CONTINGENCIA','CONTINGENCY','OPERANTE', 'OPERANT': Result:=[gsContingency]; - 'METACONTINGÊNCIA','METACONTINGENCIA','METACONTINGENCY','META': Result:=[gsMetacontingency]; - 'RECUPERA','RECUPERAR','RECUPERAR PONTOS','RECOVER','RESETAR', 'RESET': Result:=[gsRevertPoints]; - 'TIRAR DE A AO INVES DE B','TIRAR DE A AO INVÉS DE B', 'B as A' : Result:=[gsBasA]; + 'TODOS', 'ALL' : Result := gsAll; + 'SIM', 'YES','S','Y': Result := gsYes; + 'NÃO','NAO','N' : Result := gsNo; + 'CONTINGÊNCIA','CONTINGENCIA','CONTINGENCY','OPERANTE', 'OPERANT': Result := gsContingency; + 'METACONTINGÊNCIA','METACONTINGENCIA','METACONTINGENCY','META': Result := gsMetacontingency; + 'RECUPERA','RECUPERAR','RECUPERAR PONTOS','RECOVER','RESETAR', 'RESET': Result := gsRevertPoints; + 'TIRAR DE A AO INVES DE B','TIRAR DE A AO INVÉS DE B', 'B as A' : Result := gsBasA; end; end; @@ -197,33 +256,31 @@ begin Result += '|'; end; -function GetCriteriaFromString(S: string): TCriteria; +function GetCriteriaFromString(S:string):TCriteria; var - s1 : string; - i : integer; + LS : string; + i, + LCount: integer; begin - s1 := ExtractDelimited(1,S,['|']); + LS := ExtractDelimited(1,S,['|']); + LCount := WordCount(LS,[#0,',']); Result.Rows := []; - - for i := 1 to WordCount(s1,[#0,',']) do - if ExtractDelimited(i,s1,[',']) <> '' then - Result.Rows += [GetRowFromString(ExtractDelimited(i,s1,[',']))] - else Break; - - s1 := ExtractDelimited(2,S,['|']); - case UpperCase(s1) of - '','INDIFERENTE', 'NONE' : Result.Style := gtNone; - 'E', 'AND' : Result.Style := gtRowsAndColors; - 'OU', 'OR' : Result.Style := gtRowsOrColors; - + for i := 1 to LCount do + Result.Rows += [GetRowFromString(ExtractDelimited(i,LS,[',']))]; + + case ExtractDelimited(2,S,['|'])of + 'NONE':Result.Style:=gtNone; + 'CORES':Result.Style:=gtColorsOnly; + 'E':Result.Style:=gtRowsAndColors; + 'LINHAS':Result.Style:=gtRowsOnly; + 'OU':Result.Style:=gtRowsOrColors; end; - s1 := ExtractDelimited(3,S,['|']); + LS := ExtractDelimited(3,S,['|']); + LCount := WordCount(LS,[#0,',']); Result.Colors := []; - for i := 1 to WordCount(s1,[#0,',']) do - if ExtractDelimited(i,s1,[',']) <> '' then - Result.Colors += [GetGameColorFromString(ExtractDelimited(i,s1,[',']))] - else Break; + for i := 1 to LCount do + Result.Colors += [GetGameColorFromString(ExtractDelimited(i,LS,[',']))]; end; function GetCriteriaStyleString(AStyle: TGameStyle): string; -- libgit2 0.21.2