Payoff Matrix - Feedback Counter (Tidy up script)

David McFarlane mcfarla9 at msu.edu
Tue Jan 11 17:02:33 UTC 2011


Caleb,

First the punchline:  What I had in mind was that you might do this 
with no If..Then or Select Case at all.  Further comments in line below...


At 1/11/2011 02:46 AM Tuesday, you wrote:
>David,
>Thank you for your amazing advice.  Please see below as I still have
>more questions.  Also, if you keep reading past this, I will show you
>another solution I came to.  I really really hope that this formatting
>thing has been fixed.  I'm so sorry if it hasn't as this is a long
>reply and I spent a good 20 minutes trying to make the formatting to
>your specifications.
>
>Caleb
>
>On Monday, January 10, 2011 11:32:47 AM UTC-8, dkmcf wrote:
>Caleb,
>I commend you for taking an interest in improving your code, instead
>of simply settling for the first bit of code that gives the appearnce
>of working (and which almost always fails on close inspection).  I
>hope my comments below don't seem too harsh, if so just consider that
>they come from a grouchy old man.
>
>Thank you.  I appreciate constructive criticism.
>
>First, some style issues -- Your code appeared in my e-mail reader
>with indentations of *12* spaces!  That is *way* too much
>indentation, it makes the code quickly run off the edge of the screen
>and makes it unreadable.  Please learn to use the well-documented
>industry standard indentation of 4 spaces.  Also, *please* resist the
>urge to double-space your code, that only reduces how much of your
>code will fit into view on my screen and does nothing to aid
>understanding.  I had to take your code into my own text editor and
>edit it down to make it readable, do not expect me to do that again.
>
>This only happened because I had copied and pasted my post into Word
>in order to save a draft as I was typing so that in case I lost my
>post, I could retrieve it.  This may have happened again.  I'm sorry
>that Google Groups isn't so friendly with this.

