Spider.sav

Aus Franky
Wechseln zu: Navigation, Suche

I restored this article using the wayback machine [1]. It is about the format of saved games of Spider solitaire as shipped with Windows XP.

The intro mocks what you find when you enter "spider.sav" into a web search.

Intro

The File spider.sav, usually found in your user profile\My Documents is a very dangerous file. Due to a severe vulnerability in Spider Solitaire, a game shipped with MS Windows, this file appears whenever you save your game. You can test the severity of this vulnerability yourself: When you delete spider.sav, you wont be able to load your recent game into Spider Solitaire any more and you have to start all over.

file-format of spider.sav

This document describes the file format of spider.sav as produced by the XP version of spider solitaire. I'm German and have access to the German version only, thats why I use some confusing terms, e.g. I call the piles columns.

The spider.sav consists only of DWORDS (I prefer to call them int32), although most values are less than 104.

In the following, I assume the file has been read in into the (zero-based) array int32[] raw.

Suit values: 0 = clubs, 1 = diamonds, 2 = hearts, 3 = spades

raw[0x00]  Number of suits
raw[0x01]  Random seed
raw[0x02]  card count, excluding the undealt rows
raw[0x03]  card count, further excluding the completed runs
raw[0x04]  moves
raw[0x05]  dealt rows
raw[0x06]  complete runs of clubs
raw[0x07]  complete runs of diamonds
raw[0x08]  complete runs of hearts
raw[0x09]  complete runs of spades
raw[0x0a] to raw[0x11] (8 int32s) suit of n-th complete run or zero
raw[0x12]  datablock
raw[last]

Format of data block

10 times (for each column) { 
   n: the number of cards in this column
   hiddenCount: the number of face-down cards in this column
   data[n]: card data

} 

pseudo random number generator

The pseudo random number generator is the one built in in visual C++. The algorithm was found at http://www.codeproject.com/useritems/PRNG.asp

return (((randseed = randseed * 214013 + 2531011) >> 16) & 0x7fff); 

shuffle method

Well, I just present the java code snippet I wrote to emulate the shuffling

	boolean[] carddealt = new boolean[104];
	final int deckCount = 2; // final means const in C++ (in this context)
	de.genialitaet.visualc.Random prng = new Random(randseed);
	
	for(int i=0;i<carddealt.length; i++) {
		carddealt[i] = false;
	}
	for(int deckCounter = 0; deckCounter < deckCount; deckCounter++) {
		for(Suit suit : Suit.values()) { // 0 = clubs, 1 = diamonds, 2 = hearts, 3 = spades
			for(int rank=0; rank<=12; rank++) { // 0 = Ace, 1 = two, 12 = king
				int slot;
				do {
					slot = prng.rand() % 104;
				} while(carddealt[slot]);
				carddealt[slot] = true;
				cards.set(slot, new Card(rank,suit.convert(suitCount)));
			}
		}
	}

suit.convert converts all suits to spades if suitCount==1, black suit to spades and red to hearts if suitCount==2 and does not convert anything if suitCount==4.

methods

I did not use a disassembler or something similar to obtain this information. The only tools were a hex editor (opening spider.sav only) and spider.exe of course. After finding out that I have just to manipulate spider.sav to show all cards (deal all rows in spider, set hiddenCount to zero, I guessed right the visual C pseudo random number generator was used and experimented.

Solving Spider solitaire

I done my attempt at writing a spider solitaire solver. (It is too ugly, too slow and too memory intensive to allow download here...)

Emulating how I play Spider solitaire manually, I assign a 'chaos value' to each game state. Each move adds 1 to chaos, each face-down card 50, each card not fitting on the one below 23 (unless the lower card is an Ace an the upper a king - in this case we lose a free column for almost nothing),...

The solver searches the state space, taking the game state with the lowest chaos out of a priority queue and adding (almost) all possible follow-up moves (not processing a game state twice). The algorithm is similar to A*, but it violates the admissibility of the heuristic.

After 100000 states are processed this way, the queue is cleared and the 1000 best (i.e. lowest chaos) states are forced to deal a row (if allowed) and added to the queue again.

Works quite well, but there is enough space for vast improvements.