2016-03-25 3 views
0

Итак, я пытаюсь оживить общую головоломку Tower of Hanoi. Я уже написал алгоритм, чтобы сделать это в консоли, но я хочу сделать JApplet, который всплывает и оживляет головоломку, решаемую после того, как я попрошу количество дисков. Вот мой код для алгоритма, если это помогает. Просто ищите какую-то инструкцию, не нужно выписывать весь код. Благодарю.Как анимировать Башню Ханоя?

Это мой код для алгоритма.

public class TowerofHanoi extends JFrame{ 

static int count= 0; 

public void move(int n, String start, String auxiliary, String end) { 

     if (n == 1) { 
      count++; 
      System.out.println(start + " -> " + end); 
     } else { 
      count++; 
      move(n - 1, start, end, auxiliary); 
      System.out.println(start + " -> " + end); 
      move(n - 1, auxiliary, start, end); 
     } 
    } 

public static void main(String[] args) { 
    // TODO Auto-generated method stub 
     TowerofHanoi towersOfHanoi = new TowerofHanoi(); 
     System.out.print("Enter number of discs: "); 
     Scanner scanner = new Scanner(System.in); 
     int discs = scanner.nextInt(); 
     towersOfHanoi.move(discs, "A", "B", "C"); 
     System.out.println("This puzzle took "+count+" moves."); 
    } 

public void paint(Graphics g) { 
     g.drawRect (10, 10, 200, 200); 

     } 
public TowerofHanoi(){ 
    setPreferredSize(new Dimension(WIDTH, HEIGHT)); 
} 
    } 

Это мой код для JApplet.

public class Graphics_TOH { 

public static void main(String[] args) { 
    // TODO Auto-generated method stub 
    JFrame frame = new JFrame ("Draw Person"); 
     frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); 
     TowerofHanoi panel = new TowerofHanoi(); 
     frame.getContentPane().add(panel); 
     frame.pack(); 
     frame.setVisible(true); 
} 
+0

Вы должны знать координаты «колышек» и размер каждого «диска». Вероятно, вы должны начать создавать как минимум класс диска. Если вы планируете делать гладкую анимацию, то это очень широкий запрос. –

+1

* «но я хочу сделать JApplet» * Вы уже пару лет слишком поздно для этого. См. [Устаревшая поддержка плагинов Java] (http://www.gizmodo.com.au/2016/01/rest-in-hell-java-plug-in/) и [Переход в плагин-бесплатно] (https: //blogs.oracle.com/java-platform-group/entry/moving_to_a_plugin_free). –

+0

Большая часть вашей проблемы связана с «состоянием», какое состояние является пользовательским интерфейсом в настоящее время и каким состоянием вы хотите быть в будущем. Анимация - это изменение во времени, поэтому из точки A в точку B вам нужно знать, сколько времени это может потребоваться, из этого вы настроили «цикл анимации» и вычислили ход с начальной точки. В большинстве случаев что-то вроде [Swing Timer] (http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html) будет прекрасно, но ничто не ставит хорошую простую библиотеку анимации – MadProgrammer

ответ

1

Этот вопрос на самом деле немного мне интересен, потому что это относится к домашнему животному мозоли моего - путь большинство языков программирования полагаться на стек вызовов делает это слишком трудно повторно использовать эту миленькую move() функцию ваш.

Чтобы сделать этот вид анимации, вам нужно:

  1. Установите таймер, чтобы вызвать обновление в несколько раз панелей (скажем, 20) в секунду;
  2. Помните текущее время начала анимации; и
  3. Каждый раз, когда панель освежает себя, получите текущее время и нарисуйте то, что должно выглядеть в это время.

Хитрость для вас, конечно, шаг 3.

Допустим, вы хотите сделать один шаг в секунду. Обновление происходит, вы получаете текущее время и обнаруживаете, что с момента начала анимации прошло 4,234 секунды. Вы подсчитаете, что вы составляете 0.234 секунды в ход 4, поэтому вы хотите нарисовать то, что должно выглядеть 23,4% пути через ход 4.

Для этого вам необходимо знать: какие диски статичны на который привязывается во время движения 4, и какой диск движется, его исходный штифт и его привязка.

Было бы довольно легко исправить вашу рекурсивную функцию перемещения, чтобы отслеживать все это, НО, так как она будет генерировать ВСЕ движения одновременно, нет никакого способа, чтобы она рассказывала вам о движении 4 конкретно.

Чтобы это исправить, в основном есть 3 варианта:

а) Вы могли бы назвать вашу функцию перемещения в начале, и он записывает все ходы. Затем, когда вы должны рисовать, вы можете продвигаться по записанным движениям к правильному. Это легко и, вероятно, практично. Конечно, требуется большая память для записи всех движений для большой головоломки (1M записи для 20 дисков), но также требуется много времени для анимации (1 неделя за один ход/сек), так что вы в любом случае, не собираться оживлять большие головоломки.

b) Вы можете выполнить свою функцию рекурсивного перемещения в отдельном потоке, который обменивается информацией с потоком рендеринга при каждом перерисовании. На самом деле это довольно частое ожидание, чтобы сделать это в многопользовательских играх, где игровое состояние нужно отслеживать в режиме реального времени. Для вас это больше проблем, чем того стоит.

