home *** CD-ROM | disk | FTP | other *** search
Text File | 1998-06-19 | 6.1 KB | 227 lines | [TEXT/CWIE] |
- /*
- Problem 02 - Hower of Tanoi
-
- This problem is to solve a variant of the Tower of Hanoi puzzle. You remember
- the Tower of Hanoi, a board with three pegs, one of which has N disks of size
- 1, 2, 3, ... N, with the smallest disk at the top. In the standard puzzle, the
- goal is to move all of the disks from one peg to another peg, by repeatedly
- moving a disk from the top of one peg to another peg without ever placing a
- larger disk on top of a smaller disk.
-
- In our Hower of Tanoi problem, the objective and the constraints are the same,
- except that the disks on the first peg are initially in random order. You can
- still only move a smaller disk onto a larger disk.
-
- Your objective is output the moves required to place all the disks on peg 3 in
- order with the smallest disk at the top.
-
- Input specification
-
- The first line of the input file contains an integer M, M<1000, the number of
- disks in the problem. The next M lines contain the numbers 1 .. M, one number
- per line, randomly ordered, where the first number is the size of the top disk
- on peg 1, the second number is the size of the 2nd disk from the top, etc.
-
- Output specification
-
- The output is a sequence of lines, each representing a single move, consisting
- of the source peg number followed by a comma (',') followed by the destination
- peg number, followed by a return character.
-
- Sample input
-
- 2
- 2
- 1
-
- Sample output
-
- 1,3
- 1,3
- */
-
- #undef DEBUG
- #define NDEBUG
-
- #include "Solution.h"
- #include <assert.h>
- #include <string>
- #include <sstream>
- #include <stdio.h>
-
- // Fill in your solution and then submit this folder
-
- // Team Name: ThreeAndOne
-
- struct Tower
- {
- int length;
- int disks[1000]; // Array of length disks in order from bottom to top
-
- int popDisk() {assert(length); return disks[--length];}
- void pushDisk(int disk) {assert(!length || disks[length-1] > disk); disks[length++] = disk;}
- int largestDisk(int depth, int &pos);
- bool ordered(int depth);
- int diskAtDepth(int depth) {assert (depth < length); return disks[length - 1 - depth];}
- };
-
- Tower ReadTower(short refNum)
- {
- long eof;
- GetEOF(refNum, &eof);
- char* buffer = new char[eof];
- FSRead(refNum, &eof, buffer);
- std::string asstring(buffer, eof);
- delete [] buffer;
- std::istringstream s(asstring);
-
- Tower tower;
- s >> tower.length;
- int index = tower.length;
- while (index != 0)
- s >> tower.disks[--index];
- return tower;
- }
-
- short outRef;
- void WriteMove(int from, int to)
- {
- std::ostringstream s;
- s << from << "," << to;
- long count = s.str().size();
- FSWrite(outRef, &count, s.str().data());
- count = 1;
- char CR = 13;
- FSWrite(outRef, &count, &CR);
- }
-
- int Tower::largestDisk(int depth, int &pos)
- {
- assert(depth <= length);
- pos = 0;
- int largest = 0;
- for (int i = 0; i != depth; i++)
- if (disks[length-1-i] > largest) {
- largest = disks[length-1-i];
- pos = i;
- }
- return largest;
- };
-
- bool Tower::ordered(int depth)
- {
- if (depth == 0)
- return true;
- int disk = disks[length-1];
- for (int i = 1; i != depth; i++) {
- int d = disks[length-1-i];
- if (d <= disk)
- return false;
- disk = d;
- }
- return true;
- }
-
-
- struct Emitter
- {
- Tower pegs[3];
-
- void moveDisk(int srcPeg, int dstPeg);
- void moveTower(int srcPeg1, int srcPeg2, int dstPeg, int depth1, int depth2, int depth3);
- Tower &peg(int n) {assert(n>=1 && n<=3); return pegs[n-1];}
- };
-
-
- #ifdef DEBUG
- static int callDepth = 0;
- #endif
-
- void Emitter::moveDisk(int srcPeg, int dstPeg)
- {
- #ifdef DEBUG
- for (int z = callDepth; z; z--)
- fprintf(stderr, " ");
- fprintf(stderr, "moveDisk %d -> %d\n", srcPeg, dstPeg);
- #endif
- assert(srcPeg != dstPeg);
- peg(dstPeg).pushDisk(peg(srcPeg).popDisk());
- #ifdef DEBUG
- for (int peg = 0; peg != 3; peg++) {
- Tower &tower = pegs[peg];
- fprintf(stderr, " [");
- for (int i = 0; i != tower.length; i++)
- fprintf(stderr, "%d ", tower.disks[i]);
- fprintf(stderr, "] ");
- }
- fprintf(stderr, "\n");
- #endif
- WriteMove(srcPeg, dstPeg);
- }
-
- // Merge the top depth1 disks on srcPeg1 with the top depth2 disks on srcPeg2 and
- // the top depth3 disks on dstPeg and put them onto dstPeg.
- // The disks on srcPeg1 are in any order, but the disks on srcPeg2 and dstPeg
- // must be in proper size order. Any disks below the top depth1 disks on
- // srcPeg1, top depth2 disks on srcPeg2, and top depth3 disks on dstPeg don't affect
- // the possible moves.
- void Emitter::moveTower(int srcPeg1, int srcPeg2, int dstPeg, int depth1, int depth2, int depth3)
- {
- #ifdef DEBUG
- for (int z = callDepth; z; z--)
- fprintf(stderr, " ");
- fprintf(stderr, "moveTower %d:%d %d:%d %d:%d\n", srcPeg1, depth1, srcPeg2, depth2, dstPeg, depth3);
- callDepth++;
- #endif
- if (depth1 || depth2) {
- int largestPos1;
- int largest1 = peg(srcPeg1).largestDisk(depth1, largestPos1);
- int largest2 = depth2 ? peg(srcPeg2).diskAtDepth(depth2-1) : -1;
- int largest3 = depth3 ? peg(dstPeg).diskAtDepth(depth3-1) : -1;
- if (largest3 > largest1 && largest3 > largest2)
- moveTower(srcPeg1, srcPeg2, dstPeg, depth1, depth2, depth3-1);
- else if (largest2 > largest1 && largest2 > largest3)
- if (peg(srcPeg1).ordered(depth1)) {
- moveTower(srcPeg2, dstPeg, srcPeg1, depth2-1, depth3, depth1);
- moveDisk(srcPeg2, dstPeg);
- moveTower(srcPeg2, srcPeg1, dstPeg, 0, depth2-1+depth3+depth1, 0);
- } else {
- moveTower(srcPeg1, srcPeg2, dstPeg, depth1, depth2-1, depth3);
- moveTower(srcPeg2, dstPeg, srcPeg1, 0, depth1+depth2+depth3-1, 0);
- moveDisk(srcPeg2, dstPeg);
- moveTower(srcPeg2, srcPeg1, dstPeg, 0, depth1+depth2+depth3-1, 0);
- }
- else {
- moveTower(srcPeg1, dstPeg, srcPeg2, largestPos1, depth3, depth2);
- moveDisk(srcPeg1, dstPeg);
- moveTower(srcPeg1, srcPeg2, dstPeg, depth1-largestPos1-1, largestPos1+depth3+depth2, 0);
- }
- }
- #ifdef DEBUG
- callDepth--;
- #endif
- }
-
-
- pascal OSErr HowerOfTanoi( const FSSpec* infile, const FSSpec* outfile )
- {
- Emitter *emitter = new Emitter;
-
- short inRef;
- FSpOpenDF(infile, fsRdPerm, &inRef);
- emitter->pegs[0] = ReadTower(inRef);
- emitter->pegs[1].length = 0;
- emitter->pegs[2].length = 0;
- FSClose(inRef);
-
- FSpCreate(outfile, 'CWIE', 'TEXT', 0);
- FSpOpenDF(outfile, fsCurPerm, &outRef);
-
- emitter->moveTower(1, 2, 3, emitter->pegs[0].length, 0, 0);
-
- FSClose(outRef);
- delete emitter;
-
- return noErr;
- }
-