'https://en.wikipedia.org/wiki/Tower_of_Hanoi
 
$ filename "Hanoi.exe"
'uses rtl32
'uses rtl64
 
uses console
 
type CONSOLE_CURSOR_INFO ' cci  
    dword dwSize
    bool  bVisible 
end type 
 
extern lib "KERNEL32.DLL"
! SetConsoleCursorInfo (sys hConsoleOutput, CONSOLE_CURSOR_INFO *lpConsoleCursorInfo) as bool
! SetConsoleWindowInfo (sys hConsoleOutput, bool bAdsolute, SMALL_RECT *lpConsoleWindow)
! Sleep                (dword dwMilliseconds)
end extern 
 
extern lib "user32.dll"
! GetSystemMenu (sys hWnd, dword bRevert) as sys
! DeleteMenu    (sys hMenu, uint uPosition, uint uFlags)
end extern 
 
sub setcolor(int fg, bg)
  SetConsoleTextAttribute (ConsOut, fg+bg*16)
end sub
 
sub locate (int row,int col, optional int visible=1,int shape=12)
  CONSOLE_CURSOR_INFO cci
  SetPos(col-1,row-1)
  cci.bVisible = visible
  cci.dwSize   = shape
  SetConsoleCursorInfo(ConsOut, cci)
end sub
 
sub display(int col, row, string txt, optional int visible=1,int shape=12) 
  locate(row, col, visible) 
  print txt
end sub  
 
sub AdaptConsole()
   'Set size to 80,24
   dim ConsoleWindow as SMALL_RECT
   ConsoleWindow.Right = 80: ConsoleWindow.Bottom = 24
   SetConsoleWindowInfo(GetStdHandle(STD_OUTPUT_HANDLE), 1, ConsoleWindow)
   'Fix size
   sys hConsMenu=GetSystemMenu(GetConsoleWindow(), 0) 
   DeleteMenu(hConsMenu, &HF000, 0)
   DeleteMenu(hConsMenu, &HF020, 0)
   DeleteMenu(hConsMenu, &HF030, 0)   
end sub
 
SetConsoleTitle "Towers of Hanoi Puzzle"
 
 
string disk[10] = {
"         MMM         ",
"        MMMMM        ",
"       MMMMMMM       ",
"      MMMMMMMMM      ",
"     MMMMMMMMMMM     ",
"    MMMMMMMMMMMMM    ",
"   MMMMMMMMMMMMMMM   ",
"  MMMMMMMMMMMMMMMMM  ",
" MMMMMMMMMMMMMMMMMMM ",
"MMMMMMMMMMMMMMMMMMMMM"
}
 
string answer
 
int num, count, seeMoves, countMoves, intervall
int rodCol[3] ={17,41,65}   'x pos of A,B,C
int diskRow[3]               'row position of disks
 
 
sub createBoard()
  int idx, row
  string board=space 75
  setcolor 0,6 ' black, yellow
  display 4,20, board, 0
  for row=9 to 19
    for idx=1 to 3
      display rodCol[idx],row, " ", 0
    next
  next
  setcolor 7,0 ' white, black
  display 17,22,"A",0 : display 41,22,"B",0 : display 65,22,"C",0
end sub
 
sub pushDisk(string disk, int rod)
  setcolor 13,0 ' magenta, black
  diskRow(rod)-=1
  display rodCol(rod)-10, diskRow(rod), disk,0
end sub 
 
sub popDisk(string disk, int rod)
  setcolor 0,0 ' black, black 
  display rodCol(rod)-10, diskRow(rod), space(21),0
  setcolor 0,6 ' black, yellow
  display rodCol[rod], diskRow(rod), " ",0
  diskRow(rod)+=1 
end sub 
 
sub addDisks(int num)
  int row
  setcolor 13,0 ' magenta, black
  for row=num to 1 step -1
     pushDisk(disk(row),1)
  next
  diskRow[1]=20-num  
end sub
 
sub initGame()
  setcolor 7,0 ' white, black
  display 1,1, "How many disks? (3-10): "
  num=val(input)
  if num<3 then 
    num=3
  elseif num>10 then 
    num=10
  end if
  countMoves=pow(2,num)-1
  intervall=(5000\countMoves)  
  display 25,1, str(num) & "    ",0
  addDisks(num) 
loop1:  
  setcolor 7,0 ' white, black                 
  display  1,2, "Use Enter for next move? (y/n) "
  answer=getkey()
  if lcase(chr(answer))="y" then 
    seeMoves=1
    display 1,2, "Press Enter to see next Move  "
  elseif lcase(chr(answer))="n" then
    display 1,2, "                              ",0
  else
    goto loop1    
  end if
end sub
 
sub movedisk (int n, fromPeg, toPeg, viaPeg)
  'recursive method
  if n>0 then
    movedisk n-1, fromPeg, viaPeg, toPeg
    count+=1
    if seeMoves then waitkey()
    popDisk(disk(n),fromPeg)
    pushDisk(disk(n),toPeg)
    if seeMoves=0 then Sleep(Intervall)
    movedisk n-1, viaPeg, toPeg, fromPeg
  end if
end sub
 
================================================================================ 
'Prepare console, fix size
AdaptConsole()
 
'Start the app
start:
diskRow[]={20,20,20}   'row position of disks 
 
setcolor 7,0 ' white, black
 
cls
count=0 : seeMoves=0 : intervall=0
 
createBoard()
initGame()
 
movedisk (num, 1,2,3)
 
display 1,24, "Solved in " count " moves",0
display 1,25, "Enter to continue ...",0 : waitkey()
 
loop2:  
setcolor 7,0 ' white, black 
display 1,25, "Another Try? (y/n)   "
 
answer=getkey() : if lcase(chr(answer))="y" then goto start
if lcase(chr(answer))<>"n" then goto loop2
