UNIX> cp -r /home/plank/Superball $HOMEThen you can run superball with:
UNIX> ~/Superball &You'll have to be on a machine that has tcl/tk installed (our lab machines will work, as will macintosh's. I haven't tested it on cygwin.) If the high score doesn't work, go into the file hscore and change "mozilla" to whatever web browser you have installed.
#ifndef _DISJOINT_
#define _DISJOINT_
typedef struct {
int *links;
int *sizes;
int *ranks;
int maxindex;
int nsets;
} DisjointSet;
extern DisjointSet *new_disjoint_set(int maxindex);
extern void free_disjoint_set(DisjointSet *dj);
extern void disjoint_makeset(DisjointSet *dj, int index);
extern int disjoint_union(DisjointSet *dj, int s1, int s2);
extern int disjoint_find(DisjointSet *dj, int index);
#endif
|
Note that sizes and ranks are only well defined for root nodes of sets (those whose value of links is -1).
I have a tcl/tk/shell-scripted Superball player at /home/plank/Superball. Simply copy that directory to your home directory:
UNIX> cp -r /home/plank/Superball $HOME
Then you can play it with ~/Superball/Superball. The high score probably won't work -- you'll have to change the open command in the file hscore to the name of your web browser.
Let's look at some screen shots. Suppose we fire up Superball:

The "goal" cells are marked with asterisks, and there are five non-empty cells. Our only legal action is to swap two cells -- I'm going to swap cells [6,3] and [7,5]. This will make those two blue cells contiguous. In the game, I do that by clicking on the two cells that I want to swap. Afterwards, five new cells are put on the screen. Here's the screen shot:

I do a bunch more swaps and end up with the following board: (In case you're wondering, I haven't really figured out this screen shot thing, but it should be clear enough).

I can score the red cells by clicking on cell [2,0] or [2,1] and then clicking "collect". This will score that group of nine red squares, which gets me 45 points (9*5), and three new cells will be added:

There are no cells to score here (the purple ones in the upper right-hand corner are only a group of four). So I revert to swapping. Suppose I keep doing so until I reach:

I'm in trouble -- I can score those purple ones in the upper right-hand corner, but when I'm done, and three new cells are filled in, there will be only four empty cells:

You'll note, even though there's a group of six light blue cells, none of them are in the goal squares, so I can't score them. I'm stuck -- I have to simply switch two cells, and the game will be over:

Oh well.
Now, try the interactive game player:
UNIX> cd /home/plank/cs140/Labs/LabD/ UNIX> sb-player usage: sb-player rows cols min-score-size colors player interactive(y|n) output(y|n) seed UNIX> sb-player 8 10 5 pbyrg - y y - Empty Cells: 75 Score: 0 ..b....... .......g.. **......** **......** Y*......** **..b...** ......y... .......... Your Move: SWAP 0 2 4 0 Empty Cells: 70 Score: 0 ..y....... ......yg.. **.....b** **..rp..** B*......** **..b...** ....y.y... .......... Your Move:It works the same way, only it's much more tedious. However, give it a try. When a letter is capitalized, it is on a goal cell. Dots and asterisks stand for empty cells -- asterisks are on the goal cells. Note, if you click on the Print Boards button in the tcl/tk game, it will print out each board on standard output. When you want to score a cell, you type SCORE row col. That cell must be a goal cell.

May be represented by the following text (in input-1.txt):
...yyryy.p y.rg.yppyp **gg.yrpPP GGgbgybp** R*bg.yrp*P G*gygyypY* yyybpby.pb .pgg.yp.bb |
When we run sb-read on it, we get the following:
UNIX> sb-read 8 10 5 pbyrg < input-1.txt Empty cells: 20 Non-Empty cells: 60 Number of pieces in goal cells: 8 Sum of their values: 33 UNIX>There are three purple pieces in goal cells, one yellow, three green and one red. That makes a total of 3*2 + 4 + 5 + 3*6 = 33.
You should take a look at sb-read.c. In particular, look at the Superball struct.
typedef struct {
int r;
int c;
int mss;
int empty;
int *board;
int *goals;
int *colors;
} Superball;
|
mss is min-score-size. empty is the number of empty cells in the board. board is an array of r * c integers. The element in [i,j] is in entry board[i*c+j], and is either '.', '*' or a lower case letter. goals is another array of r * c integers. It is equal to -1 if the cell is not a goal cell, and it is equal to the goal's index if it is a goal cell. Colors is an array of 256 elements, which should be indexed by a letter. Its value is the value of the letter (e.g. in the above example, colors['p'] = 2).
sb-read does all manner of error checking for you. It is a nice program on which to build your other programs.
UNIX> sb-analyze usage: sb-analyze rows cols min-score-size colors UNIX> sb-analyze 8 10 5 pbyrg < input-1.txt Scoring sets: Size: 10 Char: p Scoring Cell: 2,8 Size: 6 Char: g Scoring Cell: 3,0 UNIX>Note, each set must be printed exactly once, but in any order, and with any legal goal cell. Thus, the following output would also be ok:
UNIX> sb-analyze 8 10 5 pbyrg < input-1.txt Scoring sets: Size: 6 Char: g Scoring Cell: 3,1 Size: 10 Char: p Scoring Cell: 2,7 UNIX>Think about how you would use the disjoint sets data structure to implement this. I would recommend augmenting your Superball struct with a DisjointSet, and then having a procedure called analyze_superball(), which performs the analysis. Give this some thought -- it's a little subtle, but it's not that bad.
Here's another example:

