이야기박스
Java) 하노이의 탑 < 완성본 > 본문
드디어!
하노이의 탑을 완성하였습니다! (짝짝짝)
미리 설계를 하고 짠게 아니고
마구잡이로 생각나는대로 하다보니까 오히려 시간이 더 걸린거 같네요.. 하하
설계의 중요성을 다시 한번 깨닫게 됩니다.
간단한 설명을 하겠습니다.
모두가 아시는 하노이의 탑의 UI버젼입니다.
블록의 이동을 버튼을 통해 하나씩 확인할 수 있도록 했습니다.
기본적인 동작만 코딩했으므로 예외처리나 리셋 등 기타 옵션들은 없습니다.
< 사용한 클래스들 >
위와 같이 6개의 클래스를 사용하였습니다.
1. Main
프로그램을 실행하기 위한 클래스. JFrame을 사용
2. Display
기본 UI를 위한 클래스
버튼의 이벤트들을 담당한다
3. Logic
하노이 탑의 로직을 담당
4. HanoiData
하노이 탑에서 각 블록의 정보를 담는다.
5. Sequence
각 화면의 시퀀스(단계)를 나타낸다.
예를 들어, 3개의 블록을 가진 하노이의 탑에서 하나의 시퀀스는 3개의 블록 데이터의 집합이다.
6. DrawPanel
위에서 얻은 정보를 바탕으로 그림을 그린다 ^__^
< 코드 >
1. Main
import javax.swing.*;
public class Main{
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Display primary = new Display();
frame.getContentPane().add(primary);
frame.pack();
frame.setVisible(true);
}
}
2. Display
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.*;
public class Display extends JPanel{
private Dimension displaySize;
private JLabel lblTitle, lblAsking;
private JPanel subOptions;
private DrawPanel mainDisplay;
private JButton btnNext, btnPrev, btnExe;
private JTextField txtInput;
private HanoiListener listener;
private Logic logic;
private int nInput, nSequence;
private ArrayList sequence;
public Display() {
displaySize = new Dimension(800,800);
this.setPreferredSize(displaySize);
this.setBackground(Color.black);
this.setLayout(null);
listener = new HanoiListener();
nSequence = 1;
// Top side
lblTitle = new JLabel("Hanoi Top");
lblTitle.setForeground(Color.white);
lblTitle.setFont(new Font("Monofour",Font.ITALIC,40));
lblTitle.setHorizontalAlignment(SwingConstants.CENTER);
lblTitle.setBounds(0,0,displaySize.width,displaySize.height/8);
this.add(lblTitle);
// Main - Display
mainDisplay = new DrawPanel(displaySize);
this.add(mainDisplay);
// Bottom side
subOptions = new JPanel();
subOptions.setBackground(Color.black);
subOptions.setBounds(0, displaySize.height*7/8, displaySize.width, displaySize.height*1/8);
subOptions.setLayout(null);
this.add(subOptions);
Font fnt = new Font("Monofour",Font.BOLD,20);
lblAsking = new JLabel("Tops");
lblAsking.setBounds(50,25,100,50);
lblAsking.setForeground(Color.white);
lblAsking.setHorizontalAlignment(SwingConstants.CENTER);
lblAsking.setFont(fnt);
subOptions.add(lblAsking);
txtInput = new JTextField();
txtInput.setBounds(150, 25, 100, 50);
txtInput.setFont(fnt);
txtInput.addActionListener(listener);
subOptions.add(txtInput);
btnExe = new JButton("Confirm");
btnExe.setBounds(250,25,100,50);
btnExe.addActionListener(listener);
subOptions.add(btnExe);
btnPrev = new JButton("Prev");
btnPrev.setBounds(500,25,100,50);
btnPrev.addActionListener(listener);
btnPrev.setEnabled(false);
subOptions.add(btnPrev);
btnNext = new JButton("Next");
btnNext.setBounds(600,25,100,50);
btnNext.addActionListener(listener);
btnNext.setEnabled(false);
subOptions.add(btnNext);
} // Display()
private class HanoiListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
Object obj = e.getSource();
if((obj == txtInput) || (obj == btnExe)) {
nInput = Integer.parseInt(txtInput.getText());
logic = new Logic(nInput);
btnNext.setEnabled(true);
txtInput.setText("");
} else if(obj == btnPrev) {
nSequence--;
btnNext.setEnabled(true);
if(nSequence == 1) {
btnPrev.setEnabled(false);
}
} else if(obj == btnNext) {
nSequence++;
btnPrev.setEnabled(true);
if(nSequence == logic.getCount()+1) {
btnNext.setEnabled(false);
}
}
sequence = logic.getSequence();
mainDisplay.setBoard(nSequence-1, logic.getCount());
mainDisplay.setDataList(sequence.get(nSequence-1).getNowData(),nSequence-1);
mainDisplay.repaint();
} // actionPerformed()
} // HanoiListener class
} // Display class
3. Logic
import java.util.*;
public class Logic {
private int count;
private ArrayList nowList;
private ArrayList sequence;
private int aBar, bBar, cBar;
public Logic(int num) {
count = 0;
aBar = num;
bBar = cBar = 0;
// initialize Data - nowList
nowList = new ArrayList();
for(int i=0; i<num; i++) {
nowList.add(new HanoiData(i,num));
} // for i
// insert to sequence
ArrayList tmpList = new ArrayList();
int i=0;
for(HanoiData data : nowList) {
tmpList.add(new HanoiData(data, num-i));
i++;
}
sequence.add(new Sequence(tmpList));
// logic exe
this.calcHanoi(num,'A','B','C');
} // Logic()
public void calcHanoi(int num,char from, char other, char to) {
if (num == 1) {
++count;
this.moveBlock(num - 1, from, to);
} else {
++count;
this.calcHanoi(num - 1, from, to, other);
this.moveBlock(num - 1, from, to);
this.calcHanoi(num - 1, other, from, to);
}
} // clacHanoi()
public void moveBlock(int position, char from, char to) {
int tBar;
if(from == 'A') {
aBar--;
} else if(from == 'B') {
bBar--;
} else {
cBar--;
}
if(to == 'A') {
aBar++;
tBar=aBar;
} else if(to == 'B') {
bBar++;
tBar=bBar;
} else {
cBar++;
tBar=cBar;
}
for(HanoiData data : nowList) {
if(data.getPosition() == position) {
data.changeData(to, tBar);
break;
}
} // for nowList
ArrayList tmpList = new ArrayList();
for(int i=0; i<nowList.size(); i++){
tmpList.add(new HanoiData(nowList.get(i),tBar-i));
}
sequence.add(new Sequence(tmpList));
} // moveBlock()
public ArrayList getSequence() { return sequence; }
public int getCount() { return count; }
} // Logic class
4. HanoiData
import java.awt.*;
public class HanoiData {
private Point ptOne;
private int position, width, height;
private Color blockColor;
private int vertic;
private int stdx, total, stdPosit;
private char location;
public HanoiData(int num, int tot) {
ptOne = new Point();
location = 'A';
total = tot;
position = num;
stdPosit = total-position;
vertic = 550;
height = 40;
int r,g,b;
r = (int)(Math.random()*256);
g = (int)(Math.random()*256);
b = (int)(Math.random()*256);
blockColor = new Color(r,g,b);
this.setDatas();
} // HanoiData()
public HanoiData(HanoiData data, int x) {
ptOne = data.getPtOne();
location = data.getLocation();
total = data.getTotal();
position = data.getPosition();
stdPosit = data.getStdPosit();
vertic = 550;
height = 40;
width = data.getWidth();
blockColor = data.getColor();
this.setDatas();
} // HanoiData()
public void changeData(char change, int bar) {
location = change;
stdPosit = bar;
}
public void setDatas() {
int locStd;
if(location == 'A') {
locStd = 140;
} else if(location == 'B') {
locStd = 380;
} else {
locStd = 620;
}
stdx = 90/total;
ptOne.y = vertic - height*stdPosit;
ptOne.x = locStd - stdx*(position+1);
width = (locStd - ptOne.x)*2;
} // setDatas()
public Point getPtOne() { return ptOne; }
public int getPosition() { return position; }
public int getTotal() { return total; }
public char getLocation() { return location; }
public int getWidth() { return width; }
public int getHeight() { return height; }
public Color getColor() { return blockColor; }
public int getStdPosit() { return stdPosit; }
} // HanoiData class
5. Sequence
import java.util.*;
public class Sequence {
private ArrayListnow;
public Sequence(ArrayList tmp) {
now = tmp;
} // Sequence()
public ArrayList getNowData() { return now; }
} // Sequence class
6. DrawPanel
import javax.swing.*;
import java.awt.*;
import java.util.*;
public class DrawPanel extends JPanel {
private Dimension dsize;
private JLabel lblStatus, lblA, lblB, lblC;
private JPanel bottom;
private Graphics page;
private ArrayList tmpA;
// size 800, 600
public DrawPanel(Dimension displaySize) {
this.setBackground(Color.white);
this.setBounds(0, displaySize.height/8, displaySize.width, displaySize.height*3/4);
this.setLayout(null);
dsize = new Dimension(displaySize.width, displaySize.height*3/4);
lblStatus = new JLabel();
lblStatus.setBounds(displaySize.width*7/8,0,100,50);
lblStatus.setText("");
lblStatus.setForeground(Color.black);
lblStatus.setFont(new Font("Monofour",Font.ITALIC,25));
this.add(lblStatus);
tmpA = new ArrayList();
bottom = new JPanel();
bottom.setBounds(0,dsize.height-50,dsize.width,50);
bottom.setBackground(Color.gray);
bottom.setLayout(null);
this.add(bottom);
Font fnt = new Font("Monofour",Font.ITALIC,20);
lblA = new JLabel("A");
lblA.setBounds(135,0,50,50);
lblA.setFont(fnt);
lblA.setForeground(Color.white);
bottom.add(lblA);
lblB = new JLabel("B");
lblB.setBounds(375,0,50,50);
lblB.setFont(fnt);
lblB.setForeground(Color.white);
bottom.add(lblB);
lblC = new JLabel("C");
lblC.setBounds(615,0,50,50);
lblC.setFont(fnt);
lblC.setForeground(Color.white);
bottom.add(lblC);
} // DrawPanel()
public void drawTops() {
for(HanoiData data : tmpA) {
page.setColor(data.getColor());
page.fillRect(data.getPtOne().x,data.getPtOne().y,data.getWidth(),data.getHeight());
} // for HanoiData data
} // drawTops()
public void pillar() {
page.fillRect(120,dsize.height/4,40,dsize.height*3/4-50);
page.fillRect(360,dsize.height/4,40,dsize.height*3/4-50);
page.fillRect(600,dsize.height/4,40,dsize.height*3/4-50);
} // pillar()
public void paintComponent(Graphics p) {
super.paintComponent(p);
page = p;
this.pillar();
this.drawTops();
} // paintComponent()
public void setDataList(ArrayList nowList, int x) {
for(HanoiData data : nowList) {
tmpA.add(new HanoiData(data,x));
}
} // setDataList()
public void setBoard(int num, int goal) {
lblStatus.setText(num + " / " + goal);
}
} // DrawPanel class
코드 설명은 생략하겠습니다!
필요하신분은 각자 분석해서.. ㅎㅎ
질문하신다면 답변은 드리겠습니다.
위에서 말했듯이 계획없이 중구난방으로 만든 코드다보니..
난잡합니다 ㅎㅎ;;
나름 안쓰는 코드는 지운다고 했는데, 아직 남아있을 수도 있겠네요.
꼼꼼히 확인한건 아니어서.. ㅎㅎ
그럼 실행화면을 보여드리겠습니다.
< 실행 화면 >
1. 처음에 블록의 개수를 입력합니다.
2. 블록이 생성되고, 오른쪽 상단에 (현재 단계 / 총 단계) 가 표시됩니다.
( 실제로는 텍스트필드도 사라지게 해놨습니다. - 예시에서는 편의상 다시 써넣어 뒀을뿐입니다. )
3. prev / next 버튼을 이용하여 각 단계를 이동합니다.
( 첫 페이지, 마지막 페이지에서는 각각 prev, next 버튼이 disabled 됩니다. )
< 소감 >
이번 프로그램을 만들면서 부족한 코딩실력을 다시 절감하게 됬네요. ㅎㅎ
다음번에는 좀더 나은 설계, 그리고 코딩을 해보도록 하겠습니다.
좀더 발전해야죠 하하..
이상으로 UI로 구현한 하노이의 탑! 이었습니다.
'Programming Language > JAVA' 카테고리의 다른 글
(작성중) Maven Lifecycle (0) | 2019.11.21 |
---|---|
(작성중) Maven Repository (0) | 2019.11.19 |
Java) 하이로우 게임 (1) | 2019.06.02 |
Effective java 3/E - 직렬화 (item 85~90) (0) | 2019.01.16 |
Effective java 3/E - 동시성 (item 78~84) (0) | 2019.01.11 |