Programming Set

Some thoughts and notes

From both of us

Quick reminder:  Don't evaluate anything except what's in "Okay, I'm sure you're sick of looking at old versions...Here's the real one!  The whole thing!".  If you do, it probably won't work too well.

Also, this notebook is necessarily not representative of everything we did.  And the earlier attempts are not appropriately documented.  It's mostly there to prove to you that we went through insane amounts of work.  heh heh.

By the way, we're really proud of ourselves.  We accomplished almost everything we set out to do perfectly.  And more in some cases... in the beginning, we thought we'd only be able to use three of the four categories.  In fact, it wasn't until we were just about done that we realized, "Hey, we can do this!"  It was kind of cool.  We also both got a lot out of this, especially from working together (see our individual comments).  

That said, there are always ways to improve upon our wonderful work of art :) .    
We are aware of the following problems / potential upgrades:  
1.  When you click one button three times, it occasionally replaces more than just that button.
2.  There's no way to tell which buttons have been clicked, and no way to unclick a button that has been clicked accidentally.
3.  The whole putting the buttons in the right place thing-- like when you click on a cell that's not the button cell, and then click on a set, it goes crazy.
4.  The print statements that just keep printing (The Little Print Statements That Could).
5.  It would be cool if the computer knew whether or not there were sets... cool, but hard.
6.  And scoring.  There's no scoring and nothing to account for a multi-player game. 

