// By Chung-Chih Li, May-3-2002 // This program uses CMU Graphics library. #include using namespace std; #include #include #include #define SPause 0 #define MySteps 0.002 #define Default_Max_Disk 10 // Max is 25 #define Default_Font_Size 24 // Max is 25 int W_Width=1000; int TWin_X_Width=W_Width; int TWin_Y_Width= TWin_X_Width*3/4; int Button_size=TWin_Y_Width/30; //28 int Big_Button_size=Button_size*5/3; //40 int Tower_Lift=TWin_Y_Width/10; //70 int Tower_Gap=TWin_Y_Width/10; //50 int Min_disk=W_Width/20; //50 int Disk_Height=(TWin_Y_Width-Tower_Lift*3/2)/30; //25 // 20 is original idea int Disk_Gap=Disk_Height/5; int Disk_Width = (TWin_X_Width-Tower_Gap*4)/3.0; int Font_size = Default_Font_Size * (TWin_X_Width / 1000.0); bool Quit; const double PI = 3.141592653589793238462643383279; window *TowerWin; image Emptyimage; image Diskimage[50]; double steps=MySteps; // This has to be double double Jumps; long no_moved; int Max_Disk=Default_Max_Disk; struct coord { int x; int y; }; coord estp, counter, dp, dm, n, sp, sm, ok, manual, quit, tb_a, tb_b, tb_c; // buttons bool operator == (const coord & p1, const coord & p2) {return p1.x == p2.x && p1.y == p2.y; } bool operator != (const coord & p1, const coord & p2) {return p1.x != p2.x || p1.y != p2.y; } class est_time { public: est_time(int disk_no, coord p); int update(long has_moved); void set(long where); private: coord mydp,myhp,mymp,mysp; int myGap; int myD, myH, myM, myS; int myUD, myUH, myUM, myUS; int myFont_size; long myTotal_moves; long mySet_at_move; long mySet_at_time; long myHas_moved; long myBegin; long myElapse; unsigned long myEst; long myRemain; double myR, myG, myB; }; est_time *EstClock; est_time::est_time(int disk_no, coord p) { int x,y; myR = myG = 0.5; myB = 0; myTotal_moves = pow(2,disk_no)-1; myGap = Font_size/2; myFont_size = Font_size-2; mySet_at_move = mySet_at_time = 0; myElapse = myEst=myHas_moved=myD=myH=myM=myS=0; myUD=myUH=myUM=myUS=0; mydp.y=myhp.y=mymp.y=mysp.y=p.y; myBegin=clock(); TowerWin->SetFont(myFont_size,1,ROMAN); TowerWin->SetPen(myR, myG, myB); TowerWin->GetIntegerSize(x,y,88888); mydp.x = p.x+x; TowerWin->DrawString(mydp.x+myGap, mydp.y, "Days + "); TowerWin->GetStringSize(x,y,"Days + "); myhp.x = mydp.x+x+myGap; TowerWin->GetIntegerSize(x,y,88); myhp.x = myhp.x + x; TowerWin->DrawString(myhp.x, myhp.y, " : "); TowerWin->DrawString(myhp.x, myhp.y+Font_size, " : "); TowerWin->GetStringSize(x,y," : "); mymp.x = myhp.x+x; TowerWin->GetIntegerSize(x,y,88); mymp.x = mymp.x+x; TowerWin->DrawString(mymp.x, mymp.y, " : "); TowerWin->DrawString(mymp.x, mymp.y+Font_size, " : "); TowerWin->GetStringSize(x,y," : "); mysp.x = mymp.x+x; TowerWin->GetIntegerSize(x,y,88); mysp.x = mysp.x+x; TowerWin->GetIntegerSize(x,y,myD); TowerWin->DrawInteger(mydp.x-x, mydp.y, myD); TowerWin->DrawInteger(myhp.x-x, myhp.y, myH); TowerWin->DrawInteger(mymp.x-x, mymp.y, myM); TowerWin->DrawInteger(mysp.x-x, mysp.y, myS); TowerWin->DrawInteger(mydp.x-x, mydp.y+Font_size, myUD); TowerWin->DrawInteger(myhp.x-x, myhp.y+Font_size, myUH); TowerWin->DrawInteger(mymp.x-x, mymp.y+Font_size, myUM); TowerWin->DrawInteger(mysp.x-x, mysp.y+Font_size, myUS); } void est_time::set(long where) { mySet_at_move = where; mySet_at_time = myElapse; myBegin = clock(); } int est_time::update(long has_moved) { int x,y; int newS, newM, newH, newD; int newUS, newUM, newUH, newUD; long now = clock(); unsigned long newEst; double d_rem, d_moved=(has_moved-mySet_at_move); // make d_move a double long elapse = (now-myBegin)/1000 ; // in sec d_rem = elapse*((myTotal_moves-mySet_at_move)/d_moved); newEst = d_rem+mySet_at_time; elapse += mySet_at_time; if (elapse == myElapse) return 0; myElapse = elapse; myEst = newEst; newS = newEst % 60; newEst /= 60; // minutes; newM = newEst % 60; newEst /= 60; // hours; newH = newEst % 24; newEst /= 24; // day; newD = newEst; newUS = elapse % 60; elapse /= 60; // minutes; newUM = elapse % 60; elapse /= 60; // hours; newUH = elapse % 24; elapse /= 24; // day; newUD = elapse; TowerWin->SetFont(myFont_size,1,ROMAN); if (newD != myD) { TowerWin->GetIntegerSize(x,y,myD); TowerWin->SetPen(1.0, 1.0, 1.0); TowerWin->DrawInteger(mydp.x-x, mydp.y, myD); TowerWin->SetPen(myR, myG, myB); myD=newD; TowerWin->GetIntegerSize(x,y,myD); TowerWin->DrawInteger(mydp.x-x, mydp.y, myD); } if (newH != myH) { TowerWin->GetIntegerSize(x,y,myH); TowerWin->SetPen(1.0, 1.0, 1.0); TowerWin->DrawInteger(myhp.x-x, myhp.y, myH); TowerWin->SetPen(myR, myG, myB); myH=newH; TowerWin->GetIntegerSize(x,y,myH); TowerWin->DrawInteger(myhp.x-x, myhp.y, myH); } if (newM != myM) { TowerWin->GetIntegerSize(x,y,myM); TowerWin->SetPen(1.0, 1.0, 1.0); TowerWin->DrawInteger(mymp.x-x, mymp.y, myM); TowerWin->SetPen(myR, myG, myB); myM=newM; TowerWin->GetIntegerSize(x,y,myM); TowerWin->DrawInteger(mymp.x-x, mymp.y, myM); } if (newS != myS) { TowerWin->GetIntegerSize(x,y,myS); TowerWin->SetPen(1.0, 1.0, 1.0); TowerWin->DrawInteger(mysp.x-x, mysp.y, myS); TowerWin->SetPen(myR, myG, myB); myS=newS; TowerWin->GetIntegerSize(x,y,myS); TowerWin->DrawInteger(mysp.x-x, mysp.y, myS); } if (newUD != myUD) { TowerWin->GetIntegerSize(x,y,myUD); TowerWin->SetPen(1.0, 1.0, 1.0); TowerWin->DrawInteger(mydp.x-x, mydp.y+Font_size, myUD); TowerWin->SetPen(myR, myG, myB); myUD=newUD; TowerWin->GetIntegerSize(x,y,myUD); TowerWin->DrawInteger(mydp.x-x, mydp.y+Font_size, myUD); } if (newUH != myUH) { TowerWin->GetIntegerSize(x,y,myUH); TowerWin->SetPen(1.0, 1.0, 1.0); TowerWin->DrawInteger(myhp.x-x, myhp.y+Font_size, myUH); TowerWin->SetPen(myR, myG, myB); myUH=newUH; TowerWin->GetIntegerSize(x,y,myUH); TowerWin->DrawInteger(myhp.x-x, myhp.y+Font_size, myUH); } if (newUM != myUM) { TowerWin->GetIntegerSize(x,y,myUM); TowerWin->SetPen(1.0, 1.0, 1.0); TowerWin->DrawInteger(mymp.x-x, mymp.y+Font_size, myUM); TowerWin->SetPen(myR, myG, myB); myUM=newUM; TowerWin->GetIntegerSize(x,y,myUM); TowerWin->DrawInteger(mymp.x-x, mymp.y+Font_size, myUM); } if (newUS != myUS) { TowerWin->GetIntegerSize(x,y,myUS); TowerWin->SetPen(1.0, 1.0, 1.0); TowerWin->DrawInteger(mysp.x-x, mysp.y+Font_size, myUS); TowerWin->SetPen(myR, myG, myB); myUS=newUS; TowerWin->GetIntegerSize(x,y,myUS); TowerWin->DrawInteger(mysp.x-x, mysp.y+Font_size, myUS); } return 1; } class tower { public: tower(int tower_number, string tower_name); void push(image *disk); image *pop(); image *at(int i); void build_tower(int number); coord top(); string name(); int gap(); int height(); void set_button(coord p); coord button(); private: string myName; image *myTower[50]; int myHeight; int myGap; coord myTop; coord myButton; }; tower::tower(int number, string name) :myName(name), myHeight(0), myGap(Disk_Gap) { myTop.x = (Disk_Width + Tower_Gap)*number-(Disk_Width+Tower_Gap)/2; myTop.y = TWin_Y_Width - Tower_Lift; myButton.x = myButton.y = 0; } void tower::push(image *disk) // Store from 1 (not 0); { int w = (*disk).GetWidth(); int h = (*disk).GetHeight(); myTower[++myHeight] = disk; myTop.y = myTop.y - myGap - Disk_Height; TowerWin->DrawImage(*disk, myTop.x - w/2, myTop.y, w, h); } image *tower::pop() { int w = myTower[myHeight]->GetWidth(); int h = myTower[myHeight]->GetHeight(); coord a = myTop; TowerWin->DrawImage(Emptyimage, a.x - w/2, a.y, w, h); myTop.y = myTop.y + myGap + Disk_Height; return myTower[myHeight--]; } image *tower::at(int i) { return myTower[i]; } coord tower::top() { return myTop; } string tower::name() { return myName; } int tower::gap() { return myGap; } int tower::height() { return myHeight; } void tower::set_button(coord p) { myButton = p; } coord tower::button() { return myButton; } void tower::build_tower(int number) { int i, disk, width; coord lup, rlo; int disk_inc = (Disk_Width-Min_disk)/Max_Disk; disk_inc += ((disk_inc) % 2); // make it an even number for (i = 0; i < number ; i++) { disk = number-i; width = Min_disk + disk_inc*disk; lup.x = myTop.x - width/2; lup.y = myTop.y-Disk_Height-myGap; rlo.x = myTop.x + width/2; rlo.y = myTop.y-myGap; TowerWin->SetBrush(1.0 - pow(abs((disk-i)/(double)number),0.01), pow((disk-1)/(double)number,1), pow((i)/(double)number,1)); TowerWin->DrawRectangle(lup.x, lup.y, rlo.x, rlo.y, FILLED, 4, 10); TowerWin->StoreImage(Diskimage[i], lup.x, lup.y, width, Disk_Height); \ push(& Diskimage[i]); //Sleep(100); } } void put_red_button(coord & a) { int x = a.x, y = a.y; TowerWin->SetBrush(1.0, 0.0, 0.0); TowerWin->DrawRectangle(x,y,x+Button_size,y+Button_size, FILLED, 4, 10); } void put_button(coord & a, string name) { int x = a.x, y = a.y; int w,h; int i=0; do { TowerWin->SetFont(32-i,1,ROMAN); TowerWin->GetStringSize(w, h, name); i++; } while (w > Button_size - 4); TowerWin->SetBrush(0.2, 0.2, 0.2); TowerWin->DrawRectangle(x+3,y+3,x+3+Button_size,y+3+Button_size, FILLED, 4, 10); TowerWin->SetBrush(0.0, 0.8, 0.8); TowerWin->DrawRectangle(x,y,x+Button_size,y+Button_size, FILLED, 4, 10); TowerWin->SetPen(0.0, 0.0, 0.0); TowerWin->DrawString(x+(Button_size-w)/2, y+(Button_size-h)/2, name); } void push_button(coord a, string name, int run) { int i; for (i = 0 ; i < 3; i++) { a.x = a.x+i; a.y = a.y+i; put_button(a, name); } // if (run == 0) Sleep(100); for (i = 0 ; i < 3; i++) { a.x = a.x-i; a.y = a.y-i; put_button(a, name); } } void put_big_button(coord & a, string name) { int x = a.x, y = a.y; int w,h; int i=0; do { TowerWin->SetFont(32-i,1,ROMAN); TowerWin->GetStringSize(w, h, name); i++; } while (w > Big_Button_size - 4); TowerWin->SetBrush(0.2, 0.2, 0.2); TowerWin->DrawRectangle(x+3,y+3,x+3+Big_Button_size,y+3+Button_size, FILLED, 4, 10); TowerWin->SetBrush(0.0, 0.8, 0.8); TowerWin->DrawRectangle(x,y,x+Big_Button_size,y+Button_size, FILLED, 4, 10); TowerWin->SetPen(0.0, 0.0, 0.0); TowerWin->DrawString(x+(Big_Button_size-w)/2, y+(Button_size-h)/2, name); } void push_big_button(coord a, string name, int run) { int i; for (i = 0 ; i < 3; i++) { a.x = a.x+i; a.y = a.y+i; put_big_button(a, name); } // if (run == 0) Sleep(100); for (i = 0 ; i < 3; i++) { a.x = a.x-i; a.y = a.y-i; put_big_button(a, name); } } // This will return steps; double change_speed(coord & a, coord & b, int x, int y, int run) { if (x >= a.x && x <= a.x+Button_size && y >= a.y && y <= a.y+Button_size) { push_button(a,"+", run); if (steps <= 2) { steps = steps*2; Jumps = 14 + log(steps); } else { if (steps < 100) steps = steps*1.2; if (steps > 100) steps = 100; Jumps = 15; } TowerWin->SetBrush(1.0, 0.0, 0.0); TowerWin->DrawRectangle(b.x+Button_size+10, b.y, b.x+Button_size+10+Jumps*10+steps, b.y+Button_size/2, FILLED, 0, 0); if (run) EstClock->set(no_moved); } else if (x >= b.x && x <= b.x+Button_size && y >= b.y && y <= b.y+Button_size) { push_button(b,"-", run); if (steps <= 2) { if (steps >= 0.00001) steps = steps/2; Jumps = 14 + log(steps); } else { steps = steps/1.2; Jumps = 15; } TowerWin->SetBrush(1.0, 0.9, 0.0); TowerWin->DrawRectangle(b.x+Button_size+10+Jumps*10+steps, b.y, b.x+Button_size+10+250, b.y+Button_size/2, FILLED, 0, 0); if (run) EstClock->set(no_moved); } else if (x > 0 && run == 1) { put_big_button(quit, "Quit"); TowerWin->WaitMouseClick(x,y); if (x >= quit.x && x <= quit.x+Big_Button_size && y >= quit.y && y <= quit.y+Button_size) { push_big_button(quit, "Quit", 0); Quit = true; steps = MySteps; // In order to finish the move fast; return steps; } put_big_button(quit, " "); TowerWin->FlushMouseQueue(); } return steps; } int change_disk_number(coord & a, coord & b, coord & n, int x, int y) { if (x >= a.x && x <= a.x+Button_size && y >= a.y && y <= a.y+Button_size) { if (Max_Disk < 25) { push_button(dp,"+", 0); TowerWin->SetPen(1.0, 1.0, 1.0); TowerWin->SetFont(Font_size,1,ROMAN); TowerWin->DrawInteger(n.x, n.y, Max_Disk); TowerWin->SetPen(0.0, 0.0, 0.7); Max_Disk++; TowerWin->DrawInteger(n.x, n.y, Max_Disk); return 1; } } else if (x >= b.x && x <= b.x+Button_size && y >= b.y && y <= b.y+Button_size) { if (Max_Disk > 1) { push_button(dm,"-", 0); TowerWin->SetPen(1.0, 1.0, 1.0); TowerWin->SetFont(Font_size,1,ROMAN); TowerWin->DrawInteger(n.x, n.y, Max_Disk); TowerWin->SetPen(0.0, 0.0, 0.7); Max_Disk--; TowerWin->DrawInteger(n.x, n.y, Max_Disk); return -1; } } return 0; } // Will save the destination's origrinal image in old_i void mover(image & old_i, image & a_disk, coord & a, coord & b, int w, int h) { if (a.y >= 0) TowerWin->DrawImage(old_i, a.x, a.y, w, h); else if (a.y+h > 0) TowerWin->DrawImage(old_i, a.x, 0, w, a.y+h); if (b.y >= 0) TowerWin->StoreImage(old_i, b.x, b.y, w, h); else if (b.y+h > 0) TowerWin->StoreImage(old_i, b.x, 0, w, b.y+h); TowerWin->DrawImage(a_disk, b.x, b.y, w, h); } // track is a circle, not used. void c_move(image *disk, coord & a, coord & b) { int w = (*disk).GetWidth(); int h = (*disk).GetHeight(); image old; TowerWin->StoreImage(old, a.x, a.y, w, h); coord c,p1,p2; double dx,dy, beta, shift_theta, delta, theta, r, dis; int x=0,y=0; p1.x = a.x; p1.y = a.y; c.x = (a.x+b.x)/2; c.y = (a.y+b.y)/2; dis = sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)); r = dis/2.0; delta=atan(steps/r); shift_theta = asin((a.y-b.y)/dis); for (theta = 0 ; theta < PI; theta=theta+delta) { TowerWin->GetMouseClick(x,y); if ( x >= 0) { steps = change_speed(sp, sm, x, y, 1); delta=atan(steps/r); } beta = PI-theta+shift_theta; if (a.x < b.x) dx = r*cos(beta); else dx = -r*cos(beta); dy = r*sin(beta); p2.x = c.x+dx; p2.y = c.y-dy; if (abs(p1.x-p2.x)+abs(p1.y-p2.y) > Jumps) { mover(old, *disk, p1, p2, w, h); p1.x = p2.x; p1.y = p2.y; } } mover(old, *disk, p1, b, w, h); } // track is parabolic void p_move(image *disk, coord & a, coord & b) { int w = (*disk).GetWidth(); int h = (*disk).GetHeight(); image old; TowerWin->StoreImage(old, a.x, a.y, w, h); coord pp=a, p; int x,y; double g=0.01, dis = b.x - a.x; double hv; if (abs(dis) < TWin_X_Width /2) hv = 0.6; else hv = 1.2; double t = abs(dis/hv); if (dis < 0) { dis = - dis; hv = - hv; } double vv = (b.y-a.y)/t-g*t/2; for (double i =0; iGetMouseClick(x,y); if ( x >= 0) { steps = change_speed(sp, sm, x, y, 1); } p.x = a.x+hv*i; p.y = a.y+vv*i+g*i*i/2; if (abs(pp.x-p.x)+abs(pp.y-p.y) > Jumps*2) { mover(old, *disk, pp, p, w, h); EstClock->update(no_moved); pp = p; } } mover(old, *disk, pp, b, w, h); } void move_a_disk(tower & from, tower & to) { image *disk; coord a,b; int w, h; a = from.top(); disk = from.pop(); w = (*disk).GetWidth(); h = (*disk).GetHeight(); a.x = a.x - w/2; b = to.top(); b.y = b.y-h-Disk_Gap; b.x = b.x - w/2; // c_move(disk, a, b); p_move(disk, a, b); to.push(disk); TowerWin->SetFont(Font_size,1,ROMAN); TowerWin->SetPen(1.0, 1.0, 1.0); TowerWin->DrawInteger(counter.x,counter.y, no_moved); TowerWin->SetPen(0.5, 0.0, 0.9); no_moved++; TowerWin->DrawInteger(counter.x, counter.y, no_moved); EstClock->update(no_moved); } void hannoi(int disks, tower & from, tower & to, tower & use) { if (!Quit && disks > 0) { hannoi(disks-1, from, use, to); if (!Quit) move_a_disk(from, to); hannoi(disks-1, use, to, from); } } void auto_play_hannoi(int disks, tower & from, tower & to, tower & use) { est_time T(disks, estp); EstClock = &T; no_moved=0; TowerWin->SetFont(Font_size,1,ROMAN); TowerWin->SetPen(0.0, 0.6, 0.6); TowerWin->GetStringSize(counter.x,counter.y,"Moves: " ); TowerWin->DrawString(0,0,"Moves:"); counter.y = 0; hannoi(disks, from, to, use); } tower *choose_to(int x, int y, tower *a, tower *b) { if (x >= (*a).button().x && x <= (*a).button().x+Button_size && y >= (*a).button().y && y <= (*a).button().y+Button_size) { push_button((*a).button(), " ", 0); put_red_button((*a).button()); put_button((*b).button(), " "); return a; } if (x >= (*b).button().x && x <= (*b).button().x+Button_size && y >= (*b).button().y && y <= (*b).button().y+Button_size) { push_button((*b).button(), " ", 0); put_red_button((*b).button()); put_button((*a).button(), " "); return b; } return a; } coord locate(coord a, tower & t, int & w, int & h) { coord address; int tfloor; int min_x, max_x; int min_y = t.top().y; int max_y = TWin_Y_Width - Tower_Lift; w = h = address.x = 0; if (a.y > max_y) return address; tfloor = 1 + (max_y - a.y )/(Disk_Height + Disk_Gap); if (tfloor > t.height()) return address; w = t.at(tfloor)->GetWidth(); min_x = t.top().x - w/2; max_x = min_x + w; if (a.x >= min_x && a.x <= max_x) { h = (Disk_Height + Disk_Gap)*(t.height()-tfloor+1)-Disk_Gap; address.x = min_x; address.y = t.top().y; } else { w=h=0; } return address; } tower *find_shift(coord a, tower & ta, tower & tb, tower & tc, int & w, int & h, coord & shift) { coord address; tower *at; w = h = shift.x = shift.y = 0; at = &ta; address = locate(a, ta, w, h); if (address.x == 0) { at = &tb; address = locate(a, tb, w, h); } if (address.x == 0) { at = & tc; address = locate(a, tc, w, h); } if (address.x == 0) { w = h = 0; return at; } shift.x = address.x - a.x; shift.y = address.y - a.y; return at; } tower *find_to(int x, tower & ta, tower & tb, tower & tc) { if (x > ta.top().x - Tower_Gap*2 && x < ta.top().x + Tower_Gap*2) return &ta; if (x > tb.top().x - Tower_Gap*2 && x < tb.top().x + Tower_Gap*2) return &tb; if (x > tc.top().x - Tower_Gap*2 && x < tc.top().x + Tower_Gap*2) return &tc; return 0; } void manual_play_hannoi(int disk_no, tower & ta, tower & tb, tower & tc) { int x,y,w, h, topw; tower *from, *to; tower temp(0,""); coord o, a,b, sa, sb, shift; image old, block; buttonstate hold = BUTTON_DOWN; button selectB = LEFT_BUTTON; bool cheat=false, Done=false; est_time T(disk_no, estp); EstClock = &T; TowerWin->SetFont(Font_size,1,ROMAN); TowerWin->SetPen(0.0, 0.6, 0.6); TowerWin->GetStringSize(counter.x,counter.y,"Moves: " ); TowerWin->DrawImage(Emptyimage,0,0, TWin_X_Width, counter.y); TowerWin->DrawString(0,0,"Moves:"); no_moved = counter.y = 0; do { while (TowerWin->GetButtonState(selectB, a.x, a.y) != hold) { EstClock->update(0); }; from = find_shift(a, ta, tb, tc, w, h, shift); if (w == 0) continue; o.x = a.x + shift.x; o.y = a.y + shift.y; TowerWin->StoreImage(block, a.x+shift.x, a.y+shift.y, w, h); TowerWin->DrawImage(Emptyimage, a.x+shift.x, a.y+shift.y, w, h); TowerWin->StoreImage(old, a.x+shift.x, a.y+shift.y, w, h); TowerWin->DrawImage(block, a.x+shift.x, a.y+shift.y, w, h); while (TowerWin->GetButtonState(selectB, b.x, b.y) == hold) { EstClock->update(0); if (abs(a.x-b.x)+abs(a.y-b.y) > 10) { sa.x = a.x+shift.x; sa.y = a.y+shift.y; sb.x = b.x+shift.x; sb.y = b.y+shift.y; mover(old, block, sa, sb, w,h); a=b; } } to = find_to(sb.x+w/2, ta, tb, tc); if (to != 0) { sa.x = to->top().x - w/2; sa.y = to->top().y - h - Disk_Gap; TowerWin->DrawImage(old, sb.x, sb.y, w, h); if (to->height() == 0) { topw = 99999; } else { topw = (to->at(to->height()))->GetWidth(); } if (w < topw) { int disks_to_move = (h+Disk_Gap)/(Disk_Height+Disk_Gap); if (!cheat && disks_to_move > 1) { cheat = true; TowerWin->SetPen(1.0, 1.0, 1.0); TowerWin->DrawInteger(counter.x, counter.y, no_moved); TowerWin->SetPen(0.5, 0.0, 0.9); TowerWin->DrawInteger(counter.x, counter.y, 0); } for (int i = disks_to_move; i>0; i--) temp.push(from->pop()); for (i = disks_to_move; i>0; i--) to->push(temp.pop()); if (!cheat) { TowerWin->SetPen(1.0, 1.0, 1.0); TowerWin->DrawInteger(counter.x, counter.y, no_moved); TowerWin->SetPen(0.5, 0.0, 0.9); no_moved++; TowerWin->DrawInteger(counter.x, counter.y, no_moved); } } else { // not a legal move (big on small) mover(old, block, sb, o, w,h); } } else { // move to itself; mover(old, block, sb, o, w,h); } if (tb.height() == disk_no) // maybe done { put_big_button(quit, "Done"); TowerWin->FlushMouseQueue(); TowerWin->WaitMouseClick(x,y); if (x >= quit.x && x <= quit.x + Big_Button_size && y >= quit.y && y <= quit.y + Button_size) { Done = true; push_big_button(quit, "Done",0); } else { Done = false; put_big_button(quit, " "); } } } while (! Done); } int main() { int x,y; cout << "Input Window Width (400-2800):"; cin >> x; if (x >= 400 && x <= 2800) { W_Width=x; TWin_X_Width=W_Width; TWin_Y_Width= TWin_X_Width*3/4; Button_size=TWin_Y_Width/30; //28 Big_Button_size=Button_size*5/3; //40 Tower_Lift=TWin_Y_Width/10; //70 Tower_Gap=TWin_Y_Width/10; //50 Min_disk=W_Width/20; //50 Font_size = Default_Font_Size * (TWin_X_Width / 1000.0); Disk_Height=(TWin_Y_Width-Tower_Lift*3/2)/30; //25 // 20 is original idea Disk_Gap=Disk_Height/5; Disk_Width = (TWin_X_Width-Tower_Gap*4)/3.0; } cout << "Click on the " << TWin_X_Width << "X" << TWin_Y_Width << " Window to activate." << endl; window LocalWin(TWin_X_Width, TWin_Y_Width, 20, 20); TowerWin = &LocalWin; TowerWin->SetWaitClose(false); TowerWin->ChangeTitle("Hannoi Tower, \t C.C.L."); TowerWin->WaitMouseClick(x,y); x=y=0; TowerWin->SetFont(Font_size,1,ROMAN); dp.y = dm.y = n.y = sp.y = sm.y = manual.y = ok.y = quit.y = TWin_Y_Width-Button_size-10; dp.x=0+10; dm.x=dp.x+Button_size+10; n.x=dm.x+Button_size+10; TowerWin->SetFont(Font_size,1,ROMAN); TowerWin->SetPen(0.0, 0.5, 0.5); TowerWin->DrawString(n.x, n.y,"Disk:"); TowerWin->GetStringSize(x,y,"Disk: "); n.x = n.x + x; TowerWin->SetPen(0.0, 0.0, 0.7); TowerWin->SetFont(Font_size,1,ROMAN); TowerWin->DrawInteger(n.x, n.y, Max_Disk); TowerWin->GetIntegerSize(x,y,255); sp.x = n.x+x; sm.x = sp.x+Button_size+10; quit.x = TWin_X_Width-Big_Button_size-10; ok.x = quit.x-Big_Button_size-10; manual.x = ok.x-Big_Button_size-10; put_button(dp,"+"); put_button(dm,"-"); put_button(sp,"+"); put_button(sm,"-"); TowerWin->StoreImage(Emptyimage, 0, 0, Disk_Width+4, Disk_Height); tower ta(1,"Tower 1"), tb(2, "Tower 2"), tc(3, "Tower 3"); tower *from, *use, *to, *temp; TowerWin->SetPen(0.4, 0.4, 0.4); TowerWin->SetFont(Font_size,1,ROMAN); TowerWin->GetStringSize(x,y,ta.name()); TowerWin->DrawString(ta.top().x-x/2, ta.top().y, ta.name()); TowerWin->DrawString(tb.top().x-x/2, tb.top().y, tb.name()); TowerWin->DrawString(tc.top().x-x/2, tc.top().y, tc.name()); tb_a.y = tb_b.y = tb_c.y = ta.top().y; tb_a.x = ta.top().x + x/2 +10; tb_b.x = tb.top().x + x/2 +10; tb_c.x = tc.top().x + x/2 +10; ta.set_button(tb_a); tb.set_button(tb_b); tc.set_button(tb_c); push_button(tb_a, " ", 1); push_button(tb_b, " ", 1); put_red_button(tb_b); push_button(tb_c, " ", 1); TowerWin->SetPen(0.0, 0.0, 0.0); TowerWin->SetFont(Font_size*2/3,1,ROMAN); TowerWin->DrawString(sm.x+Button_size+10, sm.y+Button_size/2, "Speed"); tb.build_tower(0); tc.build_tower(0); ta.build_tower(Max_Disk); from = &ta; to = &tb; use = &tc; TowerWin->SetFont(Font_size,1,ROMAN); TowerWin->GetStringSize(x,y,"88888 Days + 88 : 88 : 888"); estp.x = TWin_X_Width-x; estp.y = 0; do{ int d,change = 0; bool autoplay=false; bool manualplay=false; if (steps < 1) Jumps = 14 + log(steps); else Jumps = 15; TowerWin->SetBrush(1.0, 0.0, 0.0); TowerWin->DrawRectangle( sm.x+Button_size+10, sm.y, sm.x+Button_size+10+Jumps*10+steps, sm.y+Button_size/2, FILLED, 0, 0); TowerWin->SetBrush(1.0, 0.9, 0.0); TowerWin->DrawRectangle( sm.x+Button_size+10+Jumps*10+steps-1, sm.y, sm.x+Button_size+10+250, sm.y+Button_size/2, FILLED, 0, 0); put_big_button(quit,"Quit"); put_big_button(ok,"Auto"); put_big_button(manual,"Manu"); do { TowerWin->GetMouseClick(x,y); change = change_disk_number(dp,dm,n,x,y); if (change == 1) // increase 1 disk { d = (*from).height(); for (int i=0; i < d; i++) (*from).pop(); (*from).build_tower(Max_Disk); TowerWin->FlushMouseQueue(); } if (change == -1) // remove 1 disk { (*from).pop(); TowerWin->FlushMouseQueue(); } steps = change_speed(sp,sm,x,y,0); if (choose_to(x,y,to,use) != to) { temp = to; to = use; use = temp; } if (x >= ok.x && x <= ok.x+Big_Button_size && y >= ok.y && y <= ok.y+Button_size) { autoplay = true; push_big_button(ok,"Auto",1); put_big_button(manual, " "); put_big_button(quit, " "); } if (x >= manual.x && x <= manual.x+Big_Button_size && y >= manual.y && y <= manual.y+Button_size) { manualplay = true; push_big_button(manual,"Manu",1); put_big_button(ok, " "); put_big_button(quit," "); } if (x >= quit.x && x <= quit.x+Big_Button_size && y >= quit.y && y <= quit.y+Button_size) { push_big_button(quit,"Quit",0); put_big_button(manual,"Click"); put_big_button(ok,"mouse"); put_big_button(quit,"again"); return 0; } } while (!autoplay && !manualplay); Quit = false; long ST=clock(); TowerWin->DrawImage(Emptyimage,0,0, TWin_X_Width, Font_size*3); if (autoplay) { auto_play_hannoi((*from).height(), *from, *to, *use); } if (manualplay) manual_play_hannoi((*from).height(), *from, *to, *use); cout << "\n Use " << (clock() - ST)/1000 << " seconds\n"; put_button((*to).button(), " "); if (Quit) { from = &ta; to = &tb; use = &tc; put_red_button((*to).button()); d = (*from).height(); for (int i=0; i < d; i++) (*from).pop(); (*from).build_tower(Max_Disk); d = (*to).height(); for (i=0; i < d; i++) (*to).pop(); (*to).build_tower(0); d = (*use).height(); for (i=0; i < d; i++) (*use).pop(); (*use).build_tower(0); } else { put_red_button((*use).button()); temp = from; from = to; to = use; use = temp; } TowerWin->FlushMouseQueue(); } while (true); }