This is in the file input-2.txt:
yyggyryybp ggrgpyppyp RBgggyrpPP GGgggybpPP RGygryrpBP YGyygyypYB yyybpbyppb ppggyypbbb |
UNIX> sb-analyze 8 10 5 pbyrg < input-2.txt Scoring sets: Size: 14 Char: g Scoring Cell: 5,1 Size: 15 Char: p Scoring Cell: 4,9 Size: 7 Char: y Scoring Cell: 5,0 Size: 5 Char: b Scoring Cell: 5,9 UNIX>
Note, if you have fewer than five pieces and cannot score any, you will lose the game -- you should do that by swapping two legal pieces so that the game can end.
The sb-player program takes as its 5th argument the name of a program that it will use for input. I also have three programs - sb-play, sb-play2 and sb-play3 in that directory. sb-play simply swaps two random cells until there are fewer than five empty, then it scores a set if it can. The other two are smarter, but are by no means the best one can do.
Here's sb-player running on sb-play2 (note, sb-player creates a temporary file, so you must run it from your own directory):
UNIX> /home/plank/cs140/Labs/LabD/sb-player 8 10 5 pbyrg /home/plank/cs140/Labs/LabD/sb-play2 y y - Empty Cells: 75 Score: 0 g......... .......... **......** *Pr.....** **......** **..p...** ........b. .......... Type Return for the next playNote, it waits for you to press the return key. When you do so, it will send the game board to /home/plank/cs140/Labs/LabD/sp-play2 and perform the output. Here's what happens:
Move is: SWAP 5 4 3 2 Empty Cells: 70 Score: 0 g........g .......y.. **......** *Pp.....** **......G* **..r...** ..g.....b. ........g. Type Return for the next playYou can bet that the next move will swap that b with one of the g's:
Move is: SWAP 6 8 0 0 Empty Cells: 65 Score: 0 b........g .......y.. **..b...** *Pp.g...** **.....gG* **..r...** ..g.....g. .p...p..g. Type Return for the next playAnd so on. If you run it with n for the 6th argument, it will simply run the program without your input:
UNIX> /home/plank/cs140/Labs/LabD/sb-player 8 10 5 pbyrg /home/plank/cs140/Labs/LabD/sb-play2 n y - Empty Cells: 75 Score: 0 .......... .......... **......** **y..y..** **......** *P......** .......... ......p.g. Move is: SWAP 3 5 3 2... a bunch of output skipped...
Empty Cells: 1 Score: 505 yyrrgggpyy grrbppg.yg GYbgygggPB GBggpgbpPB PPgggggrYB YBbybgpbYR pprrrggggr byyrppppgg Move is: SWAP 0 1 7 5 Game over. Final score = 505 UNIX>You'll note that even though there were no good moves at the end, the program did a final SWAP so that the game could finish.
If you run with the 7th argument as n, it will only print out the end result, and the last argument can specify a seed (it uses the current time if that argument is "-"), so that you can compare multiple players on the same game:
UNIX> /home/plank/cs140/Labs/LabD/sb-player 8 10 5 pbyrg /home/plank/cs140/Labs/LabD/sb-play n n 1 Game over. Final score = 38 UNIX> /home/plank/cs140/Labs/LabD/sb-player 8 10 5 pbyrg /home/plank/cs140/Labs/LabD/sb-play2 n n 1 Game over. Final score = 855 UNIX> /home/plank/cs140/Labs/LabD/sb-player 8 10 5 pbyrg /home/plank/cs140/Labs/LabD/sb-play3 n n 1 Game over. Final score = 2572 UNIX>It can take a while for these to run -- if it appears to be hanging, send the process a QUIT signal and it will print out what the current score is.
UNIX> sh run_multiple.sh 8 10 5 pbyrg sb-play 10 Run 1 - Score: 38 - Average 38.000 Run 2 - Score: 0 - Average 19.000 Run 3 - Score: 0 - Average 12.667 Run 4 - Score: 57 - Average 23.750 Run 5 - Score: 0 - Average 19.000 Run 6 - Score: 0 - Average 15.833 Run 7 - Score: 89 - Average 26.286 Run 8 - Score: 15 - Average 24.875 Run 9 - Score: 0 - Average 22.111 Run 10 - Score: 20 - Average 21.900 UNIX> sh run_multiple.sh 8 10 5 pbyrg sb-play2 10 Run 1 - Score: 855 - Average 855.000 Run 2 - Score: 979 - Average 917.000 Run 3 - Score: 650 - Average 828.000 Run 4 - Score: 833 - Average 829.250 Run 5 - Score: 832 - Average 829.800 Run 6 - Score: 3326 - Average 1245.833 Run 7 - Score: 1507 - Average 1283.143 Run 8 - Score: 3643 - Average 1578.125 Run 9 - Score: 610 - Average 1470.556 Run 10 - Score: 862 - Average 1409.700 UNIX> sh run_multiple.sh 8 10 5 pbyrg sb-play3 10 Run 1 - Score: 2572 - Average 2572.000 Run 2 - Score: 2708 - Average 2640.000 Run 3 - Score: 745 - Average 2008.333 Run 4 - Score: 424 - Average 1612.250 Run 5 - Score: 1888 - Average 1667.400 Run 6 - Score: 7140 - Average 2579.500 Run 7 - Score: 3475 - Average 2707.429 Run 8 - Score: 1701 - Average 2581.625 Run 9 - Score: 2699 - Average 2594.667 Run 10 - Score: 2291 - Average 2564.300 UNIX>Obviously, to get a meaningful average, many more runs (than 10) will be required.