If the world had been perfect (and we'd had all the time in it), perhaps these would've been rectified.

From Julie

The actual programming part of the project (the functions themselves) came easier to me than manipulating buttons, graphics, and windows.  Because I worked with Melanie, I was able to learn more about these other aspects of the program than I would have had I worked on my own.  I believe that Melanie also gained a lot from working with me (she'll talk about this below)... When I first began working with her, she'd done all of the graphics, but was having problems breaking down the program into smaller chunks.  So the first thing I did was to help her get rid of one of the categories.  Once I helped her break down the program some more, and  we started creating functions, it started to go relatively smoothly.  You can see below the parts of the program that were created mostly by me.

From Melanie

It's done!  I can't believe it, but I wrote (well, helped write) a program that actually does something!  And it does something cool!  In the end, I was very glad to have worked together with Julie.  I don't think I could have done this otherwise.  The presentation aspects (i.e. pretty pictures and bright colors) came the easiest to me, and it was tempting to spend all my time doing just those aspects.  However, in the spirit of teamwork, I did not.  Through this project, and looking at the versions Julie would write, I was actually able to put together some functions of my own, fiddle with what she had done, and to fully grasp what she was doing by herself and what we did together. We spend most of the time on this project sitting together in front of the same computer throwing ideas back and forth, explaining our thinking, and testing things out.  Granted, Julie was better at all of it than I was, but this process of collaboration taught me more than just about anything else throughout the semester.  
	Speaking of the semester...  There were about eight million times when I came within an eyelash of dropping this course.  It nearly killed me a few times, because I couldn't get it and refused to ask for help.  By brain just doesn't think the right way for this kind of stuff.  Sort of like it can decode what has been done by other people, but not encode its own ideas.  Had I attempted this whole project alone, I would have lost my mind.  Thankfully, it did not come to that, and I can honestly say that when I look at the final program I understand what it all means, and why it works the way it does.  Well, except for the bugs mentioned above.    I feel a little bad, because it would have been more gratifying to have done something completely on my own.  But when I weigh gratification against sanity, I'm glad I worked with Julie.  
	Julie obviously has had a better grasp on programming the whole semester.  Hence, she did much of the complicated work at the beginning.  However, I feel that I have improved tremendously in the past few weeks alone, enough so that by the end we were working side by side and at the same level on this particular project.  I know it is hard to tell how to distinguish who did what for purposes of grading, but my inclination would be that when in doubt, the grading should be weighted in Julie's favor.

The Graphics

Here are all 81 graphics images used as "cards" in our game.  This was the first thing Melanie did, before we became a team.

greenFilledDiamondOne := 
        Graphics[{RGBColor[0,  .5, 0], 
            Polygon[{{1, 0}, {1.05, 1}, {1, 2},  { .95, 
                  1}}]},   AspectRatio -> 3/2, 
          ImageSize ->  {65, 65},  
          Background -> Yellow];

redFilledDiamondOne := 
        Graphics[{RGBColor[ .8, 0, 0], 
            Polygon[{{1, 0}, {1.05, 1}, {1, 2},  { .95, 
                  1}}]},   AspectRatio -> 3/2, 
          ImageSize ->   {65, 65},  
          Background -> Yellow];

purpleFilledDiamondOne := 
        Graphics[{RGBColor[ .5, 0,  .5], 
            Polygon[{{1, 0}, {1.05, 1}, {1, 2},  { .95, 
                  1}}]},   AspectRatio -> 3/2,  
          ImageSize ->   {65, 65},  
          Background -> Yellow];

greenEmptyDiamondOne := 
        Graphics[{Thickness[ .1], RGBColor[0,  .5, 0], 
            Line[{{1, 0}, {1.05, 1}, {1, 2},  { .95, 1},  {1, 
                  0}}]},   AspectRatio -> 3/2, 
          ImageSize ->   {65, 65},  
          Background -> Yellow];

redEmptyDiamondOne :=  
        Graphics[{Thickness[ .1], RGBColor[ .8, 0, 0], 
            Line[{{1, 0}, {1.05, 1}, {1, 2},  { .95, 1},  {1, 0}}]},  
          AspectRatio -> 3/2,   ImageSize ->   {65, 65},  
          Background -> Yellow];

purpleEmptyDiamondOne := 
        Graphics[{Thickness[ .1], RGBColor[ .5,  0,   .5], 
            Line[{{1, 0}, {1.05, 1}, {1, 2},  { .95, 1},  {1, 0}}]},  
          AspectRatio -> 3/2,   ImageSize ->   {65, 65},  
          Background -> Yellow];

greenCrossedDiamondOne := 
        Graphics[{Thickness[ .1], RGBColor[0,  .5, 0], 
            Line[{{1, 0}, {1.05, 1}, {1, 2},  { .95, 1},  {1, 0}}],  
            Line[{{1.05,  1},  { .95,  1}}],  
            Line[{{1, 0},  {1, 1.9}}]},   AspectRatio -> 3/2, 
          ImageSize ->   {65, 65},  
          Background -> Yellow];

redCrossedDiamondOne := 
        Graphics[{Thickness[ .1], RGBColor[ .8, 0, 0], 
            Line[{{1, 0}, {1.05, 1}, {1, 2},  { .95, 1},  {1, 0}}],  
            Line[{{1.05,  1},  { .95,  1}}],  
            Line[{{1, 0},  {1, 1.9}}]},  AspectRatio -> 3/2,  
          ImageSize ->   {65, 65},  
          Background -> Yellow];

purpleCrossedDiamondOne := 
        Graphics[{Thickness[ .1], RGBColor[ .5, 0,  .5], 
            Line[{{1, 0}, {1.05, 1}, {1, 2},  { .95, 1},  {1, 0}}],  
            Line[{{1.05,  1},  { .95,  1}}],  
            Line[{{1, 0},  {1, 1.9}}]},   AspectRatio -> 3/2, 
          ImageSize ->   {65, 65},  
          Background -> Yellow];

greenFilledOvalOne := 
Graphics[{RGBColor[0,  .5, 
              0], Disk[{0, 0}, { .8, 1.5}]}, AspectRatio -> 1.6, 
          Axes -> False,  ImageSize ->   {65, 65},  
          Background -> Yellow];

redFilledOvalOne := 
Graphics[{RGBColor[ .8, 0, 0], 
            Disk[{0, 0}, { .8, 1.5}]}, AspectRatio -> 1.6, 
          Axes -> False,  ImageSize ->   {65, 65},  
          Background -> Yellow];

purpleFilledOvalOne := 
Graphics[{RGBColor[ .5, 
              0,  .5], Disk[{0, 0}, { .8, 1.5}]}, AspectRatio -> 1.6, 
          Axes -> False,  ImageSize -> {65, 65},  
          Background -> Yellow];

greenEmptyOvalOne :=  
Graphics[{Thickness[ .15], 
            RGBColor[0,   .5,  0],  
            Circle[{0, 0},  { .8,  
                1.5}]}, 
AspectRatio -> 1.6,  
          ImageSize ->  {65, 65},  
          Background -> Yellow];

redEmptyOvalOne := 
Graphics[{Thickness[ .15], 
            RGBColor[ .8,  0,  0],  
            Circle[{0, 0},  { .8,  
                1.5}]}, 
AspectRatio -> 1.6,  
          ImageSize ->  {65, 65},  
          Background -> Yellow];

purpleEmptyOvalOne :=  
Graphics[{Thickness[ .15], 
            RGBColor[ .5, 0,  .5],  
            Circle[{0, 0},  { .8,  
                1.5}]}, 
AspectRatio -> 1.6,  
          ImageSize ->  {65, 65},  
          Background -> Yellow];

greenCrossedOvalOne :=  
        Graphics[{Thickness[ .15], RGBColor[0,   .5,  0],  
            Circle[{0, 0},  { .8,  1.5}],  
            Line[{{- .8, 0},  { .8, 0}}],  
            Line[{{0,  -1.5},  {0,  
                  1.5}}]}, 
AspectRatio -> 1.6,  
          ImageSize ->  {65, 65},  Background -> Yellow,  
          Axes -> False];

redCrossedOvalOne :=  
Graphics[{Thickness[ .15], 
            RGBColor[ .8,  0,  0],  Circle[{0, 0},  { .8,  1.5}],  
            Line[{{- .8, 0},  { .8, 0}}],  
            Line[{{0,  -1.5},  {0,  
                  1.5}}]}, 
AspectRatio -> 1.6,  
          ImageSize ->  {65, 65},  Axes -> False,  
          Background -> Yellow];

purpleCrossedOvalOne :=  
Graphics[{Thickness[ .15], RGBColor[ .5,  0,  .5],  Circle[{0, 0},  { .8,  1.5}],  
            Line[{{- .8, 0},  { .8, 0}}],  
            Line[{{0,  -1.5},  {0,  
                  1.5}}]}, 
AspectRatio -> 1.6,  
          ImageSize ->  {65, 65},  Axes -> False,  
          Background -> Yellow];

greenFilledThingyOne := 
Graphics[{RGBColor[0,  .5, 
              0], 
Polygon[{{0, 0},  {1, 0},  {0, 
                  2},  {1, 2}}]}, 
 AspectRatio -> 3/2, 
          ImageSize ->  {65, 65}, 
          Background -> Yellow];

redFilledThingyOne := 
Graphics[{RGBColor[ .8, 0, 
              0], 
Polygon[{{0, 0},  {1, 0},  {0, 
                  2},  {1, 2}}]}, 
 AspectRatio -> 3/2, 
          ImageSize ->  {65, 65},  
          Background -> Yellow];

purpleFilledThingyOne := 
Graphics[{RGBColor[ .5, 
              0,  .5], 
Polygon[{{0, 0},  {1, 0},  {0, 
                  2},  {1, 2}}]}, 
 AspectRatio -> 3/2, 
          ImageSize ->  {65, 65},  
          Background -> Yellow];

greenEmptyThingyOne := 
Graphics[{Thickness[ .1], 
            RGBColor[0,  .5, 
              0], 
Line[{{0, 0},  {1, 0},  {0, 2},  {1, 
                  2},  {0, 0}}]}, 
 AspectRatio -> 3/2, 
          ImageSize ->  {65, 65},  
          Background -> Yellow];

redEmptyThingyOne := 
Graphics[{Thickness[ .1], 
            RGBColor[ .8, 0, 
              0], 
Line[{{0, 0},  {1, 0},  {0, 2},  {1, 
                  2},  {0, 0}}]}, 
 AspectRatio -> 3/2,  
          ImageSize ->  {65, 65},  
          Background -> Yellow];

purpleEmptyThingyOne := 
Graphics[{Thickness[ .1], 
            RGBColor[ .5, 
              0,  .5], 
Line[{{0, 0},  {1, 0},  {0, 
                  2},  {1, 2},  {0, 0}}]}, 
 
          AspectRatio -> 3/2, ImageSize ->  {65, 65},  
          Background -> Yellow];

greenCrossedThingyOne := 
Graphics[{Thickness[ .1], 
            RGBColor[0,  .5, 
              0], 
Line[{{0, 0},  {1, 0},  {0, 2},  {1, 
                  2},  {0, 0}} ], 
Line[{{ .5, 
                  0},  { .5, 
                  2}}], 
Line[{{ .25,   .35},  { .75,  .35}}], 
Line[{{ .25, 1.6},  { .75,  
                  1.6}}]}, 
 AspectRatio -> 3/2,  
          ImageSize ->  {65, 65},  
          Background -> Yellow];

redCrossedThingyOne := 
Graphics[{Thickness[ .1], 
            RGBColor[ .8, 0, 
              0], 
Line[{{0, 0},  {1, 0},  {0, 2},  {1, 
                  2},  {0, 0}}], 
Line[{{ .5, 0},  { .5, 
                  2}}], 
Line[{{ .25,   .35},  { .75,  .35}}], 
Line[{{ .25, 1.6},  { .75,  
                  1.6}}]}, 
 AspectRatio -> 3/2, 
          ImageSize ->  {65, 65},  
          Background -> Yellow];

purpleCrossedThingyOne := 
Graphics[{Thickness[ .1], RGBColor[ .5, 
              0,   .5], 
Line[{{0, 0},  {1, 0},  {0, 
                  2},  {1, 2},  {0, 0}}], 
Line[{{ .5, 
                  0},  { .5, 
                  2}}], 
Line[{{ .25,   .35},  { .75,  .35}}], 
Line[{{ .25, 1.6},  { .75,  
                  1.6}}]}, 
 AspectRatio -> 3/2, 
          ImageSize ->  {65, 65},  
          Background -> Yellow];

greenFilledDiamondTwo := 
        GraphicsArray[{greenFilledDiamondOne,  greenFilledDiamondOne},  
          ImageSize ->  {130, 65},  
          Background -> Yellow];

redFilledDiamondTwo := 
        GraphicsArray[{redFilledDiamondOne,  redFilledDiamondOne},  
          ImageSize ->  {130, 65}];

purpleFilledDiamondTwo := 
        GraphicsArray[{purpleFilledDiamondOne,  purpleFilledDiamondOne},  
          ImageSize ->  {130, 65}];

greenEmptyDiamondTwo := 
        GraphicsArray[{greenEmptyDiamondOne,  greenEmptyDiamondOne},  
          ImageSize ->  {130, 65}];

redEmptyDiamondTwo := 
        GraphicsArray[{redEmptyDiamondOne,  redEmptyDiamondOne},  
          ImageSize ->  {130, 65}];

purpleEmptyDiamondTwo := 
        GraphicsArray[{purpleEmptyDiamondOne,  purpleEmptyDiamondOne},  
          ImageSize ->  {130, 65}];

greenCrossedDiamondTwo := 
        GraphicsArray[{greenCrossedDiamondOne,  greenCrossedDiamondOne},  
          ImageSize ->  {130, 65}];

redCrossedDiamondTwo := 
        GraphicsArray[{redCrossedDiamondOne,  redCrossedDiamondOne},  
          ImageSize ->  {130, 65}];

purpleCrossedDiamondTwo := 
        GraphicsArray[{purpleCrossedDiamondOne,  purpleCrossedDiamondOne},  
          ImageSize ->  {130, 65}];

greenFilledOvalTwo := 
        GraphicsArray[{greenFilledOvalOne,  greenFilledOvalOne},  
          ImageSize ->  {130, 65}];

redFilledOvalTwo := 
        GraphicsArray[{redFilledOvalOne,  redFilledOvalOne},  
          ImageSize ->  {130, 65}];

purpleFilledOvalTwo := 
        GraphicsArray[{purpleFilledOvalOne,  purpleFilledOvalOne},  
          ImageSize ->  {130, 65}];

greenEmptyOvalTwo := 
        GraphicsArray[{greenEmptyOvalOne,  greenEmptyOvalOne},  
          ImageSize ->  {130, 65}];

\(\(redEmptyOvalTwo := 
        GraphicsArray[{redEmptyOvalOne, \ redEmptyOvalOne}, \ 

          ImageSize -> \ {130, 65}];\)\)

purpleEmptyOvalTwo := 
        GraphicsArray[{purpleEmptyOvalOne,  purpleEmptyOvalOne},  
          ImageSize ->  {130, 65}];

greenCrossedOvalTwo := 
        GraphicsArray[{greenCrossedOvalOne,  greenCrossedOvalOne},  
          ImageSize ->  {130, 65}];

redCrossedOvalTwo := 
        GraphicsArray[{redCrossedOvalOne,  redCrossedOvalOne},  
          ImageSize ->  {130, 65}];

purpleCrossedOvalTwo := 
        GraphicsArray[{purpleCrossedOvalOne,  purpleCrossedOvalOne},  
          ImageSize ->  {130, 65}];

greenFilledThingyTwo := 
        GraphicsArray[{greenFilledThingyOne,  greenFilledThingyOne},  
          ImageSize ->  {130, 65}];

redFilledThingyTwo := 
        GraphicsArray[{redFilledThingyOne,  redFilledThingyOne},  
          ImageSize ->  {130, 65}];

purpleFilledThingyTwo := 
        GraphicsArray[{purpleFilledThingyOne,  purpleFilledThingyOne},  
          ImageSize ->  {130, 65}];

greenEmptyThingyTwo := 
        GraphicsArray[{greenEmptyThingyOne,  greenEmptyThingyOne},  
          ImageSize ->  {130, 65}];

redEmptyThingyTwo := 
        GraphicsArray[{redEmptyThingyOne,  redEmptyThingyOne},  
          ImageSize ->  {130, 65}];

purpleEmptyThingyTwo := 
        GraphicsArray[{purpleEmptyThingyOne,  purpleEmptyThingyOne},  
          ImageSize ->  {130, 65}];

greenCrossedThingyTwo := 
        GraphicsArray[{greenCrossedThingyOne,  greenCrossedThingyOne},  
          ImageSize ->  {130, 65}];

redCrossedThingyTwo := 
        GraphicsArray[{redCrossedThingyOne,  redCrossedThingyOne},  
          ImageSize ->  {130, 65}];

purpleCrossedThingyTwo := 
        GraphicsArray[{purpleCrossedThingyOne,  purpleCrossedThingyOne},  
          ImageSize ->  {130, 65}];

greenFilledDiamondThree := 
        GraphicsArray[{greenFilledDiamondOne,  greenFilledDiamondOne,  
            greenFilledDiamondOne},  
          ImageSize ->  {195, 65}];

redFilledDiamondThree := 
        GraphicsArray[{redFilledDiamondOne,  redFilledDiamondOne,  
            redFilledDiamondOne},  
          ImageSize ->  {195, 65}];

purpleFilledDiamondThree := 
        GraphicsArray[{purpleFilledDiamondOne,  purpleFilledDiamondOne,  
            purpleFilledDiamondOne},  
          ImageSize ->  {195, 65}];

greenEmptyDiamondThree := 
        GraphicsArray[{greenEmptyDiamondOne,  greenEmptyDiamondOne,  
            greenEmptyDiamondOne},  
          ImageSize ->  {195, 65}];

redEmptyDiamondThree := 
        GraphicsArray[{redEmptyDiamondOne,  redEmptyDiamondOne,  
            redEmptyDiamondOne},  
          ImageSize ->  {195, 65}];

purpleEmptyDiamondThree := 
        GraphicsArray[{purpleEmptyDiamondOne,  purpleEmptyDiamondOne,  
            purpleEmptyDiamondOne},  
          ImageSize ->  {195, 65}];

greenCrossedDiamondThree := 
        GraphicsArray[{greenCrossedDiamondOne,  greenCrossedDiamondOne,  
            greenCrossedDiamondOne},  
          ImageSize ->  {195, 65}];

redCrossedDiamondThree := 
        GraphicsArray[{redCrossedDiamondOne,  redCrossedDiamondOne,  
            redCrossedDiamondOne},  
          ImageSize ->  {195, 65}];

purpleCrossedDiamondThree := 
        GraphicsArray[{purpleCrossedDiamondOne,  purpleCrossedDiamondOne,  
            purpleCrossedDiamondOne},  
          ImageSize ->  {195, 65}];

greenFilledOvalThree := 
        GraphicsArray[{greenFilledOvalOne,  greenFilledOvalOne,  
            greenFilledOvalOne},  
          ImageSize ->  {195, 65}];

redFilledOvalThree := 
        GraphicsArray[{redFilledOvalOne,  redFilledOvalOne,  
            redFilledOvalOne},  ImageSize ->  {195, 65}];

purpleFilledOvalThree := 
        GraphicsArray[{purpleFilledOvalOne,  purpleFilledOvalOne,  
            purpleFilledOvalOne},  
          ImageSize ->  {195, 65}];

greenEmptyOvalThree := 
        GraphicsArray[{greenEmptyOvalOne,  greenEmptyOvalOne,  
            greenEmptyOvalOne},  
          ImageSize ->  {195, 65}];

redEmptyOvalThree := 
        GraphicsArray[{redEmptyOvalOne,  redEmptyOvalOne,  
            redEmptyOvalOne},  ImageSize ->  {195, 65}];

purpleEmptyOvalThree := 
        GraphicsArray[{purpleEmptyOvalOne,  purpleEmptyOvalOne,  
            purpleEmptyOvalOne},  
          ImageSize ->  {195, 65}];

greenCrossedOvalThree := 
        GraphicsArray[{greenCrossedOvalOne,  greenCrossedOvalOne,  
            greenCrossedOvalOne},  
          ImageSize ->  {195, 65}];

redCrossedOvalThree := 
        GraphicsArray[{redCrossedOvalOne,  redCrossedOvalOne,  
            redCrossedOvalOne},  
          ImageSize ->  {195, 65}];

purpleCrossedOvalThree := 
        GraphicsArray[{purpleCrossedOvalOne,  purpleCrossedOvalOne,  
            purpleCrossedOvalOne},  
          ImageSize ->  {195, 65}];

greenFilledThingyThree := 
        GraphicsArray[{greenFilledThingyOne,  greenFilledThingyOne,  
            greenFilledThingyOne},  
          ImageSize ->  {195, 65}];

redFilledThingyThree := 
        GraphicsArray[{redFilledThingyOne,  redFilledThingyOne,  
            redFilledThingyOne},  
          ImageSize ->  {195, 65}];

purpleFilledThingyThree := 
        GraphicsArray[{purpleFilledThingyOne,  purpleFilledThingyOne,  
            purpleFilledThingyOne},  
          ImageSize ->  {195, 65}];

greenEmptyThingyThree := 
        GraphicsArray[{greenEmptyThingyOne,  greenEmptyThingyOne,  
            greenEmptyThingyOne},  
          ImageSize ->  {195, 65}];

redEmptyThingyThree := 
        GraphicsArray[{redEmptyThingyOne,  redEmptyThingyOne,  
            redEmptyThingyOne},  
          ImageSize ->  {195, 65}];

purpleEmptyThingyThree := 
        GraphicsArray[{purpleEmptyThingyOne,  purpleEmptyThingyOne,  
            purpleEmptyThingyOne},  
          ImageSize ->  {195, 65}];

greenCrossedThingyThree := 
        GraphicsArray[{greenCrossedThingyOne,  greenCrossedThingyOne,  
            greenCrossedThingyOne},  
          ImageSize ->  {195, 65}];

redCrossedThingyThree := 
        GraphicsArray[{redCrossedThingyOne,  redCrossedThingyOne,  
            redCrossedThingyOne},  
          ImageSize ->  {195, 65}];

purpleCrossedThingyThree := 
        GraphicsArray[{purpleCrossedThingyOne,  purpleCrossedThingyOne,  
            purpleCrossedThingyOne},  
          ImageSize ->  {195, 65}];

Some ridiculous first and second and third and... and nth attempts

Attempt to make the cards understand what they were

At one point we tried this ridiculous list within list within list within list approach (Julie's idea...).  But things kept coming out in different orders.  We got confused.  We had the brilliant mod idea (Melanie's idea, which we will get into later) and gave up on this attempt. It looked like it would have worked at the beginning...oh how short sighted we were!  Young and foolish!

listofcards = { 
{red {filled {diamond,  oval,  
                    thingy}}, 
{empty {diamond,  oval,  
                  thingy}}, {crossed {diamond,  oval,  
                  thingy}}
}, 
{green {filled {diamond,  oval,  thingy}}, {empty {diamond,  oval,  
                  thingy}}, {crossed {diamond,  oval,  
                  thingy}}
}, 
{purple {filled {diamond,  oval,  thingy}}, {empty {diamond,  oval,  
                  thingy}}, {crossed {diamond,  oval,  
                  thingy}}}
} // TableForm

And we never did figure out why things came out in different orders.  Some were shape first, others shading first.  It was weird.  And we just realized it was doing it alphabetically...weird.

Our first real function related to the project...Shuffling the deck!

The only problem with this way of doing it, is the possibility, as Jim pointed out, of it taking FOREVER to finish.  It's not very time-efficient.  This was definitely a part that was done with us sitting together in front of the computer (and we were very proud).

number:=  
Module[{q}, 
chosen = {}; 
While[
            Length[chosen] ≠ 27, 
Do[
              q = Random[
                  Integer, {1, 27}]; 
If[! MemberQ[
                    chosen,  q], 
AppendTo[chosen, 
                  q]]]
];
];

A 3-card experiment with making pictures in buttons and a set function

This was all Julie trying to test out functions in buttons and an overall setQ.  In this version, each button had its own function, and in order to find out if the three buttons clicked were a set, you had to type in the function setQ.  This was done after a few days of both of us sitting together, and separately, perfecting the art of putting graphics in to buttons.

n = 0;
cardsChosen = {};
\(\(fct1 := 
        Module[{}, 
\(n++\); 
Print["The card you chose is a filled circle."]; 
If[n > 3, \ Print["You've chosen too many cards."]; 
            n = 0; Return[]]; 
If[n == 3, \ 
            Print["Three cards chosen."]; 
            n = 0, 
Print["You have " <> 
                ToString[
                  3 - n] <> " more cards to choose."]]; 
AppendTo[cardsChosen, 1]; 
Return[
            setQ];
];\)\)

\(\(\(fct2 := 
        Module[{}, 
\(n++\); 
Print["The card you chose is an empty circle."]; 
If[n > 3, \ Print["You've chosen too many cards."]; 
            n = 0; Return[]]; 
If[n == 3, \ 
            Print["Three cards chosen."]; 
            n = 0, 
Print["You have " <> 
                ToString[
                  3 - n] <> " more cards to choose."]]; 
AppendTo[cardsChosen, 
            2]; 
setQ
];\)\(
\)
    \)\)
\(\(fct3 := 
        Module[{}, 
\(n++\); 
Print["The card you chose is a line."]; 
If[n > 3, \ Print["You've chosen too many cards."]; 
            n = 0; Return[]]; 
If[n == 3, \ 
            Print["Three cards chosen."]; 
            n = 0, 
Print["You have " <> 
                ToString[
                  3 - n] <> " more cards to choose."]]; 
AppendTo[cardsChosen, 3]; 
Return[
            setQ];
];\)\)

cardsChosen = {};
\(\(setQ := 
        Module[{}, 
If[
            Length[cardsChosen] == 
              3, 
If[\((cardsChosen[\([1]\)] == 
                    cardsChosen[\([2]\)] == 
                    cardsChosen[\([3]\)])\) || 
\((cardsChosen[\([1]\)] ≠ 
                    cardsChosen[\([2]\)] ≠ 
                    cardsChosen[\([3]\)])\), \ 
Return["That's a set.  Good job."]; 
              cardsChosen = {}, 
Return["Sorry, that's not a set."]; 
              cardsChosen = {}], 
Return["Not enough cards chosen."]]
];\)\)

setQ

Our first experience with making a set function...oh, the mod experiment :(

init := 
      Module[{}, 
number; 
winOrLose = 
          0; 
cardsChosen = {}; 
makeButton; 
drawButton;
]
number := 
Module[{q}, 
chosen = 
              Table[i, {i, 1, 
                  27}]; 
newchosen = {}; 
Do[
              q = Random[
                  Integer, {1, Length[chosen]}]; 
AppendTo[
                newchosen, chosen[[q]]]; 
chosen = 
                Drop[chosen, {q}], {i, 1, 27}]; 
Return[
              newchosen];

];

  
\(fct[someNumber_] := 
          Module[{}, 
newNumber = 
              someNumber; 
Print[
              newNumber]; 
AppendTo[cardsChosen, 
              newNumber]; 
\(winOrLose++\); 
setQ; 
If[winOrLose == 3, \ 
              Print["Three cards chosen."]; 
              winOrLose = 
                0, 
Print["You have " <> 
                  ToString[
                    3 - winOrLose] <> " more cards to choose."]];

];\)

  
setQ:=Module[{},  
While[Length[cardsChosen] == 3,
If[Mod[
                          cardsChosen[[1]] + cardsChosen[[2]] + 
                            cardsChosen[[3]], 3] == 0,
  \(Print["cards add up to " <> 
                          ToString[
                            Mod[cardsChosen[\([1]\)] + cardsChosen[\([2]\)] + 
                                cardsChosen[\([3]\)], 
                              3]]]; 
cardsChosen = {}; 
Print["That's a set.  Good job."]\),
  \(Print["cards add up to " <> 
                          ToString[
                            Mod[cardsChosen[\([1]\)] + cardsChosen[\([2]\)] + 
                                cardsChosen[\([3]\)], 
                              3]]]; 
cardsChosen = {}; 
Print["Sorry, that's not a set."];\)
]
]
];

oneButton[aNumber_] := 
          ButtonBox[
            Cell[GraphicsData["PostScript", DisplayString[theOne]]], 
            ButtonFunction :> fct[aNumber], 
            ButtonEvaluator -> Automatic, Active -> True, 
            ButtonStyle -> "None"];

\(makeButton := 
          Module[{}, 
firstRow = {}; 
secondRow = {}; 
thirdRow = {}; 
Do[
              aNumber = 
                newchosen[\([i]\)];  (*picks\ the\ first\ number\ from\ our\ "shuffled deck"*) 
theOne = 
                listOPicks[\([aNumber]\)]; \  (*Finds\ the\ picture\ that\ equates\ to\ it*) 
If[1 ≤ i ≤ 3, \ 
                AppendTo[firstRow, 
                  oneButton[aNumber]]]; 
If[
                4 ≤ i ≤ 6, \ 
                AppendTo[secondRow, 
                  oneButton[aNumber]]]; 
If[
                7 ≤ i ≤ 9, \ 
                AppendTo[thirdRow, \ 
                  oneButton[aNumber]]], 
{i, 1, 
                9}]
];\)

makeButtonCell := 
          Cell[BoxData[GridBox[{firstRow, secondRow, thirdRow}]], 
            CellTags -> picturePlace];

drawButton := 
        Module[{nb}, 
          nb = SelectedNotebook[]; 
NotebookFind[nb, 
            picturePlace, All, CellTags]; 
NotebookWrite[
            nb, makeButtonCell, All];];

UH-OH... and this is where Melanie was playing with our game, and clicked on something she knew was not a set.  Then it told her that it was.  Obviously, it was a foolish, foolish idea.  Below are some examples of cards that added up to 0 (mod 3), but are obviously not sets in the sense that we wanted them.

Show[listOPicks[[12]]]

Show[listOPicks[[2]]]

Show[listOPicks[[7]]]

(Melanie's thoughts around 2 am after a power outtage and finding out that all our attempts were for naught: )  Well, 12+2+7=21≡0(mod3). In this set it should only work if 2 is a redEmptyThingy. That is number 23.  But it is obviously not a set.  Oh dear.  Now we're back to that original problem of having the picture know that it is green, or crossed, or whatnot. Dear dear deary deary dear dear dear. (Melanie's original words of exasperation are not reproduced here) 20,5,11 do it too. 
 Maybe they have to be a+b+c≡0(mod 3)&&a+b+c!≡0(mod 9)...  Also not true...3,6,9 do work.  which is 18, which is ≡ 0 (mod 9).  also 12,5,7
27,16,20... etc., etc.  Fear not, we do something about this below.

Show[listOPicks[[20]]];
Show[listOPicks[[5]]];
Show[listOPicks[[11]]];

Show[listOPicks[[12]]];
Show[listOPicks[[5]]];
Show[listOPicks[[7]]];

Show[listOPicks[[27]]];
Show[listOPicks[[16]]];
Show[listOPicks[[20]]];

A later 9-card version

This was our first version without serious flaws.  The second cell does the exact same thing, just worded slightly differently (i.e. one do-loop instead of three, some variables changed to more appropriate names.  Essentially, what this program does is (1) takes a list of numbers from 1-27, which represented the cards we were using at the time.  It then shuffles the list, as a representative shuffling of the deck of cards.  (2) sets the variable winOrLose, or, in the next version, buttonsClicked, to 0.   (3) sets color, shape, and shading to empty lists. (4) makes a Button, with ...  Well, we'll tell you all this later in the final program.  The important thing to notice from this version as opposed to the previous is that we made each object, instead of just being a picture, being a list with {picture, color, shading, shape}.

listOPicks = {{greenFilledDiamond, green, filled, 
            diamond}, 
{ redFilledDiamond, red, filled, 
            diamond},  
{purpleFilledDiamond, purple,  
            filled,  diamond},  
{greenEmptyDiamond, 
            green,  empty,  
            diamond},  
{redEmptyDiamond,  red,  
            empty,  diamond},  
{purpleEmptyDiamond,  
            purple,  empty,  
            diamond}, 
{greenCrossedDiamond,  green,  
            crossed,  diamond}, 
{redCrossedDiamond,  
            red,  crossed,  
            diamond}, 
{purpleCrossedDiamond,  purple,  
            crossed,  diamond}, 
{greenFilledOval,  
            green,  filled,  oval}, 
{redFilledOval,  
            red,  filled,  oval}, 
{purpleFilledOval,  
            purple,  filled,  oval}, 
{greenEmptyOval,  
            green,  empty,  oval}, 
{redEmptyOval,  
            red,  empty,  oval}, 
{purpleEmptyOval,  
            purple,  empty,  oval}, 
{greenCrossedOval, 
            green,  crossed,  oval}, 
{redCrossedOval,  
            red,  crossed,  oval}, 
{purpleCrossedOval, 
            purple,  crossed,  
            oval}, 
{greenFilledThingy,  green,  
            filled,  thingy}, 
{redFilledThingy,  red,  
            filled,  thingy}, 
{purpleFilledThingy,  
            purple,  filled,  
            thingy}, 
{greenEmptyThingy,  green,  
            empty,  thingy}, 
{redEmptyThingy,  red,  
            empty,  thingy}, 
{purpleEmptyThingy,  
            purple,  empty,  
            thingy}, 
{greenCrossedThingy,  green,  
            crossed,  thingy}, 
{redCrossedThingy,  
            red,  crossed,  
            thingy}, 
{purpleCrossedThingy, purple,  
            crossed,  thingy}};

init:=Module[{},
number;
winOrLose = 0;
cardsChosen = {};
color = {};
shading = {};
shape = {};
makeButton;
drawButton;
];

number := 
Module[{q}, 
chosen = 
              Table[i, {i, 1, 
                  27}]; 
newchosen = {}; 
Do[
              q = Random[
                  Integer, {1, Length[chosen]}]; 
AppendTo[
                newchosen, chosen[[q]]]; 
chosen = 
                Drop[chosen, {q}], {i, 1, 27}]; 
Return[
              newchosen];
];

fct[someNumber_]:=Module[{},
newNumber = someNumber;
Print["You chose a " <> 
                      ToString[listOPicks[[newNumber, 2]]] <> " " <> 
                      ToString[listOPicks[[newNumber, 3]]] <> " " <> 
                      ToString[
                        listOPicks[[newNumber, 
                            4]]] <> "."]
AppendTo[
                    cardsChosen, newNumber];
AppendTo[color, listOPicks[[newNumber, 2]]];
AppendTo[shading, 
                    listOPicks[[newNumber, 3]]];
AppendTo[shape, listOPicks[[newNumber, 4]]];
winOrLose++;
If[winOrLose == 3, newSetQ;; 
                  winOrLose = 
                    0, 
Print["You have " <> 
                      ToString[
                        3 - winOrLose] <> " more card(s) to choose."]];
];

  
newSetQ:=Module[{},
If[Length[cardsChosen] == 3,
If[
((ToString[color[[1]]] == 
                                    ToString[color[[2]]] == 
                                    ToString[
                                      color[[3]]]) || 
(ToString[color[[1]]] ≠  
                                    ToString[color[[2]]] ≠  
                                    ToString[
                                      color[[3]]])) && 
((ToString[shape[[1]]] == 
                                    ToString[shape[[2]]] == 
                                    ToString[
                                      shape[[3]]]) || 
(ToString[shape[[1]]] ≠  
                                    ToString[shape[[2]]] ≠  
                                    ToString[
                                      shape[[3]]])) && 
((ToString[shading[[1]]] == 
                                    ToString[shading[[2]]] == 
                                    ToString[
                                      shading[[3]]]) || 
(ToString[shading[[1]]] ≠  
                                    ToString[shading[[2]]] ≠  
                                    ToString[shading[[3]]])),
Print["That's a set. Good \
job!"],Print["Sorry, that's not a set."]
];
cardsChosen = {};
color = {};
shape = {};
shading = {};]];

  
oneButton[aNumber_] := 
            ButtonBox[
              Cell[GraphicsData["PostScript", DisplayString[theOne]]], 
              ButtonFunction :> fct[aNumber], 
              ButtonEvaluator -> Automatic, Active -> True, 
              ButtonStyle -> "None"];

makeButton := 
          Module[{}, 
picToDraw1 = {}; 
picToDraw2 = {}; 
picToDraw3 = {}; 
Do[
              aNumber = newchosen[[i]]; 
theOne = 
                listOPicks[[aNumber, 1]]; 
AppendTo[
                picToDraw1, oneButton[aNumber]], {i, 1, 
                3}]; 
Do[
aNumber = 
                Evaluate[newchosen[[i]]]; 
theOne = 
                listOPicks[[aNumber, 1]]; 
AppendTo[
                picToDraw2, oneButton[aNumber]], {i, 4, 
                6}]; 
Do[
aNumber = 
                newchosen[[i]]; 
theOne = 
                listOPicks[[aNumber, 1]]; 
AppendTo[
                picToDraw3, oneButton[aNumber]], {i, 7, 
                9}];
];

makeButtonCell := 
          Cell[BoxData[GridBox[{picToDraw1, picToDraw2, picToDraw3}]], 
            CellTags -> picturePlace];

drawButton := 
        Module[{nb}, 
          nb = SelectedNotebook[]; 
NotebookFind[nb, 
            picturePlace, All, CellTags]; 
NotebookWrite[
            nb, makeButtonCell, All];];
init

  
({{, , }, {, , }, {, , }})

Below here is the slightly improved, basically the same version.  This was Melanie being anal and wanting only one do-loop, and just changing some names because she's silly and picky.

init := 
          Module[{}, 
number; 
buttonsClicked = 
              0; 
cardsChosen = {}; 
color = {}; 
shading = {}; 
shape = {}; 
makeButton; 
drawButton;
];

number := 
Module[{q}, 
chosen = 
              Table[i, {i, 1, 
                  27}]; 
newchosen = {}; 
Do[
              q = Random[
                  Integer, {1, Length[chosen]}]; 
AppendTo[
                newchosen, chosen[[q]]]; 
chosen = 
                Drop[chosen, {q}], {i, 1, 27}]; 
Return[
              newchosen];
];

fct[someNumber_]:=Module[{},
newNumber = someNumber;
Print["You chose a " <> 
                      ToString[listOPicks[[newNumber, 2]]] <> " " <> 
                      ToString[listOPicks[[newNumber, 3]]] <> " " <> 
                      ToString[
                        listOPicks[[newNumber, 
                            4]]] <> "."]
AppendTo[
                    cardsChosen, newNumber];
AppendTo[color, 
                  listOPicks[[newNumber, 2]]];
AppendTo[shading, 
                  listOPicks[[newNumber, 3]]];
AppendTo[shape, 
                  listOPicks[[newNumber, 4]]];
buttonsClicked++;
If[buttonsClicked == 3,  newSetQ;; 
                    buttonsClicked = 0,
  Print["You have " <> 
                        ToString[
                          3 - winOrLose] <> " more card(s) to \
choose."]];
];

newSetQ:=Module[{},
If[Length[cardsChosen] == 3,
If[
((ToString[color[[1]]] == 
                                  ToString[color[[2]]] == 
                                  ToString[
                                    color[[3]]]) || 
(ToString[color[[1]]] ≠  
                                  ToString[color[[2]]] ≠  
                                  ToString[
                                    color[[3]]])) && 
((ToString[shape[[1]]] == 
                                  ToString[shape[[2]]] == 
                                  ToString[
                                    shape[[3]]]) || 
(ToString[shape[[1]]] ≠  
                                  ToString[shape[[2]]] ≠  
                                  ToString[
                                    shape[[3]]])) && 
((ToString[shading[[1]]] == 
                                  ToString[shading[[2]]] == 
                                  ToString[
                                    shading[[3]]]) || 
(ToString[shading[[1]]] ≠  
                                  ToString[shading[[2]]] ≠  
                                  ToString[shading[[3]]])),
  Print["That's a set. Good \
job!"],
  \(Print["Sorry, that's not a set."]\)
];
cardsChosen = {};
color = {};
shape = {};
shading = {};]];

oneButton[aNumber_] := 
          ButtonBox[
            Cell[GraphicsData["PostScript", DisplayString[theOne]]], 
            ButtonFunction :> fct[aNumber], 
            ButtonEvaluator -> Automatic, Active -> True, 
            ButtonStyle -> "None"];

makeButton:=Module[{},
firstRow={};
secondRow={};
thirdRow={};
Do[aNumber = newchosen[[i]];  
theOne = listOPicks[[aNumber, 1]];   
If[1 ≤ i ≤ 3,  
                          AppendTo[firstRow, oneButton[aNumber]]];
If[4 ≤ i ≤ 6,  
                          AppendTo[secondRow, oneButton[aNumber]]];
If[7 ≤ i ≤ 9,  
                          AppendTo[thirdRow,  oneButton[aNumber]]],
{i, 1, 9}]
];

makeButtonCell := 
          Cell[BoxData[GridBox[{firstRow, secondRow, thirdRow}]], 
            CellTags -> picturePlace];

drawButton := 
        Module[{nb}, 
          nb = SelectedNotebook[]; 
NotebookFind[nb, 
            picturePlace, All, CellTags]; 
NotebookWrite[
            nb, makeButtonCell, All];];

init

Adding what to do if they click the same card three times, and opening in a new window

init:=Module[{},
Clear[theGameWindow];
number;
buttonsClicked = 0;
cardsChosen = {};
color = {};
shading = {};
shape = {};
makeButton;
<< Graphics`Graphics`; 
<< Graphics`Colors`;  
createGameWindow;
drawButton;
]


fct[someNumber_]:=Module[{},
newNumber = someNumber;
  
AppendTo[cardsChosen, newNumber];
AppendTo[color, 
                  listOPicks[[newNumber, 2]]];
AppendTo[shading, 
                  listOPicks[[newNumber, 3]]];
AppendTo[shape, 
                  listOPicks[[newNumber, 4]]];
buttonsClicked++;
If[buttonsClicked == 3,  newSetQ;areYouLame;buttonsClicked = 0(*,
  Print["You have " <> 
                          ToString[
                            3 - buttonsClicked] <> " more card(s) to \
choose."]*)];
];

newSetQ:=Module[{},
If[Length[cardsChosen] == 3,
If[
((ToString[color[[1]]] == 
                                  ToString[color[[2]]] == 
                                  ToString[
                                    color[[3]]]) || 
(ToString[color[[1]]] ≠  
                                  ToString[color[[2]]] ≠  
                                  ToString[
                                    color[[3]]])) && 
((ToString[shape[[1]]] == 
                                  ToString[shape[[2]]] == 
                                  ToString[
                                    shape[[3]]]) || 
(ToString[shape[[1]]] ≠  
                                  ToString[shape[[2]]] ≠  
                                  ToString[
                                    shape[[3]]])) && 
((ToString[shading[[1]]] == 
                                  ToString[shading[[2]]] == 
                                  ToString[
                                    shading[[3]]]) || 
(ToString[shading[[1]]] ≠  
                                  ToString[shading[[2]]] ≠  
                                  ToString[shading[[3]]])),
  Print["That's a set. Good \
job!"],
  \(Print["Sorry, that's not a set."]\)
];
]];

  

\(areYouLame := 
            Module[{}, 
If[
                Length[cardsChosen] == 3 && 
                  cardsChosen[\([1]\)] == \ 
                    cardsChosen[\([2]\)] == \ cardsChosen[\([3]\)], \ 
                Print["Wait, no it's not.  You can't just pick the same card three times.  Try again."]]; 
cardsChosen = {}; 
color = {}; 
shape = {}; 
shading = {};
];\)

oneButton[aNumber_] := 
          ButtonBox[
            Cell[GraphicsData["PostScript", DisplayString[theOne]]], 
            ButtonFunction :> fct[aNumber], 
            ButtonEvaluator -> Automatic, Active -> True,  
            ButtonStyle -> "None",  
            Background -> CadmiumLemon];

\(makeButton := 
          Module[{}, 
firstRow = {}; 
secondRow = {}; 
thirdRow = {}; 
Do[
              aNumber = 
                newchosen[\([i]\)];  (*picks\ the\ first\ number\ from\ our\ "shuffled deck"*) 
theOne = 
                listOPicks[\([aNumber, 
                    1]\)]; \  (*Finds\ the\ picture\ that\ equates\ to\ it*) 
If[1 ≤ i ≤ 3, \ 
                AppendTo[firstRow, 
                  oneButton[aNumber]]]; 
If[
                4 ≤ i ≤ 6, \ 
                AppendTo[secondRow, 
                  oneButton[aNumber]]]; 
If[
                7 ≤ i ≤ 9, \ 
                AppendTo[thirdRow, \ 
                  oneButton[aNumber]]], 
{i, 1, 
                9}]
];\)

makeButtonCell := 
          Cell[BoxData[GridBox[{firstRow, secondRow, thirdRow}]], 
            CellTags -> picturePlace];

  

createGameWindow := 
            Module[{}, 
If[! ValueQ[
                    theGameWindow], theGameWindow = 
                    NotebookCreate[WindowSize -> {400, 600},  
                      WindowTitle ->  "Let's Play Set!",  
                      FontSize ->  11,  
                      Background ->  Honeydew,  
                      FontColor ->  
                        RGBColor[ .2,  .2,  .2]];
]];

drawButton:=Module[{nb},nb = theGameWindow;
NotebookFind[nb, picturePlace, All, 
                CellTags];
NotebookWrite[nb, makeButtonCell, 
                All];];

Nearly the same as above, but with replacing of used cards

The replacing of used cards was a quite difficult. It went through many phases and turmoils.  While Melanie was figuring out how to have things open in new windows, etc, Julie was trying to find out how to replace cards.  We collaborated a little bit on these things, but were almost completely separated task and skill-level wise.  Notice that setq (the True or False variable), theShapes, maybeShapes, newShapes, and theNext have all been added to this version.  All of these became part of the final product.  The idea is that when a card is picked, newShapes changes the number in that card's position to the next card in the deck.  This happens three times.  Each time, newShapes changes, and maybeShapes changes.  If the three cards chosen are a set, theShapes changes to maybeShapes.  If they are not a set, maybeShapes changes back to theShapes.  You can seen more in the final documentation about why Julie decided to have all three (theShapes, maybeShapes, and newShapes).

engageSetYo:=Module[{},
Clear[theGameWindow];
number;
buttonsClicked = 0;
cardsChosen = {};
color = {};
shading = {};
shape = {};
setq = False;
theShapes = Table[newchosen[[i]], {i, 1, 9}];
maybeShapes = theShapes;
newShapes = theShapes;
theNext = 10;
makeButton;
createGameWindow;
drawButton;
];

number := 
Module[{q}, 
chosen = 
              Table[i, {i, 1, 
                  27}]; 
newchosen = {}; 
Do[
              q = Random[
                  Integer, {1, Length[chosen]}]; 
AppendTo[
                newchosen, chosen[[q]]]; 
chosen = 
                Drop[chosen, {q}], {i, 1, 27}]; 
Return[
              newchosen];

];

fct[someNumber_]:=Module[{},
newNumber = someNumber;
Do[If[theShapes[[i]] == newNumber, 
                        numberPlace = i],{i, 1, 9}];
  ;
AppendTo[cardsChosen, newNumber];
AppendTo[color, 
                  listOPicks[[newNumber, 2]]];
AppendTo[shading, 
                  listOPicks[[newNumber, 3]]];
AppendTo[shape, 
                  listOPicks[[newNumber, 4]]];
buttonsClicked++;
If[
                    theNext ≤ 27, 
newShapes = 
                      ReplacePart[newShapes, newchosen[[theNext]], 
                        numberPlace]; 
maybeShapes = 
                      newShapes; 
theNext++, 
newShapes = 
                      ReplacePart[newShapes, 28, 
                        numberPlace]; 
maybeShapes = 
                      newShapes;];
If[buttonsClicked == 3,  
newSetQ;
If[
                          setq == True, 
theShapes = 
                            maybeShapes; 
setq = False];
buttonsClicked = 0;
makeButton;
createGameWindow;
drawButton,
  
maybeShapes=theShapes;
(*Print["You have " <> 
                          ToString[
                            3 - buttonsClicked] <> " more card(s) to \
choose."];*)];
];

newSetQ:=Module[{},
If[Length[cardsChosen] == 3,
If[
((ToString[color[[1]]] == 
                                  ToString[color[[2]]] == 
                                  ToString[
                                    color[[3]]]) || 
(ToString[color[[1]]] ≠  
                                  ToString[color[[2]]] ≠  
                                  ToString[
                                    color[[3]]])) && 
((ToString[shape[[1]]] == 
                                  ToString[shape[[2]]] == 
                                  ToString[
                                    shape[[3]]]) || 
(ToString[shape[[1]]] ≠  
                                  ToString[shape[[2]]] ≠  
                                  ToString[
                                    shape[[3]]])) && 
((ToString[shading[[1]]] == 
                                  ToString[shading[[2]]] == 
                                  ToString[
                                    shading[[3]]]) || 
(ToString[shading[[1]]] ≠  
                                  ToString[shading[[2]]] ≠  
                                  ToString[shading[[3]]])),
  Print["That's a set. Good job!"]; 
                        areYouLame; 
setq = True,
  Print["Sorry, that's not a \
set."]; 
setq = False;
];
cardsChosen = {};
color = {};
shape = {};
shading = {};]];

areYouLame := 
          Module[{}, 
If[
                Length[cardsChosen] == 3 && 
                  cardsChosen[[1]] ==  
                    cardsChosen[[2]] ==  cardsChosen[[3]],  
                
                Print["Wait, no it's not.  You can't just pick the same \
card three times.  Try again."]];
];


oneButton[aNumber_] := 
          ButtonBox[
            Cell[GraphicsData["PostScript", DisplayString[theOne]]], 
            ButtonFunction :> fct[aNumber], 
            ButtonEvaluator -> Automatic, Active -> True, 
            ButtonStyle -> "None",  
            Background -> CadmiumLemon];

\(makeButton := 
          Module[{}, 
firstRow = {}; 
secondRow = {}; 
thirdRow = {}; 
Do[
              aNumber = 
                theShapes[\([i]\)];  (*picks\ the\ first\ number\ from\ our\ "shuffled deck"*) 
theOne = 
                listOPicks[\([aNumber, 
                    1]\)]; \  (*Finds\ the\ picture\ that\ equates\ to\ it*) 
If[1 ≤ i ≤ 3, \ 
                AppendTo[firstRow, 
                  oneButton[aNumber]]]; 
If[
                4 ≤ i ≤ 6, \ 
                AppendTo[secondRow, 
                  oneButton[aNumber]]]; 
If[
                7 ≤ i ≤ 9, \ 
                AppendTo[thirdRow, \ 
                  oneButton[aNumber]]], 
{i, 1, 
                9}]
];\)

makeButtonCell := 
          Cell[BoxData[GridBox[{firstRow, secondRow, thirdRow}]], 
            CellTags -> picturePlace];

createGameWindow := 
          Module[{}, 
If[! ValueQ[theGameWindow], 
                theGameWindow = 
                  NotebookCreate[WindowSize -> {450, 600},  
                    WindowTitle ->  "Let's Play Set!",  
                    FontSize ->  11,  Background ->  Honeydew,  
                    FontColor ->  
                      RGBColor[ .2,  .2,  .2]]];
];

drawButton := 
        Module[{nb}, 
          nb = theGameWindow; 
NotebookFind[nb, 
            picturePlace, All, CellTags]; 
NotebookWrite[
            nb, makeButtonCell, All];];

Non-working attempts with background switching

Below is one of Melanie's attempts at background switching.  She also tried frames and things.  Julie worked on this once or twice too, but unfortunately did not save a copy of her progress.  We eventually gave up on this part as being not vital to the program.

init:=Module[{},
buttonPushed = False;
number;
winOrLose = 0;
cardsChosen = {};
makeButton;
drawButton;

];

number := 
Module[{q}, 
chosen = 
              Table[i, {i, 1, 
                  27}]; 
newchosen = {}; 
Do[
              q = Random[
                  Integer, {1, Length[chosen]}]; 
AppendTo[
                newchosen, chosen[[q]]]; 
chosen = 
                Drop[chosen, {q}], {i, 1, 27}]; 
Return[
              newchosen];

];

fct[someNumber_]:=Module[{},
newNumber = someNumber;
Print[newNumber];
AppendTo[cardsChosen, newNumber];
winOrLose++;
setQ;
\(If[winOrLose == 3, \ 
                      Print["Three cards chosen."]; 
winOrLose = 
                        0, 
Print["You have " <> 
                          ToString[
                            3 - winOrLose] <> " more cards to choose."]]\)
buttonPushed=! buttonPushed;
If[buttonPushed, 
                    theBackground = RGBColor[0,  0,  0] , 
                    theBackground =  RGBColor[1,  1,  1] ];
];

setQ:=Module[{},  
While[Length[cardsChosen] == 3,
If[Mod[
                          cardsChosen[[1]] + cardsChosen[[2]] + 
                            cardsChosen[[3]], 3] == 0,
  \(Print["cards add up to " <> 
                          ToString[
                            Mod[cardsChosen[\([1]\)] + cardsChosen[\([2]\)] + 
                                cardsChosen[\([3]\)], 
                              3]]]; 
cardsChosen = {}; 
Print["That's a set.  Good job."]\),
  \(Print["cards add up to " <> 
                          ToString[
                            Mod[cardsChosen[\([1]\)] + cardsChosen[\([2]\)] + 
                                cardsChosen[\([3]\)], 
                              3]]]; 
cardsChosen = {}; 
Print["Sorry, that's not a set."];\)
]
]
];

oneButton[aNumber_]:=ButtonBox[Cell[
                GraphicsData["PostScript", DisplayString[theOne]]],ButtonFunction :> fct[aNumber],ButtonEvaluator -> Automatic,Active -> True,ButtonStyle -> "None", Background -> theBackground  ];

\(makeButton := 
          Module[{}, 
firstRow = {}; 
secondRow = {}; 
thirdRow = {}; 
Do[
              aNumber = 
                newchosen[\([i]\)];  (*picks\ the\ first\ number\ from\ our\ "shuffled deck"*) 
theOne = 
                listOPicks[\([aNumber]\)]; \  (*Finds\ the\ picture\ that\ equates\ to\ it*) 
If[1 ≤ i ≤ 3, \ 
                AppendTo[firstRow, 
                  oneButton[aNumber]]]; 
If[
                4 ≤ i ≤ 6, \ 
                AppendTo[secondRow, 
                  oneButton[aNumber]]]; 
If[
                7 ≤ i ≤ 9, \ 
                AppendTo[thirdRow, \ 
                  oneButton[aNumber]]], 
{i, 1, 
                9}]
];\)

makeButtonCell := 
          Cell[BoxData[GridBox[{firstRow, secondRow, thirdRow}]], 
            CellTags -> picturePlace];

drawButton := 
        Module[{nb}, 
          nb = SelectedNotebook[]; 
NotebookFind[nb, 
            picturePlace, All, CellTags]; 
NotebookWrite[
            nb, makeButtonCell, All];];

init

Okay, I'm sure you're sick of looking at old versions...Here's the real one!  The whole thing!

Welcome to SET!  To Play, please observe the following:
   
   Opening the Game: 
    1.Place your cursor next to the phrase engageSetYo and press Shift+Return or Enter.
    2. A box will come up asking whether or not you would like to initialize cells.  Click Yes.
    3. A new window will open with a layout of 12 cards.  
    4. The rules will also open in a new window.  Pay attention to them.

Pictures

Off[General::spell1];
<< Graphics`Graphics`;
<< Graphics`Colors`;

\(Rules := 
          Module[{}, 
Cell[
              TextData[{StyleBox[" What is a Set?:", 
                    FontFamily -> "Chalkboard", FontSize -> 16, 
                    FontWeight -> "Bold"], "
", 
                  StyleBox["    First,  you must know what defines a set.  
    There are four categories:
      1. COLOR - green, red, purple
      2. SHAPE - oval, diamond, hourglass
      3. SHADING - filled, empty, crossed
      4. NUMBER - one, two, three
   A set contains three cards.  The images on the cards must be either all the same or all different in each category. Remember: it must be so in ALL 4 CATEGORIES!", 
                    FontFamily -> "Comic Sans MS"], "
   
", 
                  StyleBox[" ", FontFamily -> "Chalkboard"], 
                  StyleBox["  ", FontFamily -> "Chalkboard", 
                    FontSize -> 16], 
                  StyleBox["Playing the Game:", 
                    FontFamily -> "Chalkboard", FontSize -> 16, 
                    FontWeight -> "Bold"], "
", 
                  StyleBox["   1. Locate a set.
   2. Click on the three cards that make up the set.
   3. If the cards are indeed a set, those three cards will be replaced.
   4. Keep playing.
   5. Smiley Faces do not count as cards!
   ", FontFamily -> "Comic Sans MS"], "
", 
                  StyleBox["   ", FontFamily -> "Chalkboard", 
                    FontWeight -> "Bold"], 
                  StyleBox["Notes:", FontFamily -> "Chalkboard", 
                    FontSize -> 16, 
                    FontWeight -> "Bold"], "
", 
                  StyleBox["   1. If you absolutely cannot find a set, click on one card three times.  This will replace that card with a new one, hopefully with one that will be useful.
   2. If you delete the text at the bottom of the window, make sure to reselect the game cell before clicking on new cards.  Otherwise, it will explode.
           We don't want that.  We care for you.  ", 
                    FontFamily -> "Comic Sans MS"]}], "Text"]];\)

\(\(\(greenFilledDiamondOne := 
        Graphics[{RGBColor[0,  .5, 0], 
            Polygon[{{1, 0}, {1.05, 1}, {1, 2}, \ { .95, 
                  1}}]}, \ \ AspectRatio -> 3/2, 
          ImageSize -> \ {65, 65}, \ Background -> Yellow];\)\(
\)
    \)\)

\(\(\(redFilledDiamondOne := 
        Graphics[{RGBColor[ .8, 0, 0], 
            Polygon[{{1, 0}, {1.05, 1}, {1, 2}, \ { .95, 
                  1}}]}, \ \ AspectRatio -> 3/2, 
          ImageSize -> \ \ {65, 65}, \ 
          Background -> Yellow];\)\(
\)
    \)\)

\(\(\(purpleFilledDiamondOne := 
        Graphics[{RGBColor[ .5, 0,  .5], 
            Polygon[{{1, 0}, {1.05, 1}, {1, 2}, \ { .95, 
                  1}}]}, \ \ AspectRatio -> 3/2, \ 
          ImageSize -> \ \ {65, 65}, \ 
          Background -> Yellow];\)\(
\)
    \)\)

\(\(\(greenEmptyDiamondOne := 
        Graphics[{Thickness[ .1], RGBColor[0,  .5, 0], 
            Line[{{1, 0}, {1.05, 1}, {1, 2}, \ { .95, 1}, \ {1, 
                  0}}]}, \ \ AspectRatio -> 3/2, 
          ImageSize -> \ \ {65, 65}, \ 
          Background -> Yellow];\)\(
\)
    \)\)

redEmptyDiamondOne :=  
        Graphics[{Thickness[ .1], RGBColor[ .8, 0, 0], 
            Line[{{1, 0}, {1.05, 1}, {1, 2},  { .95, 1},  {1, 0}}]},  
          AspectRatio -> 3/2,   ImageSize ->   {65, 65},  
          Background -> Yellow];

\(\(\(purpleEmptyDiamondOne := 
        Graphics[{Thickness[ .1], RGBColor[ .5, \ 0, \  .5], 
            Line[{{1, 0}, {1.05, 1}, {1, 2}, \ { .95, 1}, \ {1, 0}}]}, \ 
          AspectRatio -> 3/2, \ \ ImageSize -> \ \ {65, 65}, \ 
          Background -> Yellow];\)\(
\)
    \)\)

greenCrossedDiamondOne := 
        Graphics[{Thickness[ .1], RGBColor[0,  .5, 0], 
            Line[{{1, 0}, {1.05, 1}, {1, 2},  { .95, 1},  {1, 0}}],  
            Line[{{1.05,  1},  { .95,  1}}],  
            Line[{{1, 0},  {1, 1.9}}]},   AspectRatio -> 3/2, 
          ImageSize ->   {65, 65},  
          Background -> Yellow];

\(\(\(redCrossedDiamondOne := 
        Graphics[{Thickness[ .1], RGBColor[ .8, 0, 0], 
            Line[{{1, 0}, {1.05, 1}, {1, 2}, \ { .95, 1}, \ {1, 0}}], \ 
            Line[{{1.05, \ 1}, \ { .95, \ 1}}], \ 
            Line[{{1, 0}, \ {1, 1.9}}]}, \ AspectRatio -> 3/2, \ 
          ImageSize -> \ \ {65, 65}, \ 
          Background -> Yellow];\)\(
\)
    \)\)

purpleCrossedDiamondOne := 
        Graphics[{Thickness[ .1], RGBColor[ .5, 0,  .5], 
            Line[{{1, 0}, {1.05, 1}, {1, 2},  { .95, 1},  {1, 0}}],  
            Line[{{1.05,  1},  { .95,  1}}],  
            Line[{{1, 0},  {1, 1.9}}]},   AspectRatio -> 3/2, 
          ImageSize ->   {65, 65},  
          Background -> Yellow];

greenFilledOvalOne := 
Graphics[{RGBColor[0,  .5, 
              0], Disk[{0, 0}, { .8, 1.5}]}, AspectRatio -> 1.6, 
          Axes -> False,  ImageSize ->   {65, 65},  
          Background -> Yellow];

redFilledOvalOne := 
Graphics[{RGBColor[ .8, 0, 0], 
            Disk[{0, 0}, { .8, 1.5}]}, AspectRatio -> 1.6, 
          Axes -> False,  ImageSize ->   {65, 65},  
          Background -> Yellow];

purpleFilledOvalOne := 
Graphics[{RGBColor[ .5, 
              0,  .5], Disk[{0, 0}, { .8, 1.5}]}, AspectRatio -> 1.6, 
          Axes -> False,  ImageSize -> {65, 65},  
          Background -> Yellow];

greenEmptyOvalOne :=    

Graphics[{Thickness[ .15], 
            RGBColor[0,   .5,  0],  
            Circle[{0, 0},  { .8,  
                1.5}]}, 
AspectRatio -> 1.6,  
          ImageSize ->  {65, 65},  
          Background -> Yellow];

redEmptyOvalOne :=    

Graphics[{Thickness[ .15], 
            RGBColor[ .8,  0,  0],  
            Circle[{0, 0},  { .8,  
                1.5}]}, 
AspectRatio -> 1.6,  
          ImageSize ->  {65, 65},  
          Background -> Yellow];

purpleEmptyOvalOne :=    

Graphics[{Thickness[ .15], 
            RGBColor[ .5, 0,  .5],  
            Circle[{0, 0},  { .8,  
                1.5}]}, 
AspectRatio -> 1.6,  
          ImageSize ->  {65, 65},  
          Background -> Yellow];

greenCrossedOvalOne :=   (*Makes green oval with cross  -  
            close enough to being shaded*) 

Graphics[{Thickness[ .15], RGBColor[0,   .5,  0],  
            Circle[{0, 0},  { .8,  1.5}],  
            Line[{{- .8, 0},  { .8, 0}}],  
            Line[{{0,  -1.5},  {0,  
                  1.5}}]}, 
AspectRatio -> 1.6,  
          ImageSize ->  {65, 65},  Background -> Yellow,  
          Axes -> False];

redCrossedOvalOne :=   (*Makes red oval with cross  -  
            close enough to being shaded*) 

Graphics[{Thickness[ .15], RGBColor[ .8,  0,  0],  
            Circle[{0, 0},  { .8,  1.5}],  
            Line[{{- .8, 0},  { .8, 0}}],  
            Line[{{0,  -1.5},  {0,  
                  1.5}}]}, 
AspectRatio -> 1.6,  
          ImageSize ->  {65, 65},  Axes -> False,  
          Background -> Yellow];

purpleCrossedOvalOne :=    
Graphics[{Thickness[ .15], 
            RGBColor[ .5,  0,  .5],  Circle[{0, 0},  { .8,  1.5}],  
            Line[{{- .8, 0},  { .8, 0}}],  
            Line[{{0,  -1.5},  {0,  
                  1.5}}]}, 
AspectRatio -> 1.6,  
          ImageSize ->  {65, 65},  Axes -> False,  
          Background -> Yellow];

greenFilledThingyOne := 
Graphics[
{RGBColor[0,  .5, 
              0], 
Polygon[
{{0, 
                  0},  {1, 0},  {0, 2},  {1, 
                  2}}
                  ]}, 
 AspectRatio -> 3/2, 
 
          ImageSize ->  {65, 65},  
          Background -> 
            Yellow
];

\(\(\(redFilledThingyOne := 
Graphics[
{RGBColor[ .8, 0, 
              0], 
Polygon[
{{0, 
                  0}, \ {1, 0}, \ {0, 2}, \ {1, 
                  2}}
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ]}, 
\ AspectRatio -> 3/2, 
\ 
          ImageSize -> \ {65, 65}, \ 
          Background -> Yellow
];\)\(
\)
    \)\)

purpleFilledThingyOne := 
Graphics[
{RGBColor[ .5, 
              0,  .5], 
Polygon[
{{0, 
                  0},  {1, 0},  {0, 2},  {1, 
                  2}}
                  ]}, 
 AspectRatio -> 3/2, 
 
          ImageSize ->  {65, 65},  
          Background -> 
            Yellow
];

\(\(\(greenEmptyThingyOne := 
Graphics[
{Thickness[ .1], 
            RGBColor[0,  .5, 
              0], 
Line[
{{0, 0}, \ {1, 
                  0}, \ {0, 2}, \ {1, 2}, \ {0, 
                  0}}
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ]}, 
\ AspectRatio -> 3/2, 
\ 
          ImageSize -> \ {65, 65}, \ 
          Background -> Yellow
];\)\(
\)
    \)\)

redEmptyThingyOne := 
Graphics[
{Thickness[ .1], 
            RGBColor[ .8, 0, 
              0], 
Line[
{{0, 0},  {1, 
                  0},  {0, 2},  {1, 2},  {0, 
                  0}}
                  ]}, 
 AspectRatio -> 3/2, 
 
          ImageSize ->  {65, 65},  
          Background -> 
            Yellow
];

\(\(\(purpleEmptyThingyOne := 
Graphics[
{Thickness[ .1], 
            RGBColor[ .5, 
              0,  .5], 
Line[
{{0, 
                  0}, \ {1, 0}, \ {0, 2}, \ {1, 2}, \ {0, 
                  0}}
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ]}, 
\ AspectRatio -> 3/2, 
\ 
          ImageSize -> \ {65, 65}, \ 
          Background -> Yellow
];\)\(
\)
    \)\)

\(\(\(greenCrossedThingyOne := 
Graphics[
{Thickness[ .1], 
            RGBColor[0,  .5, 
              0], 
Line[
{{0, 0}, \ {1, 
                  0}, \ {0, 2}, \ {1, 2}, \ {0, 
                  0}}
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ], 
Line[{{ .5, 0}, \ { .5, 
                  2}}], 
Line[{{ .25, \  .35}, \ { .75,  .35}}], 
Line[{{ .25, 1.6}, \ { .75, \ 
                  1.6}}]
}, 
\ 
          AspectRatio -> 3/2, 
\ 
          ImageSize -> \ {65, 65}, \ 
          Background -> Yellow
];\)\(
\)
    \)\)

\(\(\(redCrossedThingyOne := 
Graphics[
{Thickness[ .1], 
            RGBColor[ .8, 0, 
              0], 
Line[
{{0, 0}, \ {1, 
                  0}, \ {0, 2}, \ {1, 2}, \ {0, 
                  0}}
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ], 
Line[{{ .5, 0}, \ { .5, 
                  2}}], 
Line[{{ .25, \  .35}, \ { .75,  .35}}], 
Line[{{ .25, 1.6}, \ { .75, \ 
                  1.6}}]
}, 
\ 
          AspectRatio -> 3/2, 
\ 
          ImageSize -> \ {65, 65}, \ 
          Background -> Yellow
];\)\(
\)
    \)\)

purpleCrossedThingyOne := 
Graphics[
{Thickness[ .1], 
            RGBColor[ .5, 
              0,   .5], 
Line[
{{0, 
                  0},  {1, 0},  {0, 2},  {1, 2},  {0, 
                  0}}
                  ], 
Line[{{ .5, 0},  { .5, 
                  2}}], 
Line[{{ .25,   .35},  { .75,  .35}}], 
Line[{{ .25, 1.6},  { .75,  
                  1.6}}]
}, 
 
          AspectRatio -> 3/2, 
 
          ImageSize ->  {65, 65},  
          Background -> Yellow
];

greenFilledDiamondTwo := 
        GraphicsArray[{greenFilledDiamondOne,  greenFilledDiamondOne},  
          ImageSize ->  {130, 65},  
          Background -> Yellow];

redFilledDiamondTwo := 
        GraphicsArray[{redFilledDiamondOne,  redFilledDiamondOne},  
          ImageSize ->  {130, 65}];

purpleFilledDiamondTwo := 
        GraphicsArray[{purpleFilledDiamondOne,  purpleFilledDiamondOne},  
          ImageSize ->  {130, 65}];

greenEmptyDiamondTwo := 
        GraphicsArray[{greenEmptyDiamondOne,  greenEmptyDiamondOne},  
          ImageSize ->  {130, 65}];

redEmptyDiamondTwo := 
        GraphicsArray[{redEmptyDiamondOne,  redEmptyDiamondOne},  
          ImageSize ->  {130, 65}];

purpleEmptyDiamondTwo := 
        GraphicsArray[{purpleEmptyDiamondOne,  purpleEmptyDiamondOne},  
          ImageSize ->  {130, 65}];

greenCrossedDiamondTwo := 
        GraphicsArray[{greenCrossedDiamondOne,  greenCrossedDiamondOne},  
          ImageSize ->  {130, 65}];

redCrossedDiamondTwo := 
        GraphicsArray[{redCrossedDiamondOne,  redCrossedDiamondOne},  
          ImageSize ->  {130, 65}];

purpleCrossedDiamondTwo := 
        GraphicsArray[{purpleCrossedDiamondOne,  purpleCrossedDiamondOne},  
          ImageSize ->  {130, 65}];

greenFilledOvalTwo := 
        GraphicsArray[{greenFilledOvalOne,  greenFilledOvalOne},  
          ImageSize ->  {130, 65}];

redFilledOvalTwo := 
        GraphicsArray[{redFilledOvalOne,  redFilledOvalOne},  
          ImageSize ->  {130, 65}];

purpleFilledOvalTwo := 
        GraphicsArray[{purpleFilledOvalOne,  purpleFilledOvalOne},  
          ImageSize ->  {130, 65}];

greenEmptyOvalTwo := 
        GraphicsArray[{greenEmptyOvalOne,  greenEmptyOvalOne},  
          ImageSize ->  {130, 65}];

\(\(redEmptyOvalTwo := 
        GraphicsArray[{redEmptyOvalOne, \ redEmptyOvalOne}, \ 

          ImageSize -> \ {130, 65}];\)\)

purpleEmptyOvalTwo := 
        GraphicsArray[{purpleEmptyOvalOne,  purpleEmptyOvalOne},  
          ImageSize ->  {130, 65}];

greenCrossedOvalTwo := 
        GraphicsArray[{greenCrossedOvalOne,  greenCrossedOvalOne},  
          ImageSize ->  {130, 65}];

redCrossedOvalTwo := 
        GraphicsArray[{redCrossedOvalOne,  redCrossedOvalOne},  
          ImageSize ->  {130, 65}];

purpleCrossedOvalTwo := 
        GraphicsArray[{purpleCrossedOvalOne,  purpleCrossedOvalOne},  
          ImageSize ->  {130, 65}];

greenFilledThingyTwo := 
        GraphicsArray[{greenFilledThingyOne,  greenFilledThingyOne},  
          ImageSize ->  {130, 65}];

redFilledThingyTwo := 
        GraphicsArray[{redFilledThingyOne,  redFilledThingyOne},  
          ImageSize ->  {130, 65}];

purpleFilledThingyTwo := 
        GraphicsArray[{purpleFilledThingyOne,  purpleFilledThingyOne},  
          ImageSize ->  {130, 65}];

greenEmptyThingyTwo := 
        GraphicsArray[{greenEmptyThingyOne,  greenEmptyThingyOne},  
          ImageSize ->  {130, 65}];

redEmptyThingyTwo := 
        GraphicsArray[{redEmptyThingyOne,  redEmptyThingyOne},  
          ImageSize ->  {130, 65}];

purpleEmptyThingyTwo := 
        GraphicsArray[{purpleEmptyThingyOne,  purpleEmptyThingyOne},  
          ImageSize ->  {130, 65}];

greenCrossedThingyTwo := 
        GraphicsArray[{greenCrossedThingyOne,  greenCrossedThingyOne},  
          ImageSize ->  {130, 65}];

redCrossedThingyTwo := 
        GraphicsArray[{redCrossedThingyOne,  redCrossedThingyOne},  
          ImageSize ->  {130, 65}];

purpleCrossedThingyTwo := 
        GraphicsArray[{purpleCrossedThingyOne,  purpleCrossedThingyOne},  
          ImageSize ->  {130, 65}];

greenFilledDiamondThree := 
        GraphicsArray[{greenFilledDiamondOne,  greenFilledDiamondOne,  
            greenFilledDiamondOne},  
          ImageSize ->  {195, 65}];

redFilledDiamondThree := 
        GraphicsArray[{redFilledDiamondOne,  redFilledDiamondOne,  
            redFilledDiamondOne},  
          ImageSize ->  {195, 65}];

purpleFilledDiamondThree := 
        GraphicsArray[{purpleFilledDiamondOne,  purpleFilledDiamondOne,  
            purpleFilledDiamondOne},  
          ImageSize ->  {195, 65}];

greenEmptyDiamondThree := 
        GraphicsArray[{greenEmptyDiamondOne,  greenEmptyDiamondOne,  
            greenEmptyDiamondOne},  
          ImageSize ->  {195, 65}];

redEmptyDiamondThree := 
        GraphicsArray[{redEmptyDiamondOne,  redEmptyDiamondOne,  
            redEmptyDiamondOne},  
          ImageSize ->  {195, 65}];

purpleEmptyDiamondThree := 
        GraphicsArray[{purpleEmptyDiamondOne,  purpleEmptyDiamondOne,  
            purpleEmptyDiamondOne},  
          ImageSize ->  {195, 65}];

greenCrossedDiamondThree := 
        GraphicsArray[{greenCrossedDiamondOne,  greenCrossedDiamondOne,  
            greenCrossedDiamondOne},  
          ImageSize ->  {195, 65}];

redCrossedDiamondThree := 
        GraphicsArray[{redCrossedDiamondOne,  redCrossedDiamondOne,  
            redCrossedDiamondOne},  
          ImageSize ->  {195, 65}];

purpleCrossedDiamondThree := 
        GraphicsArray[{purpleCrossedDiamondOne,  purpleCrossedDiamondOne,  
            purpleCrossedDiamondOne},  
          ImageSize ->  {195, 65}];

greenFilledOvalThree := 
        GraphicsArray[{greenFilledOvalOne,  greenFilledOvalOne,  
            greenFilledOvalOne},  
          ImageSize ->  {195, 65}];

redFilledOvalThree := 
        GraphicsArray[{redFilledOvalOne,  redFilledOvalOne,  
            redFilledOvalOne},  ImageSize ->  {195, 65}];

purpleFilledOvalThree := 
        GraphicsArray[{purpleFilledOvalOne,  purpleFilledOvalOne,  
            purpleFilledOvalOne},  
          ImageSize ->  {195, 65}];

greenEmptyOvalThree := 
        GraphicsArray[{greenEmptyOvalOne,  greenEmptyOvalOne,  
            greenEmptyOvalOne},  
          ImageSize ->  {195, 65}];

redEmptyOvalThree := 
        GraphicsArray[{redEmptyOvalOne,  redEmptyOvalOne,  
            redEmptyOvalOne},  ImageSize ->  {195, 65}];

purpleEmptyOvalThree := 
        GraphicsArray[{purpleEmptyOvalOne,  purpleEmptyOvalOne,  
            purpleEmptyOvalOne},  
          ImageSize ->  {195, 65}];

greenCrossedOvalThree := 
        GraphicsArray[{greenCrossedOvalOne,  greenCrossedOvalOne,  
            greenCrossedOvalOne},  
          ImageSize ->  {195, 65}];

redCrossedOvalThree := 
        GraphicsArray[{redCrossedOvalOne,  redCrossedOvalOne,  
            redCrossedOvalOne},  
          ImageSize ->  {195, 65}];

purpleCrossedOvalThree := 
        GraphicsArray[{purpleCrossedOvalOne,  purpleCrossedOvalOne,  
            purpleCrossedOvalOne},  
          ImageSize ->  {195, 65}];

greenFilledThingyThree := 
        GraphicsArray[{greenFilledThingyOne,  greenFilledThingyOne,  
            greenFilledThingyOne},  
          ImageSize ->  {195, 65}];

redFilledThingyThree := 
        GraphicsArray[{redFilledThingyOne,  redFilledThingyOne,  
            redFilledThingyOne},  
          ImageSize ->  {195, 65}];

purpleFilledThingyThree := 
        GraphicsArray[{purpleFilledThingyOne,  purpleFilledThingyOne,  
            purpleFilledThingyOne},  
          ImageSize ->  {195, 65}];

greenEmptyThingyThree := 
        GraphicsArray[{greenEmptyThingyOne,  greenEmptyThingyOne,  
            greenEmptyThingyOne},  
          ImageSize ->  {195, 65}];

redEmptyThingyThree := 
        GraphicsArray[{redEmptyThingyOne,  redEmptyThingyOne,  
            redEmptyThingyOne},  
          ImageSize ->  {195, 65}];

purpleEmptyThingyThree := 
        GraphicsArray[{purpleEmptyThingyOne,  purpleEmptyThingyOne,  
            purpleEmptyThingyOne},  
          ImageSize ->  {195, 65}];

greenCrossedThingyThree := 
        GraphicsArray[{greenCrossedThingyOne,  greenCrossedThingyOne,  
            greenCrossedThingyOne},  
          ImageSize ->  {195, 65}];

redCrossedThingyThree := 
        GraphicsArray[{redCrossedThingyOne,  redCrossedThingyOne,  
            redCrossedThingyOne},  
          ImageSize ->  {195, 65}];

purpleCrossedThingyThree := 
        GraphicsArray[{purpleCrossedThingyOne,  purpleCrossedThingyOne,  
            purpleCrossedThingyOne},  
          ImageSize ->  {195, 65}];

eyes = 
        Graphics[{Disk[{0, 0}, 1], Disk[{3, 0}, 1]}, 
          ImageSize -> 65];
mouth = 
        Graphics[{Thickness[ .10],  Line[{{0, 1}, {1.5, 0}, {3, 1}}]},  
          ImageSize -> 65,  AspectRatio -> 1/4];
face := 
        GraphicsArray[{{eyes}, {mouth}},  
          ImageSize -> 65];

listOPicks={{greenFilledDiamondOne, green, filled, diamond,  
            one}, 
{ redFilledDiamondOne, red, filled, 
            diamond,  one},  
{purpleFilledDiamondOne, 
            purple,  filled,  diamond,  
            one},  
{greenEmptyDiamondOne, green,  
            empty,  diamond,  
            one},  
{redEmptyDiamondOne,  red,  empty,  
            diamond,  one},  
{purpleEmptyDiamondOne,  
            purple,  empty,  diamond,  
            one}, 
{greenCrossedDiamondOne,  green,  
            crossed,  diamond,  
            one}, 
{redCrossedDiamondOne,  red,  
            crossed,  diamond,  
            one}, 
{purpleCrossedDiamondOne,  purple,  
            crossed,  diamond,  
            one}, 
{greenFilledOvalOne,  green,  
            filled,  oval,  one}, 
{redFilledOvalOne,  
            red,  filled,  oval,  
            one}, 
{purpleFilledOvalOne,  purple,  
            filled,  oval,  one}, 
{greenEmptyOvalOne,  
            green,  empty,  oval,  
            one}, 
{redEmptyOvalOne,  red,  empty,  
            oval,  one}, 
{purpleEmptyOvalOne,  purple,  
            empty,  oval,  one}, 
{greenCrossedOvalOne, 
            green,  crossed,  oval,  
            one}, 
{redCrossedOvalOne,  red,  crossed,  
            oval,  one}, 
{purpleCrossedOvalOne, purple,  
            crossed,  oval,  
            one}, 
{greenFilledThingyOne,  green,  
            filled,  thingy,  
            one}, 
{redFilledThingyOne,  red,  filled,  
            thingy,  one}, 
{purpleFilledThingyOne,  
            purple,  filled,  thingy,  
            one}, 
{greenEmptyThingyOne,  green,  
            empty,  thingy,  one}, 
{redEmptyThingyOne,  
            red,  empty,  thingy,  
            one}, 
{purpleEmptyThingyOne,  purple,  
            empty,  thingy,  
            one}, 
{greenCrossedThingyOne,  green,  
            crossed,  thingy,  
            one}, 
{redCrossedThingyOne,  red,  
            crossed,  thingy,  
            one}, 
{purpleCrossedThingyOne, purple,  
            crossed,  thingy,  
            one}, 
{greenFilledDiamondTwo, green, filled, 
            diamond,  two}, 
{ redFilledDiamondTwo, red, 
            filled, diamond,   two},  
{purpleFilledDiamondTwo, purple,  filled,  
            diamond,   two},  
{greenEmptyDiamondTwo, 
            green,  empty,  
            diamond,   two},  
{redEmptyDiamondTwo,  
            red,  empty,  
            diamond,   two},  
{purpleEmptyDiamondTwo,  
            purple,  empty,  
            diamond,   two}, 
{greenCrossedDiamondTwo,  
            green,  crossed,  
            diamond,   two}, 
{redCrossedDiamondTwo,  
            red,  crossed,  
            diamond,   two}, 
{purpleCrossedDiamondTwo,  
            purple,  crossed,  
            diamond,   two}, 
{greenFilledOvalTwo,  
            green,  filled,  
            oval,   two}, 
{redFilledOvalTwo,  red,  
            filled,  
            oval,   two}, 
{purpleFilledOvalTwo,  
            purple,  filled,  
            oval,   two}, 
{greenEmptyOvalTwo,  green,  
            empty,  oval,   two}, 
{redEmptyOvalTwo,  
            red,  empty,  
            oval,   two}, 
{purpleEmptyOvalTwo,  
            purple,  empty,  oval,  
            two}, 
{greenCrossedOvalTwo, green,  
            crossed,  
            oval,   two}, 
{redCrossedOvalTwo,  red,  
            crossed,  
            oval,   two}, 
{purpleCrossedOvalTwo, 
            purple,  crossed,  
            oval,   two}, 
{greenFilledThingyTwo,  
            green,  filled,  
            thingy,   two}, 
{redFilledThingyTwo,  
            red,  filled,  
            thingy,   two}, 
{purpleFilledThingyTwo,  
            purple,  filled,  
            thingy,   two}, 
{greenEmptyThingyTwo,  
            green,  empty,  
            thingy,   two}, 
{redEmptyThingyTwo,  red,  
            empty,  
            thingy,   two}, 
{purpleEmptyThingyTwo,  
            purple,  empty,  
            thingy,   two}, 
{greenCrossedThingyTwo,  
            green,  crossed,  
            thingy,   two}, 
{redCrossedThingyTwo,  
            red,  crossed,  
            thingy,   two}, 
{purpleCrossedThingyTwo, 
            purple,  crossed,  
            thingy,   two}, 
{greenFilledDiamondThree, 
            green, filled, diamond,  three}, 
{ 
            redFilledDiamondThree, red, filled, 
            diamond,   three},  
{purpleFilledDiamondThree, purple,  filled,  
            diamond,   three},  
{greenEmptyDiamondThree, green,  empty,  
            diamond,   three},  
{redEmptyDiamondThree,  red,  empty,  
            diamond,   three},  
{purpleEmptyDiamondThree,  purple,  empty,  
            diamond,   three}, 
{greenCrossedDiamondThree,  green,  crossed,  
            diamond,   three}, 
{redCrossedDiamondThree,  red,  crossed,  
            diamond,   three}, 
{purpleCrossedDiamondThree,  purple,  crossed,  
            diamond,   three}, 
{greenFilledOvalThree,  
            green,  filled,  
            oval,   three}, 
{redFilledOvalThree,  
            red,  filled,  
            oval,   three}, 
{purpleFilledOvalThree,  
            purple,  filled,  
            oval,   three}, 
{greenEmptyOvalThree,  
            green,  empty,  
            oval,   three}, 
{redEmptyOvalThree,  red,  
            empty,  
            oval,   three}, 
{purpleEmptyOvalThree,  
            purple,  empty,  oval,  
            three}, 
{greenCrossedOvalThree, green,  
            crossed,  
            oval,   three}, 
{redCrossedOvalThree,  
            red,  crossed,  
            oval,   three}, 
{purpleCrossedOvalThree, 
            purple,  crossed,  
            oval,   three}, 
{greenFilledThingyThree,  
            green,  filled,  
            thingy,   three}, 
{redFilledThingyThree,  
            red,  filled,  
            thingy,   three}, 
{purpleFilledThingyThree,  purple,  filled,  
            thingy,   three}, 
{greenEmptyThingyThree,  
            green,  empty,  
            thingy,   three}, 
{redEmptyThingyThree,  
            red,  empty,  
            thingy,   three}, 
{purpleEmptyThingyThree,  
            purple,  empty,  
            thingy,   three}, 
{greenCrossedThingyThree,  green,  crossed,  
            thingy,   three}, 
{redCrossedThingyThree,  
            red,  crossed,  
            thingy,   three}, 
{purpleCrossedThingyThree, 
            purple,  crossed,  
            thingy,   three}, 
{face,  we, are, 
            terribly, cool}   
};

The Program

engageSetYo:=Module[{},
Clear[theGameWindow];
Clear[theRuleWindow];   
number;   
buttonsClicked = 0;  (* so far,  
                  the number of cards that have been clicked is 0 *) 
cardsChosen = {};   
color = {};    
shading = {};   
shape = {};   
numPics = {};   
setq = False;   
theShapes = 
                Table[newchosen[[i]], {i, 1, 12}];  
maybeShapes = theShapes;    
newShapes = theShapes;    
theNext = 13;   (* 
                  This is the next card in newchosen .   When a card gets clicked,  
                  this replaces that card and increases by 1.  The following three set up the buttons,  create theGameWindow,  
                  and place the buttons in theGameWindow. *) 
makeButton; 
createGameWindow;
drawButton;
  
createRuleWindow;
writeRules;
];

number:=  
Module[{q}, 
chosen = 
            Table[i, {i, 1, 
                81}]; 
newchosen = {}; 
Do[
            q = Random[
                Integer, {1, Length[chosen]}]; 
AppendTo[
              newchosen, chosen[[q]]]; 
chosen = 
              Drop[chosen, {q}], {i, 1, 81}]; 
Return[
            newchosen];

];

fct[someNumber_]:=  
Module[{},
newNumber = someNumber;
  
Do[
                If[theShapes[[i]] == newNumber, 
                  numberPlace = i], {i, 1, 12}];
  
AppendTo[cardsChosen, newNumber];
AppendTo[color, 
                listOPicks[[newNumber, 2]]];
AppendTo[shading, 
                listOPicks[[newNumber, 3]]];
AppendTo[shape, 
                listOPicks[[newNumber, 4]]];
AppendTo[numPics, 
                listOPicks[[newNumber, 5]]];
buttonsClicked++;
If[theNext ≤ 81,    
newShapes = 
                    ReplacePart[newShapes, newchosen[[theNext]], 
                      numberPlace]; 
maybeShapes = 
                    newShapes; 
theNext++,
  
newShapes = 
                    ReplacePart[newShapes, 82, 
                      numberPlace]; 
maybeShapes = 
                    newShapes;];
If[buttonsClicked == 3,  
newSetQ;
If[setq == True,   
theShapes = 
                          maybeShapes; 
setq = False];
buttonsClicked = 0;
makeButton;
createGameWindow;
drawButton,
  
maybeShapes=theShapes;
];
];

newSetQ:=   
Module[{},
If[Length[cardsChosen] == 3,
If[
  
((ToString[color[[1]]] == 
                                ToString[color[[2]]] == 
                                ToString[
                                  color[[3]]]) || 
(ToString[color[[1]]] ≠  
                                ToString[color[[2]]] ≠  
                                ToString[
                                  color[[3]]])) && 
((ToString[shape[[1]]] == 
                                ToString[shape[[2]]] == 
                                ToString[
                                  shape[[3]]]) || 
(ToString[shape[[1]]] ≠  
                                ToString[shape[[2]]] ≠  
                                ToString[
                                  shape[[3]]])) && 
((ToString[shading[[1]]] == 
                                ToString[shading[[2]]] == 
                                ToString[
                                  shading[[3]]]) || 
(ToString[shading[[1]]] ≠  
                                ToString[shading[[2]]] ≠  
                                ToString[
                                  shading[[3]]])) && 
((ToString[numPics[[1]]] == 
                                ToString[numPics[[2]]] == 
                                ToString[
                                  numPics[[3]]]) || 
(ToString[numPics[[1]]] ≠  
                                ToString[numPics[[2]]] ≠  
                                ToString[numPics[[3]]])),
  
\(Print["That's a set. Good job!"]; 
areYouLame; 
setq = True\),
  
\(Print["Sorry, that's not a set."]; 
setq = False;\)
];
  
cardsChosen = {};
color = {};
shape = {};
shading = {};
numPics = {};]];

areYouLame:=    
Module[{}, 
If[
              Length[cardsChosen] == 3 && 
                cardsChosen[[1]] ==  
                  cardsChosen[[2]] ==  cardsChosen[[3]],  
              Print["Wait, no it's not.  You can't just pick the same card \
three times.  Try again."]];
];

oneButton[aNumber_]:=   
ButtonBox[
              Cell[GraphicsData["PostScript", DisplayString[theOne]]], 
              ButtonFunction :> fct[aNumber], 
              ButtonEvaluator -> Automatic, Active -> True, 
              ButtonStyle -> "None",  Background -> Yellow,  
              ButtonExpandable -> True];

makeButton:=   
Module[{},
firstRow = {};
secondRow = {};
thirdRow = {};
Do[aNumber = theShapes[[i]];  
theOne = 
                      listOPicks[[aNumber, 1]];  (*Finds the picture that equates to it*) 
If[
                      1 ≤ i ≤ 4,  
                      AppendTo[firstRow, oneButton[aNumber]]];   
If[
                      5 ≤ i ≤ 8,  
                      AppendTo[secondRow, oneButton[aNumber]]];
If[
                      9 ≤ i ≤ 12,  
                      AppendTo[thirdRow,  oneButton[aNumber]]],
{i, 1, 12}]
];

makeButtonCell:=   
Cell[
            BoxData[GridBox[{firstRow, secondRow, thirdRow}]], 
            CellTags -> picturePlace];

createGameWindow:=   
\(Module[{}, 
\(If[\(! ValueQ[theGameWindow]\), 
              theGameWindow = 
                NotebookCreate[WindowSize -> {700, 600}, \ 
                  WindowTitle -> \ "Let's Play Set!", \ 
                  FontSize -> \ 13, \ Background -> Orange, \ 
                  FontColor -> \ RGBColor[ .2,  .2,  .2], \ 
                  FontWeight -> "Bold"]];\)
]\);

drawButton:=   
Module[{nb}, 
          nb = theGameWindow; 
NotebookFind[nb, 
            picturePlace, All, CellTags]; 
NotebookWrite[
            nb, makeButtonCell, All];];

createRuleWindow:=   
\(Module[{}, 
\(If[\(! ValueQ[theRuleWindow]\), 
              theRuleWindow = 
                NotebookCreate[WindowSize -> {500, 500}, \ 
                  WindowTitle -> \ "Always Follow the Rules!", \ 
                  FontSize -> \ 14, \ Background -> ForestGreen, \ 
                  FontColor -> \ 
                    CadmiumLemon]];\)
]\);

writeRules:=  
Module[{nb},  
          nb = theRuleWindow; 
NotebookWrite[nb,  Rules,  
            All]];

Usage documentation (s?)

We decided it wasn't strictly necessary to document every inside bit of the main function because it is all commented, anyway.

engageSetYo::usage = "engageSetYo opens a rules window and a game \
window that allow you to play the enjoyable game of Set."

?engageSetYo

Scratch

engageSetYo