c) Вы можете переписать свое решение hanoi нерекурсивным способом. Тогда вы можете реализовать Iterator. Это будет работать так же, как решение (а), но вы должны продвигать итератор, чтобы генерировать новые ходы, когда это необходимо, вместо того, чтобы выполнять итерацию с помощью предварительно записанных ходов.Преимущество в том, что вам не нужно создавать и хранить все ходы заранее.

Если бы это был я, я бы сделал решение (c), потому что мне было довольно удобно преобразовывать рекурсивное решение в итеративный с отдельным стеком. Если вам это не нравится, тогда вы, вероятно, захотите сделать (a) и наполнить все движения в ArrayList.

+0

* «способ, которым большинство языков программирования полагается на стек вызовов» * - запретить тот факт, что мы вернулись к goto и gosubs ... потому что это не вызвало никаких проблем: P – MadProgrammer

+0

@MadProgrammer проблема с стеком вызовов это то, что это * стек *, что делает его практически невозможным для языков, страдающих от него, для обеспечения надежной поддержки сопрограмм. Заметим, что рекурсивное ханое-решение нельзя записать рекурсивно в качестве генератора. –

+0

Это, наверное, так, но вы знаете, что я бы, вероятно, не пытался использовать рекурсивную рутину для ее решения (не тогда, когда я пытаюсь ее оживить), но это только я – MadProgrammer

0

В качестве подготовительной меры создайте объекты типа «Диск», которые будут содержать информацию о том, какие номера имеют их диски, тогда их «x» и «y» будут определены в зависимости от того, на какой башне они установлены, на каком количестве они там.

Чтобы оживить весь процесс, вам нужно собрать стек всех ходов и продолжать нажимать его так же, как и когда вы достигаете sysout между рекурсивными вызовами.

Когда стек сделан, извлеките его позже, вытащите его и прочитайте, какой диск был перемещен, когда, к какой башне. На диске у вас будет функция для изменения башни нет.

Массив дисков покажет себя, где для каждого Диск будет включена функция show(), в которой вы рисуете прямоугольники в указанной башне, умноженные на константу и на определенной высоте, здесь, чтобы уйти от сложности, оставьте вне высоты.

Это все, что вам нужно. Буквально просто преобразуйте приведенные строки в код, и все готово. Если вам нужна правильная высота, вам нужно будет создать 3 стека, которые будут удерживать диски, а затем выталкивать и извлекать информацию из основного стека, где вы сохранили все ходы. Функция Show теперь будет включать параметры о башне и ее штабелированном положении, и именно там вы нарисуете прямоугольник.

Я написал весьма понятный код JavaScript (работает на p5.js каркасных), вдохновленного ваш вопрос, и он будет полностью научить вас, как хорошо вы можете обрабатывать диски в простой программе для Башни Ханоя.

Посетите эту ссылку: My Sketch

var amount =22; 
Stack = []; 
disks = []; 
Sos= []; 
A = []; 
B = []; 
C = []; 

var frR =5; 

var slider; 

function Disk(n){ 
    this.n=n; 
    this.tower=1; 
    this.x=10+this.tower*200; 
    this.y=100+n*12; 

    this.show = function(i,j){ 
    rectMode(CENTER); 
    fill(map(n,0,amount,1,350),260,260); 
    rect(-100+(j+1)*350,300-i*12,10 +n*20,10); 
    } 
} 

function setup() { 
    createCanvas(1200, 600); 
    slider=createSlider(1,80,frR); 
    slider.position(20,400); 
    Hanoi(amount,1,2,3); 
    frameRate(frR); 
    colorMode(HSB); 

    Sos.push(A); 
    Sos.push(B); 
    Sos.push(C); 



    for(var i =0 ; i < amount; i++){ 
    disks.push(new Disk(i)); 


    } 
    for(var i =amount-1 ; i >=0; i--){ 
    Sos[0].push(disks[i]); 
    } 

} 

function draw(){ 
    if(frameCount < Stack.length) 
    drawIt(); 
} 

function drawIt() { 
    background(0); 
    frR=slider.value(); 
    frameRate(frR); 
    push(); 
    fill(255); 
    noStroke(); 
    text("Select Speed :",20,380); 

    textSize(20); 
    text("Steps taken : " + frameCount+ "/" + Stack.length + " ." ,450,450); 
    text("[ " + amount + " disks ]", 520,490); 
    rect(500,308,1800,2); 
    for(var j =0 ; j< 3; j++) 
    rect(-100+(j+1)*350, 188,2,240); 
    pop(); 


    for(var j =0 ; j< 3; j++){ 
    for(var i =0 ; i < Sos[j].length; i++){ 
     Sos[j][i].show(i,j); 

    } 
    } 

    var current = Stack[frameCount-1]; 
    Sos[current[1]-1].pop(); 
    Sos[current[2]-1].push(disks[current[0]]); 
} 


function Hanoi(n, from, to , via) 
{ 
    if (n==0) return; 

    Hanoi(n-1, from, via , to); 
//createP(n + " from" + from + " to " + to); 
    Stack.push([n,from,to]); 
    Hanoi(n-1, via, to , from); 
} 
Смежные вопросы