This is why I edit my code in a professional text-editing program.  I 
like EditPadPro (http://www.editpadpro.com/ ), which you can get for 
$50 or use the trial version for free, or you can find other programs 
out there.  Many of these, including EditPadPro even do syntax 
highlighting for you, and with some tweaks it will properly highlight 
syntax for VBA and E-Basic.  I regular pull my E-Basic code into 
EditPadPro for editing, documentation, and printout, then copy & 
paste it back into E-Studio as needed, it is so much better than 
editing in E-Studio.

(BTW, I am not just making up the "indent four spaces" convention -- 
lore has it that long ago a university study found that this was the 
optimal indentation for program code, but I can't find the reference 
offhand.  In any case, you can search the web and find lots of 
debates over these fine points.)


>Now, a few comments on the code itself.  First, I wonder if you
>really need two different Slide objects?  If they perform essentially
>the same function only with different content, then I would just use
>one Slide and change the content using attribute references.  That
>could simplify the code right there.
>
>I took your advice and basically created script that changed the slide
>based upon the Test Type condition.  This necessarily reduced the
>amount of code by half (and for your Array example, it decreases the
>array by one dimension).

Cool.  Glad that suggestion did some good.


>Next, ignoring the MsgBox statements, it seems to me that all that
>changes in the various conditions is the number of points by which
>AccuracyDisplay changes.  In that case,  I would use a variable to
>hold the change amount, e.g., dAccuracyDisplay (i.e., "delta"
>AccuracyDisplay), so that the calculation becomes merely
>
>AccuracyDisplay = AccuracyDisplay + dAccuracyDisplay
>
>Yes, you might still need a mess of code to compute dAccuracyDisplay,
>but I like to separate the mess that computes dAccuracyDisplay from
>the operation that actually uses it, I find such separation aids my
>comprehension.
>
>I was not quite sure what you meant by this.  From my understanding, I
>would declare a new variable "dAccuracyDisplay".  dAccuracyDisplay
>would equal the change in point value between my Payoff conditions.
>For example, in Condition "A", let's say that for a Hit, the
>participant would receive 1 point and for a Correct rejection, the
>participant would receive 5 points.  In Condition "B", Hit = 2 points;
>CR = 4 points.  Thus, dAccuracyDisplay = 2-1; 5-4.  The change in
>points would thus be 1 between A and B.  This is my actual point
>system, by the way.  Hit points increase by 1 each time and CR points
>decrease by 1 (from A to E).  In this scenario, I'm not sure how to
>implement this variable because it seems unnecessary.
>
>Something like:
>************************************************************************************************************
>Dim dAccuracyDisplay as Integer ' Represents change in points between
>payoff conditions
>  Select Case c.getattrib ("Payoff")
>     Case "A"
>         dAccuracyDisplay=AccuracyDisplay+1
>         If c.getattrib("StatusOldNew")="Old" then
>             If TestSlideOLDNEW.ACC = 1 then
>                 AccuracyDisplay=dAccuracyDisplay
>.
>.
>.
>     Case "B"
>         .
>         .
>         dAccuracyDisplay=AccuracyDisplay+2
>*******************************************************************************
>Doesn't doing this defeat the purpose of using a variable in the first
>place?

Depends on the purpose of using the variable.  Here, for the purpose 
of clarity (paving the way to further code improvement), I merely 
meant to separate the "what" from the "how much", even if it meant 
adding an extra line or two of code.  Here the "what" means "sum 
something into the AccuracyDisplay", and the "how much" means how 
much to sum into the AccuracyDisplay.  Your code combines those two 
conceptually separate ideas, and sometime I find it helps to separate 
these.  It is the difference between

If in Michigan
     go to Meijer and buy milk
Else if in Alabama
     go to Winn Dixie and buy milk
Else if in Connecticut
     go to A&P and buy milk
...

and

If in Michigan
     go to Meijer
Else if in Alabama
     go to Winn Dixie
Else if in Connecticut
     go to A&P
...
Wherever you end up, now buy milk

So I guess it is still largely a matter of taste & style.  And 
admittedly, at another time I might have advised exactly the 
opposite, but in this case, just making the mental leap of separating 
"what" from "how much" then prepares us for the next steps...


>Next, once I have graduated to using a variable (instead of literal
>values) in the computation, I would consider using a
>multi-dimensional array to hold a table of the possible point values,
>and use numeric codes that will act as indices into the table for
>each condition.  E.g., I might use 0 instead of "OldNew" for that
>TestType, 0 instead of "Old"  for that StatusOldNew, etc.  This
>admitedly adds a bit of indirection, but indirection that will could
>greatly simplify our computation.  I would of course still need some
>code to set up the table at the start of the session, but with that
>done my computaton during the run might reduce to a single line, e.g.,
>
>AccuracyDisplay = AccuracyDisplay + PointTable( _
>      CInt(c.getattrib ("TestType")), _
>      CInt(MasterList.getattrib("StatusOldNew")), TestSlide.ACC )
>
>But I have probably missed something really obvious, so I hope
>someone else here will chime in and set me straight.
>
>Okay.  This is where I get really confused.  I understand that a
>multidimensional array can hold different values within each dimension
>(I did look over the VBA for Dummies Chapter on Arrays and Collections
>- Google Books).  If I understand you correctly, you are saying that I
>should create such an array with three dimensions.  The first
>dimension is my Test Type, the second is StatusOldNew, and the third
>is TestSlide.ACC.

That is pretty much correct, but just to express this accurately, 
each element of the array would hold the point value for that 
combination of TestType, StatusOldNew, and Accuracy.  So, 
PointSystem( 0, 0, 0 ) would hold the number of points for the case 
of, say, TestType = OldNew, StatusOldNew = Old, and Accuracy = 0 
(e.g., 0 points), and PointSystem( 0, 0, 1 ) would hold the number of 
points for the case of, say, TestType = OldNew, StatusOldNew = Old, 
and Accuracy = 1, etc. (e.g., 5 points), much as you show below.


>   I should code each dimension with all of the
>possible values as integers.  So for example, for TestType dimension:
>1 = "oldnew" and 0 = "PDP".  This coding system can then be called
>upon later in the script (like you gave in your example).  I get
>confused on how to set this up and implement it, but I think I
>understand it conceptually.
>  For example (this is what I understand):
>**********************************************************************************
>dim PointSystem(1,1,1) as variant
>
>'do this for each of the other attributes (e.g. StatusOldNew)
>if c.getattrib("TestType") = "OldNew" then
>     c.setattrib("TestType"), "0"
>Elseif c.getattrib("TestType") = "PDP" then
>     c.setattrib("TestType"), "1"
>Else
>     MsgBox "TestType attribute set error"
>End if

[For the sake of others who might stumble across this, I will just 
correct the syntax of this code a little, should read
>if c.getattrib("TestType") = "OldNew" then
>     c.setattrib "TestType", "0"
>Elseif c.getattrib("TestType") = "PDP" then
>     c.setattrib "TestType", "1"
>Else
>     MsgBox "TestType attribute set error"
>End if
]


>'I would set this to the actual and proper point values
>PointSystem(0,0 ,0 ) = 1
>PointSystem(0 ,1,0 ) = 2
>PointSystem( 0,0 ,1) = 3
>.
>.
>.
>PointSystem(1,1,1,) = 5
>
>'Then I would use your example and all I would need is this one line.
>AccuracyDisplay = AccuracyDisplay + PointSystem( _
>      CInt(c.getattrib ("TestType")), _
>      CInt(MasterList.getattrib("StatusOldNew")), TestSlide.ACC )
>*********************************************************************************

I think that is pretty close to what I had in mind, except that 
instead of using the If..Then..ElseIf to reassign the TestType index 
values, I would just go directly to whereever TestType gets defined 
in the first place (your Startup Info, or some List or c.SetAttrib, 
etc.) and put my index values there.


>The solution I came to:
>
>I added two attributes to my MasterList List object: Points_HR and
>Points_CR.  For each trial, I input the proper point values.  Then,
>for my payoff matrix, I simply referenced these point values.
>
>Script:
>**************************************************************************
>Select Case TestSlideOLDNEW.ACC
>         Case "1"
>                 If c.getattrib("StatusOldNew") = "Old" then
> 
>AccuracyDisplay=AccuracyDisplay+(c.getattrib("Points_HR"))'Hits
>                 Elseif c.getattrib("StatusOldNew") = "New" then
> 
>AccuracyDisplay=AccuracyDisplay+(c.getattrib("Points_CR"))'Correct
>Rejection
>                 Else MsgBox "Accuracy display case 1 error"
>                 End if
>                 c.setattrib "Accuracy", AccuracyDisplay
>                 Set x =
>CSlideText(TestSlideOLDNEW.States(TestSlideOLDNEW.ActiveState).Objects("Text4"))
>                         If Not x Is Nothing Then
>                         x.Text = "Running Total: " & c.getattrib("Accuracy")
>                         End if
>                 Debug.Print "Debug Points_HR: " & c.getattrib("Accuracy")
>         Case "0"
>                 AccuracyDisplay=AccuracyDisplay
>                 c.setattrib "Accuracy", AccuracyDisplay
>                 Set x =
>CSlideText(TestSlideOLDNEW.States(TestSlideOLDNEW.ActiveState).Objects("Text4"))
>                         If Not x Is Nothing Then
>                         x.Text = "Running Total: " & c.getattrib("Accuracy")
>                         End if
>                 Debug.Print "Debug Incorrect Accuracy: " & 
> c.getattrib("Accuracy")
>         Case Else
>                 MsgBox "TestSlideOLDNEW Accuracy Error"
>End Select
>***********************************************************************************
>Please also note that I am actually not deducting points anymore for
>incorrect answers so I do not need a counter for Misses and False
>Alarms.
>
>Although this is one solution I reached, I still want to understand
>what you meant by your suggestions.  Once again, thank you!


I hope I made things a little clearer.  Of course, I am assuming that 
your point system remains static, if it becomes dynamic then you 
could not use the array method.  And sometimes you really do have to 
settle for a cascade of If..Then and Select Case statements, and then 
sometimes just applying some theorems from Boolean logic will help to 
simplify this.


And for no particular reason, I will take this opportunity to close 
with my previously unpublished "Heirarchy of Goals for Excellent Programs":
1)  Works correctly (i.e., free of errors).
2)  Works soon enough to be of use -- an ugly program that works now 
is better than a beautiful program that works too late to be of use.
3)  Efficiently uses time and resources.
4) Source code is readable, understandable, clear.
5) Source code is beautiful.

Personally, I find my quest to achieve goal #5 often interferes with 
meeting the higher-priority goal #2, which is why I wrote this up as 
a reminder to myself.

-- David McFarlane, Professional Faultfinder

-- 
You received this message because you are subscribed to the Google Groups "E-Prime" group.
To post to this group, send email to e-prime at googlegroups.com.
To unsubscribe from this group, send email to e-prime+unsubscribe at googlegroups.com.
For more options, visit this group at http://groups.google.com/group/e-prime?hl=en.



More information about the Eprime mailing list