SlideShare una empresa de Scribd logo
1 de 28
Descargar para leer sin conexión
비주얼프로그래밍 Term 프로젝트 최종 보고서
(네모 로직 퍼즐)
학과 : 정보통신공학과
조원 : 20173028 전한종
20173030 정정범
담당 교수 : 박 동 규 교수님
제출일 : 2019. 12. 21
1. 프로젝트 주제
자바를 이용하여 네모로직퍼즐을 만들기
1) 이름
네모로직퍼즐
2) 게임설명
네모로직이란? 직사각형으로 배열된 칸들을 숫자를 보고 그리거나 지워나가는 퍼즐
3) 게임방식
- 쓰인 숫자만큼의 연속된 칸을 칠해야 함.
- 숫자와 숫자 사이에는 적어도 한 칸을 비워야 함.
- 숫자의 순서와 칠해진 칸의 순서는 일치해야 함.
+ 힌트 : 힌트 버튼을 누를 시 랜덤으로 가로 혹은 세로 줄의 정답을 알려줌
2. 개발 일정
11월 24일 ~ 11월 27일 - 프로젝트 구상 및 계획
11월 28일 ~ 12월 8일 – 가장 기본적인 알고리즘 코딩(네모로직의 보드판 행과 열 판, 정답
및 마우스 이벤트)
12월 9일 ~ 12월 18일 – 추가적인 구현(보드 크기 조정, 게임탭(New game, Answer, Exit), 드
래그 기능, 등)
12월 19일 ~ 12월 21일 – 피드백 및 최종 점검
3. 역할 분담
비대면이라도 디스코드 등 온라인 메신저를 통하여 회의 및 자신의 아이디어 및 코딩 알고리
즘을 같이 구현하였습니다.
4. 캡쳐 화면
최초 실행 화면 위쪽 탭에는 Game 메뉴가 있고, 왼쪽 상단에는 시작하자 마자 타이머가 돌아감.
시작할 때 기본적으로 입력되어 있는 네모로직 퍼즐이 구현됨.
보드에 마우스를 올릴시 마우스 올린 위치가 색칠되며 행과 열쪽에도 노란색으로 칠해져 가시성
을 높임
열 또는 행을 숫자에 맞게 채울 시 해당 열의 숫자는 파란색으로 표시
드래그 시 몇 칸 칠하는지 빨간색 글씨로 보이며 X, 파란색 칠하기 , 표시 지우기가 가능함.
구별하는 방법은 처음칸이 칠해져있는가 안칠해져있는가에 따라 표시가 지워지거나 표시를 함
정답을 맞출 시 파란색으로 칠해진 것은 검은색으로 칠해지며 곱표를 칠한 부분도 없어짐. 또한
다시 표시 할 수 없도록 마우스이벤트를 조정함. 타이머도 즉시 멈춤
게임 탭에는 New Game, Answer, Exit 항목이 있음
NewGame 을 누를시
문제를 선택 할 수 있는 탭이 나옴. 문제는 크기(10*10이든 20*20이든 상관없음)
예를 들어 강아지를 선택하고 열면
타이머는 초기화 되고 해당 문제로 보드가 바뀜
게임 탭에서 Answer를 누를 시 타이머는 멈추고 정답이 나옴
Exit 를 누르면 게임에서 나가짐
5. 느낀 점
처음에 알고리즘을 구현할 때 생각하고 코딩을 하였는데 좀처럼 쉽지 않았다.
생각한 대로 구현되지 않고 오류가 뜨기도 해서 당황 했지만 같이 하니까 이에 대해 이야기하면
서 오류를 고쳐 나가니 수월하게 끝냈다. 공동 작업이니 만큼 어려운 점 이 있으면 조원에게 서
로 물어보며 해결하니까 좋았다.
로직 문제를 만들 때 배열을 직접 입력해야 하는데 사람이 하다보니 30X30과 같은 커다란 로직
퍼즐의 경우 오류가 자주 나서 시간 만 더 있으면 로직 퍼즐을 제작할 수 있는 알고리즘도 구현
하고 싶다.
프로그램을 완성한 후 잘 돌아가는 것을 보니 뿌듯했다.
6. 전체 코드
NemoNemo.java
import javax.swing.*; //스윙 패키지 선언
import java.awt.*; //Font 상수 등을 위한 awt 패키지 선언
import java.awt.event.*;
import java.io.*;
import java.time.Duration;
/* 보드 크기 지정하는 법
* 30 행, 31 행의 NUM_COLUMN, NUM_ROW 를 바꾼다. -> NUM_COLUMN x NUM_ROW, 지금은 10 x 10 으로
되어있음
* 37 행의 data 에 알맞은 값을 넣는다. -> NUM_COLUMN * NUM_ROW 만큼, 지금은 100 자의 0 과 1 로 구성된
문자열임.
* */
public class Nemonemo extends JFrame implements ActionListener{
JPanel contentPane;
JPanel stopwatch;
//메뉴
JMenuBar menuBar = new JMenuBar();
JMenu gameMenu = new JMenu("Game");
//부착(add)할 클래스의 선언
Board board;
Column col;
Row row;
// 길이
int NUM_COLUMN = 20; // 열의 개수
int NUM_ROW = 20; // 행의 개수
//마우스 커서의 좌표
int mouseX = -1;
int mouseY = -1;
String data =
"1111111111111111111110000100000000100001101111111001111111011000010000000010000110111111100111
11110110000000000000000001101111111001111111011010000010010000010110111111100111111101100001000
00000100001101111111001111111011000010000000010000110111111100111111101101000001001000001011011
11111001111111011000000000000000000111111111111111111111100010001000100010011111111111111111111
110100010001000100011"; //문제의 정답
int[] temp; //플레이어가 입력한 답
int columnNums[][]; //해당 열에 연속한 '1'의 개수를 표시
int numOfColumn[]; //'0'으로 끊어진 연속한 1 의 개수가 몇 개인가를 표시
int rowNums[][]; //해당 행에 연속한 '1'의 개수를 표시
int numOfRow[]; //'0'으로 끊어진 연속한 1 의 개수가 몇 개인가를 표시
boolean endFlag = false; //퍼즐이 풀렸는지 여부
public static void main(String args[]) //Nemonemo 애플리케이션 시작점
{
Nemonemo nemo = new Nemonemo(); //네모네모로직 게임 생성
nemo.setVisible(true);
nemo.toFront();
}
public Nemonemo()
{
this.setTitle("LOGIC"); //애플리케이션 창의 타이틀 설정
this.setSize(121+20*(NUM_COLUMN+1), 170+20*(NUM_ROW+1));
//애플리케이션 크기 설정
//변수 초기화
temp = new int[NUM_COLUMN * NUM_ROW]; //가로 10 칸, 세로
10 칸으로 총 100 칸 선언
for(int i=0; i<(NUM_COLUMN * NUM_ROW); i++) //플레이어가
입력하기 전에 0 으로 모두 초기화
{
temp[i] = 0;
}
columnNums = new int[NUM_COLUMN][NUM_COLUMN];
numOfColumn = new int[NUM_COLUMN];
rowNums = new int[NUM_ROW][NUM_ROW];
numOfRow = new int[NUM_ROW];
contentPane = (JPanel) getContentPane();
contentPane.setBackground(Color.white);
contentPane.setLayout(null); //null 레이아웃으로 설정
createMenus(); //메뉴 생성
//column 생성
col = new Column(this);
contentPane.add(col);
col.setFont(new Font("SansSerif", Font.BOLD, 14));
col.setBounds(120, 0, 20*NUM_COLUMN+1, 120);
col.repaint();
//row 생성
row = new Row(this);
contentPane.add(row);
row.setFont(new Font("SansSerif", Font.BOLD, 14));
row.setBounds(0, 120, 120, 20*NUM_ROW+1);
//board 생성
board = new Board(this);
contentPane.add(board);
board.setFont(new Font("SansSerif", Font.BOLD, 14));
board.setBounds(120, 120, 20*NUM_COLUMN+1,
20*NUM_ROW+1);
//타이머 생성
stopwatch = new StopWatchPane();
stopwatch.setBackground(Color.white);
contentPane.add(stopwatch);
stopwatch.setBounds(0, 0, 119, 119);
}
public void createMenus()
{
this.setJMenuBar(menuBar);
menuBar.add(gameMenu);
//Game 메뉴의 서부메뉴 생성
JMenuItem newGame = new JMenuItem("New Game ...");
newGame.addActionListener(this);
newGame.setActionCommand("newGame");
gameMenu.add(newGame);
JMenuItem answerGame = new JMenuItem("Answer");
answerGame.addActionListener(this);
answerGame.setActionCommand("answerGame");
gameMenu.add(answerGame);
JMenuItem exitGame = new JMenuItem("Exit");
exitGame.addActionListener(this);
exitGame.setActionCommand("exitGame");
gameMenu.add(exitGame);
}
public void showLocation(int mouseX, int mouseY) //마우스 커서의위치를
표시
{
if(mouseX!=this.mouseX) //마우스 커서가 위치한 열이 변한 경우
{
this.mouseX = mouseX;
col.repaint();
}
if(mouseY!=this.mouseY) //마우스 커서가 위치한 행이 변한 경우
{
this.mouseY = mouseY;
row.repaint();
}
}
public void display() //퍼즐이 풀렸는지 여부를 검사
{ // a 번째 col, b 번째 row 의 값 = (COL * row) + col
boolean endFlag = true;
for(int j=0; (j<NUM_ROW)&&endFlag; j++)
for(int i=0; (i<NUM_COLUMN)&&endFlag; i++)
{
if((data.charAt(j*NUM_COLUMN+i)=='1')&&(temp[j*NUM_COLUMN+i]!=1))
endFlag=false; //채워야 할
칸을 모두채웠는지 검사
else
if((data.charAt(j*NUM_COLUMN+i)!='1')&&(temp[j*NUM_COLUMN+i]==1))
endFlag=false; //채우지
않아야 할 칸을채웠는지 검사
}
if(endFlag)
{
this.endFlag = endFlag;
board.repaint(); //퍼즐이 다 풀렸으면 보드의 칸을
채움
StopWatchPane.timer.stop();
}
}
public void actionPerformed(ActionEvent e) //선택한 메뉴에 따라실행할
루틴을 호출
{
String cmd = e.getActionCommand();
if(cmd.equals("newGame")) //네모네모로직 데이터를 불러와 새
게임을 시작
showOpenDialog();
else if(cmd.equals("answerGame")) //Answer 를 선택하면정답을
출력
{
this.endFlag = true;
board.repaint();
StopWatchPane.timer.stop();
}
else if(cmd.equals("exitGame")) //게임 종료
this.dispose();
}
//메뉴에서 New Game 선택 시, 퍼즐 데이터를 불러오는 메소드
public void showOpenDialog()
{
FileDialog fd = new FileDialog(this, "Open a File",
FileDialog.LOAD);
fd.setFile("*.txt"); //데이터 파일의 확장자는 txt
fd.setVisible(true);
if(fd.getFile()!=null)
{
String filename = fd.getFile();
String logicDir = fd.getDirectory();
if(filename.indexOf('.')!=-1)
{
filename = (filename.substring(0,
filename.indexOf('.'))).toLowerCase();
}
else
{
filename = filename.toLowerCase();
}
String logicName = filename;
File f;
FileInputStream from = null;
BufferedReader d = null;
try
{
f = new File(logicDir + logicName +
".txt");
from = new FileInputStream(f);
d = new BufferedReader(new
InputStreamReader(from));
int count_col = 0;
int count_row = 0;
data = d.readLine();
for(int i = 0; i < data.length(); i++) {
char tmpchar = data.charAt(i);
if(count_col == 0)
count_row ++;
if(tmpchar == ' ')
count_col ++;
}
NUM_COLUMN = count_col + 1;
NUM_ROW = count_row - 1;
data = data.replace(" ", "");
Column col;
Row row;
this.setTitle("LOGIC"); //애플리케이션 창의
타이틀 설정
this.setSize(121+20*(NUM_COLUMN+1),
170+20*(NUM_ROW+1)); //애플리케이션 크기 설정
//변수 초기화
temp = new int[NUM_COLUMN *
NUM_ROW]; //가로 10 칸, 세로 10 칸으로 총 100 칸 선언
for(int i=0; i<(NUM_COLUMN *
NUM_ROW); i++) //플레이어가 입력하기 전에 0 으로 모두 초기화
{
temp[i] = 0;
}
columnNums = new
int[NUM_COLUMN][NUM_COLUMN];
numOfColumn = new int[NUM_COLUMN];
rowNums = new
int[NUM_ROW][NUM_ROW];
numOfRow = new int[NUM_ROW];
contentPane = (JPanel) getContentPane();
contentPane.setBackground(Color.white);
contentPane.setLayout(null); //null
레이아웃으로 설정
//column 생성
col = new Column(this);
contentPane.add(col);
col.setFont(new Font("SansSerif",
Font.BOLD, 14));
col.setBounds(120, 0,
20*NUM_COLUMN+1, 120);
col.repaint();
//row 생성
row = new Row(this);
contentPane.add(row);
row.setFont(new Font("SansSerif",
Font.BOLD, 14));
row.setBounds(0, 120, 120,
20*NUM_ROW+1);
//board 생성
board = new Board(this);
contentPane.add(board);
board.setFont(new Font("SansSerif",
Font.BOLD, 14));
board.setBounds(120, 120,
20*NUM_COLUMN+1, 20*NUM_ROW+1);
//타이머 생성
StopWatchPane.timer.stop();
stopwatch = new StopWatchPane();
stopwatch.setBackground(Color.white);
contentPane.add(stopwatch);
stopwatch.setBounds(0, 0, 119, 119);
d.close();
}
catch(IOException e)
{
System.out.println("I/O ERROR: "+ e);
}
//변수 초기화
for(int i=0; i<NUM_COLUMN*NUM_ROW; i++)
{
temp[i] = 0;
}
this.endFlag = false;
//불러온 데이터에 맞춰 column, row 의 숫자를
재생성하고 깨끗한 보드를 다시 출력
col.getColumn();
row.getRow();
board.repaint();
}
}
public static class StopWatchPane extends JPanel {
private JLabel label;
private long lastTickTime;
private static Timer timer;
public StopWatchPane() {
setLayout(new GridBagLayout());
label = new JLabel(String.format("%04d:%02d:%02d.%03d",
0, 0, 0, 0));
timer = new Timer(100, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
long runningTime = System.currentTimeMillis() -
lastTickTime;
Duration duration =
Duration.ofMillis(runningTime);
long hours = duration.toHours();
duration = duration.minusHours(hours);
long minutes = duration.toMinutes();
duration = duration.minusMinutes(minutes);
long millis = duration.toMillis();
long seconds = millis / 1000;
millis -= (seconds * 1000);
label.setText(String.format("%04d:%02d:%02d.%03d", hours, minutes, seconds, millis));
}
});
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = 1;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.insets = new Insets(4, 4, 4, 4);
add(label, gbc);
lastTickTime = System.currentTimeMillis();
timer.start();
}
}
}
Board.java
import java.awt.*; //Color 상수 등을 위한 awt 패키지 선언
import java.awt.event.*;
public class Board extends Canvas implements MouseListener, MouseMotionListener
{
Nemonemo parent; //Nemonemo 클래스의 객체를 저장
boolean drag = false; //마우스 드래그 상태인지 여부
int startX, startY; //마우스 드래그를 시작한 좌표
int endX, endY; //마우스 드래그를 끝마친 좌표
Image offScr; //더블버퍼링을 위한 가상 화면
Graphics offG;
public Board(Nemonemo parent) //Nemonemo 클래스의 객체를 보관하고 리스너를 선언
{
this.parent = parent; //Nemonemo 클래스의 객체를 보관
this.addMouseListener(this); //마우스 사용을 위한 리스너 선언
this.addMouseMotionListener(this);
}
public void paint (Graphics g) //화면에 보드의 상태를 출력
{
offScr = createImage(20*parent.NUM_COLUMN+1, 20*parent.NUM_ROW+1); //가상 화면
생성
offG = offScr.getGraphics();
if(parent.mouseX!=-1 && parent.mouseY != -1 && parent.endFlag == false)
{
offG.setColor(Color.yellow);
for(int i = 0; i < parent.mouseX; i++)
offG.fillRect(20*i, 20*parent.mouseY, 20, 20);
for(int i = 0; i < parent.mouseY; i++)
offG.fillRect(20*parent.mouseX, 20*i, 20, 20);
offG.setColor(Color.orange);
offG.fillRect(20*parent.mouseX, 20*parent.mouseY, 20, 20); //마우스 커서가
있는 칸
}
for(int j=0; j<parent.NUM_ROW; j++)
for(int i=0; i<parent.NUM_COLUMN; i++)
{
if(parent.endFlag) //게임이 끝난 경우
{
if(parent.data.charAt(j*parent.NUM_COLUMN+i)=='1')
{
offG.fillRect(i*20, j*20, 20, 20); //칸을 채워서 문제가
풀렸음을 표시
}
}
else
{
if(parent.temp[j*parent.NUM_COLUMN+i]==1)
{
offG.setColor(Color.blue); //게임 진행중일
때는 ●표시
offG.fillRect(i*20, j*20, 20, 20);
}
else if(parent.temp[j*parent.NUM_COLUMN+i]==2)
{
offG.setColor(Color.red); //게임 진행중일
때는 X 표시
offG.drawLine(i*20, j*20, i*20+20, j*20+20);
offG.drawLine(i*20, j*20+20, i*20+20, j*20);
}
}
}
if(drag) //마우스를 드래그한 경우
{
offG.setColor(Color.orange);
if(startX==endX)
{
if(startY<endY)
{
offG.fillRect(20*startX, 20*startY, 20, 20*(endY-
startY+1));
offG.setColor(Color.red);
offG.drawString(String.valueOf(endY-startY+1),
endX*20+2, (endY+1)*20-2);
}
else
{
offG.fillRect(20*endX, 20*endY, 20, 20*(startY-
endY+1));
offG.setColor(Color.red);
offG.drawString(String.valueOf(startY-endY+1),
endX*20+2, (endY+1)*20-2);
}
}
else if(startY==endY)
{
if(startX<endX)
{
offG.fillRect(20*startX, 20*startY, 20*(endX-startX+1),
20);
offG.setColor(Color.red);
offG.drawString(String.valueOf(endX-startX+1),
endX*20+2, (endY+1)*20-2);
}
else
{
offG.fillRect(20*endX, 20*endY, 20*(startX-endX+1),
20);
offG.setColor(Color.red);
offG.drawString(String.valueOf(startX-endX+1),
endX*20+2, (endY+1)*20-2);
}
}
}
for(int j=0; j<parent.NUM_ROW; j++) //격자 출력
for(int i=0; i<parent.NUM_COLUMN; i++)
{
offG.setColor(Color.black);
offG.drawRect(i*20, j*20, 20, 20);
}
offG.setColor(Color.black);
for(int i=0; i<=20*parent.NUM_COLUMN; i+=20*5)
{
offG.drawLine(i-1, 0, i-1, 20*parent.NUM_ROW);
offG.drawLine(i+1, 0, i+1, 20*parent.NUM_ROW);
}
for(int i=0; i<=20*parent.NUM_ROW; i+=20*5)
{
offG.drawLine(0, i-1, 20*parent.NUM_COLUMN, i-1);
offG.drawLine(0, i+1, 20*parent.NUM_COLUMN, i+1);
}
g.drawImage(offScr, 0, 0, this); //가상 화면을 실제 화면으로 복사
}
public void update(Graphics g)
{
paint(g);
}
@Override
public void mousePressed(MouseEvent e) //플레이어가 마우스 버튼을 누른 경우
{
int x = e.getX();
int y = e.getY();
if((x/20)>=parent.NUM_COLUMN) return;
if((y/20)>=parent.NUM_ROW) return;
if(parent.endFlag)return;
startX = x/20;
startY = y/20;
}
public void mouseReleased(MouseEvent e) //플레이어가 마우스 버튼을 놓은 경우
{
int x = e.getX();
int y = e.getY();
if((x/20)>=parent.NUM_COLUMN) return;
if((y/20)>=parent.NUM_ROW) return;
if(parent.endFlag)return;
if((e.getModifiers() & InputEvent.BUTTON3_MASK)!=0) //마우스 오른쪽 버튼
{
setTemp(x, y, 2);
}
else //마우스 왼쪽 버튼
{
setTemp(x, y, 1);
}
parent.display(); //퍼즐이 풀렸는지 검사
this.drag = false;
repaint();
}
public void mouseMoved(MouseEvent e) //마우스가 움직인 경우
{
int x = e.getX();
int y = e.getY();
if((x/20)>=parent.NUM_COLUMN) return;
if((y/20)>=parent.NUM_ROW) return;
parent.showLocation(x/20, y/20); //column 과 row 에 마우스 커서의 위치를 표시
repaint();
}
public void mouseExited(MouseEvent e) //마우스가 보드를 벗어난 경우
{
parent.showLocation(-1, -1); //column 과 row 에 마우스 커서의 위치를 표시하지 않음
this.drag = false;
repaint();
}
public void mouseClicked(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {
}
public void mouseDragged(MouseEvent e) //마우스를 드래그한 경우
{
int x = e.getX();
int y = e.getY();
if((x/20)>=parent.NUM_COLUMN) return;
if((y/20)>=parent.NUM_ROW) return;
parent.showLocation(x/20, y/20); //column 과 row 에 마우스 커서의 위치를 표시
this.drag = true;
endX = x/20;
endY = y/20;
repaint();
}
private void setTemp(int x, int y, int value)
//플레이어의 입력을 temp 배열에 저장
{
int i;
if(drag)
{
if(startX==endX)
{
if(startY<endY)
{
if(parent.temp[startX+startY*parent.NUM_COLUMN] !=
0) {
for(i=startY; i<=endY; i++)
parent.temp[startX+i*parent.NUM_COLUMN] = 0;
}
else {
for(i=startY; i<=endY; i++)
parent.temp[startX+i*parent.NUM_COLUMN] = value;
}
}
else if(startY>endY)
{
if(parent.temp[startX+startY*parent.NUM_COLUMN] !=
0) {
for(i=endY; i<=startY; i++)
parent.temp[startX+i*parent.NUM_COLUMN] = 0;
}
else {
for(i=endY; i<=startY; i++)
parent.temp[startX+i*parent.NUM_COLUMN] = value;
}
}
else //startY == endY
{
if(parent.temp[startX+startY*parent.NUM_COLUMN]!=0)
parent.temp[startX+startY*parent.NUM_COLUMN] = 0;
else
parent.temp[startX+startY*parent.NUM_COLUMN] = value;
}
}
else if(startY==endY)
{
if(startX<endX)
{
if(parent.temp[startX+startY*parent.NUM_COLUMN] !=
0) {
for(i=startX; i<=endX; i++)
parent.temp[i+startY*parent.NUM_COLUMN] = 0;
}
else {
for(i=startX; i<=endX; i++)
parent.temp[i+startY*parent.NUM_COLUMN] = value;
}
}
else if(startX>endX)
{
if(parent.temp[startX+startY*parent.NUM_COLUMN] !=
0) {
for(i=endX; i<=startX; i++)
parent.temp[i+startY*parent.NUM_COLUMN] = 0;
}
else {
for(i=endX; i<=startX; i++)
parent.temp[i+startY*parent.NUM_COLUMN] = value;
}
}
else // startX == endX
{
if(parent.temp[startX+startY*parent.NUM_COLUMN]!=0)
parent.temp[startX+startY*parent.NUM_COLUMN] = 0;
else
parent.temp[startX+startY*parent.NUM_COLUMN] = value;
}
}
}
else
{
if(parent.temp[x/20+y/20*parent.NUM_COLUMN]!=0)
parent.temp[x/20+y/20*parent.NUM_COLUMN] = 0;
else
parent.temp[x/20+y/20*parent.NUM_COLUMN] = value;
}
}
}
Column.java
import java.awt.*; //Color 상수 등을 위한 awt 패키지 선언
public class Column extends Canvas {
Nemonemo parent; //Nemonemo 클래스의 객체를 저장
Image offScr; //더블버퍼링을 위한 가상 화면
Graphics offG;
public Column(Nemonemo parent) //Nemonemo 클래스의 객체를 보관하고 모든 열의 연속한 '1'의
개수를 계산
{
this.parent = parent; //Nemonemo 클래스의 객체를 보관
getColumn();
}
public void getColumn() //데이터에 맞춰 column 의 숫자를 생성
{
for(int i=0; i<parent.NUM_COLUMN; i++) //모든 열에 연속한 '1'의 개수를 계산
{
parent.numOfColumn[i] = getNumber(i);
}
}
int getNumber(int start) //해당하는 열의 연속한 '1'의 개수를 계산
{
int count = 0; //연속된 '1'의 개수
int pos = 0; //몇 번째 연속된 '1'의 개수를 나타내는 수인지를 표시
for(int i = start; i<parent.NUM_COLUMN * parent.NUM_ROW; i+=parent.NUM_COLUMN)
//같은 열에 속한 data 의 값을 비교
{
if(parent.data.charAt(i)=='0' && count>0) //연속하지 않은 경우('0'인 경우)
{
parent.columnNums[start][pos++] = count;
count = 0;
}
else if(parent.data.charAt(i)=='1' && count>=0) //연속한 경우('1'인 경우)
{
count++;
}
}
if(count>0)
parent.columnNums[start][pos++] = count;
if(pos==0)
parent.columnNums[start][pos++] = 0;
return pos;
}
public void paint (Graphics g) //화면에 column 을 출력
{
offScr = createImage(20*parent.NUM_COLUMN+1, 121); //가상 화면 생성
offG = offScr.getGraphics();
if(parent.mouseX!=-1)
{
offG.setColor(Color.yellow);
offG.fillRect(20*parent.mouseX, 0, 19, 120); //마우스 커서가 있는 열의 경우
}
int CountofColumn[] = new int[parent.NUM_COLUMN];
int CountofTemp[] = new int[parent.NUM_COLUMN];
int right[] = new int[parent.NUM_COLUMN];
for(int i=0; i<parent.NUM_COLUMN; i++) {
for(int j=0; j<parent.NUM_ROW; j++)
{
if(parent.data.charAt(j*parent.NUM_COLUMN+i) == '1')
CountofColumn[i] += 1;
if(parent.temp[j*parent.NUM_COLUMN+i] == 1)
CountofTemp[i] += 1;
}
if(CountofColumn[i]==CountofTemp[i])
right[i] = 1;
else
right[i] = 0;
}
for(int i=0; i<parent.NUM_COLUMN; i++)
{
offG.setColor(Color.black);
offG.drawLine(i*20, 0, i*20, 220);
for(int j=0; j<parent.numOfColumn[i]; j++) //숫자 출력
{
if(right[i] == 1)
offG.setColor(Color.blue);
else
offG.setColor(Color.black);
if(String.valueOf(parent.columnNums[i][j]).length()<2)
offG.drawString(String.valueOf(parent.columnNums[i][j]), i*20+9, (100-
parent.numOfColumn[i]*20+j*20)+39);
else
offG.drawString(String.valueOf(parent.columnNums[i][j]), i*20+1, (100-
parent.numOfColumn[i]*20+j*20)+39);
}
}
offG.setColor(Color.black);
for(int i=0; i<=20*parent.NUM_COLUMN; i+=20*5)
{
offG.drawLine(i-1, 0, i-1, 120);
offG.drawLine(i+1, 0, i+1, 120);
}
offG.drawLine(200, 0, 200, 120);
offG.drawLine(0, 120, 200, 120);
g.drawImage(offScr, 0, 0, this);
}
public void update(Graphics g)
{
paint(g);
}
}
Row.java
import java.awt.*; //Color 상수 등을 위한 awt 패키지 선언
public class Row extends Canvas{
Nemonemo parent; //Nemonemo 클래스의 객체를 저장
Image offScr; //더블버퍼링을 위한 가상 화면
Graphics offG;
public Row(Nemonemo parent) //Nemonemo 클래스의 객체를 보관하고 모든 행의 연속한 '1'의
개수를 계산
{
this.parent = parent; //Nemonemo 클래스의 객체를 보관
getRow();
}
public void getRow() //데이터에 맞춰 row 의 숫자를 생성
{
for(int i=0; i<parent.NUM_ROW; i++) //모든 행에 연속한 '1'의 개수를 계산
{
parent.numOfRow[i] = getNumber(i);
}
}
int getNumber(int start) //해당하는 행의 연속한 '1'의 개수를 계산
{
int count = 0; //연속된 '1'의 개수
int pos = 0; //몇 번째 연속된 '1'의 개수를 나타내는 수인지를 표시
for(int i=start*parent.NUM_COLUMN; i<(start+1)*parent.NUM_COLUMN; i++) //같은 행에
속한 data 의 값을 비교
{
if(parent.data.charAt(i)=='0' && count>0) //연속하지 않은 경우('0'인 경우)
{
parent.rowNums[start][pos++] = count;
count = 0;
}
else if(parent.data.charAt(i)=='1' && count>=0) //연속한 경우('1'인 경우)
{
count++;
}
}
if(count>0)
parent.rowNums[start][pos++] = count;
if(pos==0)
parent.rowNums[start][pos++] = 0;
return pos;
}
public void paint (Graphics g) //화면에 row 를 출력
{
offScr = createImage(121, 20*parent.NUM_ROW+1); //가상 화면 생성
offG = offScr.getGraphics();
if(parent.mouseY!=-1)
{
offG.setColor(Color.yellow);
offG.fillRect(0, 20*parent.mouseY, 120, 19); //마우스 커서가 있는 행의 경우
}
int CountofRow[] = new int[parent.NUM_ROW];
int CountofTemp[] = new int[parent.NUM_ROW];
int right[] = new int[parent.NUM_ROW];
for(int i=0; i<parent.NUM_ROW; i++) {
for(int j=0; j<parent.NUM_COLUMN; j++)
{
if(parent.data.charAt(i*parent.NUM_COLUMN+j) == '1')
CountofRow[i] += 1;
if(parent.temp[i*parent.NUM_COLUMN+j] == 1)
CountofTemp[i] += 1;
}
if(CountofRow[i]==CountofTemp[i])
right[i] = 1;
else
right[i] = 0;
}
for(int i=0; i<parent.NUM_ROW; i++)
{
offG.setColor(Color.black);
offG.drawLine(0, i*20, 120, i*20);
for(int j=0; j<parent.numOfRow[i]; j++) //숫자 출력
{
if(right[i] == 1)
offG.setColor(Color.blue);
else
offG.setColor(Color.black);
if(String.valueOf(parent.rowNums[i][j]).length()<2) {
offG.drawString(String.valueOf(parent.rowNums[i][j]),
(100-parent.numOfRow[i]*20)+j*20+27, i*20+18); offG.setColor(Color.black); }
else {
offG.drawString(String.valueOf(parent.rowNums[i][j]),
(100-parent.numOfRow[i]*20)+j*20+21, i*20+18); offG.setColor(Color.black); }
}
}
offG.setColor(Color.black);
for(int i=0; i<=20*parent.NUM_ROW; i+=20*5)
{
offG.drawLine(0, i-1, 120, i-1);
offG.drawLine(0, i+1, 120, i+1);
}
offG.drawLine(0, 200, 120, 200);
offG.drawLine(120, 0, 120, 200);
g.drawImage(offScr, 0, 0, this);
}
public void update(Graphics g)
{
paint(g);
}
}

Más contenido relacionado

Destacado

2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by HubspotMarius Sescu
 
Everything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTEverything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTExpeed Software
 
Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsPixeldarts
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthThinkNow
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfmarketingartwork
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024Neil Kimberley
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)contently
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024Albert Qian
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsKurio // The Social Media Age(ncy)
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Search Engine Journal
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summarySpeakerHub
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next Tessa Mero
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentLily Ray
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best PracticesVit Horky
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project managementMindGenius
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...RachelPearson36
 

Destacado (20)

2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot2024 State of Marketing Report – by Hubspot
2024 State of Marketing Report – by Hubspot
 
Everything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPTEverything You Need To Know About ChatGPT
Everything You Need To Know About ChatGPT
 
Product Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage EngineeringsProduct Design Trends in 2024 | Teenage Engineerings
Product Design Trends in 2024 | Teenage Engineerings
 
How Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental HealthHow Race, Age and Gender Shape Attitudes Towards Mental Health
How Race, Age and Gender Shape Attitudes Towards Mental Health
 
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdfAI Trends in Creative Operations 2024 by Artwork Flow.pdf
AI Trends in Creative Operations 2024 by Artwork Flow.pdf
 
Skeleton Culture Code
Skeleton Culture CodeSkeleton Culture Code
Skeleton Culture Code
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search Intent
 
How to have difficult conversations
How to have difficult conversations How to have difficult conversations
How to have difficult conversations
 
Introduction to Data Science
Introduction to Data ScienceIntroduction to Data Science
Introduction to Data Science
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best Practices
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project management
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
 

Visual term project2

  • 1. 비주얼프로그래밍 Term 프로젝트 최종 보고서 (네모 로직 퍼즐) 학과 : 정보통신공학과 조원 : 20173028 전한종 20173030 정정범 담당 교수 : 박 동 규 교수님 제출일 : 2019. 12. 21
  • 2. 1. 프로젝트 주제 자바를 이용하여 네모로직퍼즐을 만들기 1) 이름 네모로직퍼즐 2) 게임설명 네모로직이란? 직사각형으로 배열된 칸들을 숫자를 보고 그리거나 지워나가는 퍼즐 3) 게임방식 - 쓰인 숫자만큼의 연속된 칸을 칠해야 함. - 숫자와 숫자 사이에는 적어도 한 칸을 비워야 함. - 숫자의 순서와 칠해진 칸의 순서는 일치해야 함. + 힌트 : 힌트 버튼을 누를 시 랜덤으로 가로 혹은 세로 줄의 정답을 알려줌 2. 개발 일정 11월 24일 ~ 11월 27일 - 프로젝트 구상 및 계획 11월 28일 ~ 12월 8일 – 가장 기본적인 알고리즘 코딩(네모로직의 보드판 행과 열 판, 정답 및 마우스 이벤트) 12월 9일 ~ 12월 18일 – 추가적인 구현(보드 크기 조정, 게임탭(New game, Answer, Exit), 드 래그 기능, 등) 12월 19일 ~ 12월 21일 – 피드백 및 최종 점검 3. 역할 분담 비대면이라도 디스코드 등 온라인 메신저를 통하여 회의 및 자신의 아이디어 및 코딩 알고리 즘을 같이 구현하였습니다.
  • 3. 4. 캡쳐 화면 최초 실행 화면 위쪽 탭에는 Game 메뉴가 있고, 왼쪽 상단에는 시작하자 마자 타이머가 돌아감. 시작할 때 기본적으로 입력되어 있는 네모로직 퍼즐이 구현됨.
  • 4. 보드에 마우스를 올릴시 마우스 올린 위치가 색칠되며 행과 열쪽에도 노란색으로 칠해져 가시성 을 높임 열 또는 행을 숫자에 맞게 채울 시 해당 열의 숫자는 파란색으로 표시 드래그 시 몇 칸 칠하는지 빨간색 글씨로 보이며 X, 파란색 칠하기 , 표시 지우기가 가능함. 구별하는 방법은 처음칸이 칠해져있는가 안칠해져있는가에 따라 표시가 지워지거나 표시를 함
  • 5. 정답을 맞출 시 파란색으로 칠해진 것은 검은색으로 칠해지며 곱표를 칠한 부분도 없어짐. 또한 다시 표시 할 수 없도록 마우스이벤트를 조정함. 타이머도 즉시 멈춤 게임 탭에는 New Game, Answer, Exit 항목이 있음
  • 6. NewGame 을 누를시 문제를 선택 할 수 있는 탭이 나옴. 문제는 크기(10*10이든 20*20이든 상관없음) 예를 들어 강아지를 선택하고 열면 타이머는 초기화 되고 해당 문제로 보드가 바뀜 게임 탭에서 Answer를 누를 시 타이머는 멈추고 정답이 나옴 Exit 를 누르면 게임에서 나가짐
  • 7. 5. 느낀 점 처음에 알고리즘을 구현할 때 생각하고 코딩을 하였는데 좀처럼 쉽지 않았다. 생각한 대로 구현되지 않고 오류가 뜨기도 해서 당황 했지만 같이 하니까 이에 대해 이야기하면 서 오류를 고쳐 나가니 수월하게 끝냈다. 공동 작업이니 만큼 어려운 점 이 있으면 조원에게 서 로 물어보며 해결하니까 좋았다. 로직 문제를 만들 때 배열을 직접 입력해야 하는데 사람이 하다보니 30X30과 같은 커다란 로직 퍼즐의 경우 오류가 자주 나서 시간 만 더 있으면 로직 퍼즐을 제작할 수 있는 알고리즘도 구현 하고 싶다. 프로그램을 완성한 후 잘 돌아가는 것을 보니 뿌듯했다.
  • 8. 6. 전체 코드 NemoNemo.java import javax.swing.*; //스윙 패키지 선언 import java.awt.*; //Font 상수 등을 위한 awt 패키지 선언 import java.awt.event.*; import java.io.*; import java.time.Duration; /* 보드 크기 지정하는 법 * 30 행, 31 행의 NUM_COLUMN, NUM_ROW 를 바꾼다. -> NUM_COLUMN x NUM_ROW, 지금은 10 x 10 으로 되어있음 * 37 행의 data 에 알맞은 값을 넣는다. -> NUM_COLUMN * NUM_ROW 만큼, 지금은 100 자의 0 과 1 로 구성된 문자열임. * */ public class Nemonemo extends JFrame implements ActionListener{ JPanel contentPane; JPanel stopwatch; //메뉴 JMenuBar menuBar = new JMenuBar(); JMenu gameMenu = new JMenu("Game"); //부착(add)할 클래스의 선언 Board board; Column col; Row row; // 길이 int NUM_COLUMN = 20; // 열의 개수 int NUM_ROW = 20; // 행의 개수 //마우스 커서의 좌표 int mouseX = -1; int mouseY = -1; String data = "1111111111111111111110000100000000100001101111111001111111011000010000000010000110111111100111 11110110000000000000000001101111111001111111011010000010010000010110111111100111111101100001000 00000100001101111111001111111011000010000000010000110111111100111111101101000001001000001011011 11111001111111011000000000000000000111111111111111111111100010001000100010011111111111111111111 110100010001000100011"; //문제의 정답 int[] temp; //플레이어가 입력한 답 int columnNums[][]; //해당 열에 연속한 '1'의 개수를 표시 int numOfColumn[]; //'0'으로 끊어진 연속한 1 의 개수가 몇 개인가를 표시 int rowNums[][]; //해당 행에 연속한 '1'의 개수를 표시
  • 9. int numOfRow[]; //'0'으로 끊어진 연속한 1 의 개수가 몇 개인가를 표시 boolean endFlag = false; //퍼즐이 풀렸는지 여부 public static void main(String args[]) //Nemonemo 애플리케이션 시작점 { Nemonemo nemo = new Nemonemo(); //네모네모로직 게임 생성 nemo.setVisible(true); nemo.toFront(); } public Nemonemo() { this.setTitle("LOGIC"); //애플리케이션 창의 타이틀 설정 this.setSize(121+20*(NUM_COLUMN+1), 170+20*(NUM_ROW+1)); //애플리케이션 크기 설정 //변수 초기화 temp = new int[NUM_COLUMN * NUM_ROW]; //가로 10 칸, 세로 10 칸으로 총 100 칸 선언 for(int i=0; i<(NUM_COLUMN * NUM_ROW); i++) //플레이어가 입력하기 전에 0 으로 모두 초기화 { temp[i] = 0; } columnNums = new int[NUM_COLUMN][NUM_COLUMN]; numOfColumn = new int[NUM_COLUMN]; rowNums = new int[NUM_ROW][NUM_ROW]; numOfRow = new int[NUM_ROW]; contentPane = (JPanel) getContentPane(); contentPane.setBackground(Color.white); contentPane.setLayout(null); //null 레이아웃으로 설정 createMenus(); //메뉴 생성 //column 생성 col = new Column(this); contentPane.add(col); col.setFont(new Font("SansSerif", Font.BOLD, 14)); col.setBounds(120, 0, 20*NUM_COLUMN+1, 120); col.repaint(); //row 생성 row = new Row(this); contentPane.add(row); row.setFont(new Font("SansSerif", Font.BOLD, 14)); row.setBounds(0, 120, 120, 20*NUM_ROW+1);
  • 10. //board 생성 board = new Board(this); contentPane.add(board); board.setFont(new Font("SansSerif", Font.BOLD, 14)); board.setBounds(120, 120, 20*NUM_COLUMN+1, 20*NUM_ROW+1); //타이머 생성 stopwatch = new StopWatchPane(); stopwatch.setBackground(Color.white); contentPane.add(stopwatch); stopwatch.setBounds(0, 0, 119, 119); } public void createMenus() { this.setJMenuBar(menuBar); menuBar.add(gameMenu); //Game 메뉴의 서부메뉴 생성 JMenuItem newGame = new JMenuItem("New Game ..."); newGame.addActionListener(this); newGame.setActionCommand("newGame"); gameMenu.add(newGame); JMenuItem answerGame = new JMenuItem("Answer"); answerGame.addActionListener(this); answerGame.setActionCommand("answerGame"); gameMenu.add(answerGame); JMenuItem exitGame = new JMenuItem("Exit"); exitGame.addActionListener(this); exitGame.setActionCommand("exitGame"); gameMenu.add(exitGame); } public void showLocation(int mouseX, int mouseY) //마우스 커서의위치를 표시 { if(mouseX!=this.mouseX) //마우스 커서가 위치한 열이 변한 경우 { this.mouseX = mouseX; col.repaint(); } if(mouseY!=this.mouseY) //마우스 커서가 위치한 행이 변한 경우 { this.mouseY = mouseY; row.repaint();
  • 11. } } public void display() //퍼즐이 풀렸는지 여부를 검사 { // a 번째 col, b 번째 row 의 값 = (COL * row) + col boolean endFlag = true; for(int j=0; (j<NUM_ROW)&&endFlag; j++) for(int i=0; (i<NUM_COLUMN)&&endFlag; i++) { if((data.charAt(j*NUM_COLUMN+i)=='1')&&(temp[j*NUM_COLUMN+i]!=1)) endFlag=false; //채워야 할 칸을 모두채웠는지 검사 else if((data.charAt(j*NUM_COLUMN+i)!='1')&&(temp[j*NUM_COLUMN+i]==1)) endFlag=false; //채우지 않아야 할 칸을채웠는지 검사 } if(endFlag) { this.endFlag = endFlag; board.repaint(); //퍼즐이 다 풀렸으면 보드의 칸을 채움 StopWatchPane.timer.stop(); } } public void actionPerformed(ActionEvent e) //선택한 메뉴에 따라실행할 루틴을 호출 { String cmd = e.getActionCommand(); if(cmd.equals("newGame")) //네모네모로직 데이터를 불러와 새 게임을 시작 showOpenDialog(); else if(cmd.equals("answerGame")) //Answer 를 선택하면정답을 출력 { this.endFlag = true; board.repaint(); StopWatchPane.timer.stop(); } else if(cmd.equals("exitGame")) //게임 종료 this.dispose(); } //메뉴에서 New Game 선택 시, 퍼즐 데이터를 불러오는 메소드 public void showOpenDialog() {
  • 12. FileDialog fd = new FileDialog(this, "Open a File", FileDialog.LOAD); fd.setFile("*.txt"); //데이터 파일의 확장자는 txt fd.setVisible(true); if(fd.getFile()!=null) { String filename = fd.getFile(); String logicDir = fd.getDirectory(); if(filename.indexOf('.')!=-1) { filename = (filename.substring(0, filename.indexOf('.'))).toLowerCase(); } else { filename = filename.toLowerCase(); } String logicName = filename; File f; FileInputStream from = null; BufferedReader d = null; try { f = new File(logicDir + logicName + ".txt"); from = new FileInputStream(f); d = new BufferedReader(new InputStreamReader(from)); int count_col = 0; int count_row = 0; data = d.readLine(); for(int i = 0; i < data.length(); i++) { char tmpchar = data.charAt(i); if(count_col == 0) count_row ++; if(tmpchar == ' ') count_col ++; } NUM_COLUMN = count_col + 1; NUM_ROW = count_row - 1; data = data.replace(" ", "");
  • 13. Column col; Row row; this.setTitle("LOGIC"); //애플리케이션 창의 타이틀 설정 this.setSize(121+20*(NUM_COLUMN+1), 170+20*(NUM_ROW+1)); //애플리케이션 크기 설정 //변수 초기화 temp = new int[NUM_COLUMN * NUM_ROW]; //가로 10 칸, 세로 10 칸으로 총 100 칸 선언 for(int i=0; i<(NUM_COLUMN * NUM_ROW); i++) //플레이어가 입력하기 전에 0 으로 모두 초기화 { temp[i] = 0; } columnNums = new int[NUM_COLUMN][NUM_COLUMN]; numOfColumn = new int[NUM_COLUMN]; rowNums = new int[NUM_ROW][NUM_ROW]; numOfRow = new int[NUM_ROW]; contentPane = (JPanel) getContentPane(); contentPane.setBackground(Color.white); contentPane.setLayout(null); //null 레이아웃으로 설정 //column 생성 col = new Column(this); contentPane.add(col); col.setFont(new Font("SansSerif", Font.BOLD, 14)); col.setBounds(120, 0, 20*NUM_COLUMN+1, 120); col.repaint(); //row 생성 row = new Row(this); contentPane.add(row); row.setFont(new Font("SansSerif", Font.BOLD, 14)); row.setBounds(0, 120, 120, 20*NUM_ROW+1); //board 생성 board = new Board(this); contentPane.add(board);
  • 14. board.setFont(new Font("SansSerif", Font.BOLD, 14)); board.setBounds(120, 120, 20*NUM_COLUMN+1, 20*NUM_ROW+1); //타이머 생성 StopWatchPane.timer.stop(); stopwatch = new StopWatchPane(); stopwatch.setBackground(Color.white); contentPane.add(stopwatch); stopwatch.setBounds(0, 0, 119, 119); d.close(); } catch(IOException e) { System.out.println("I/O ERROR: "+ e); } //변수 초기화 for(int i=0; i<NUM_COLUMN*NUM_ROW; i++) { temp[i] = 0; } this.endFlag = false; //불러온 데이터에 맞춰 column, row 의 숫자를 재생성하고 깨끗한 보드를 다시 출력 col.getColumn(); row.getRow(); board.repaint(); } } public static class StopWatchPane extends JPanel { private JLabel label; private long lastTickTime; private static Timer timer; public StopWatchPane() { setLayout(new GridBagLayout()); label = new JLabel(String.format("%04d:%02d:%02d.%03d", 0, 0, 0, 0)); timer = new Timer(100, new ActionListener() {
  • 15. @Override public void actionPerformed(ActionEvent e) { long runningTime = System.currentTimeMillis() - lastTickTime; Duration duration = Duration.ofMillis(runningTime); long hours = duration.toHours(); duration = duration.minusHours(hours); long minutes = duration.toMinutes(); duration = duration.minusMinutes(minutes); long millis = duration.toMillis(); long seconds = millis / 1000; millis -= (seconds * 1000); label.setText(String.format("%04d:%02d:%02d.%03d", hours, minutes, seconds, millis)); } }); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 0; gbc.weightx = 1; gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.insets = new Insets(4, 4, 4, 4); add(label, gbc); lastTickTime = System.currentTimeMillis(); timer.start(); } } }
  • 16. Board.java import java.awt.*; //Color 상수 등을 위한 awt 패키지 선언 import java.awt.event.*; public class Board extends Canvas implements MouseListener, MouseMotionListener { Nemonemo parent; //Nemonemo 클래스의 객체를 저장 boolean drag = false; //마우스 드래그 상태인지 여부 int startX, startY; //마우스 드래그를 시작한 좌표 int endX, endY; //마우스 드래그를 끝마친 좌표 Image offScr; //더블버퍼링을 위한 가상 화면 Graphics offG; public Board(Nemonemo parent) //Nemonemo 클래스의 객체를 보관하고 리스너를 선언 { this.parent = parent; //Nemonemo 클래스의 객체를 보관 this.addMouseListener(this); //마우스 사용을 위한 리스너 선언 this.addMouseMotionListener(this); } public void paint (Graphics g) //화면에 보드의 상태를 출력 { offScr = createImage(20*parent.NUM_COLUMN+1, 20*parent.NUM_ROW+1); //가상 화면 생성 offG = offScr.getGraphics(); if(parent.mouseX!=-1 && parent.mouseY != -1 && parent.endFlag == false) { offG.setColor(Color.yellow); for(int i = 0; i < parent.mouseX; i++) offG.fillRect(20*i, 20*parent.mouseY, 20, 20); for(int i = 0; i < parent.mouseY; i++) offG.fillRect(20*parent.mouseX, 20*i, 20, 20); offG.setColor(Color.orange); offG.fillRect(20*parent.mouseX, 20*parent.mouseY, 20, 20); //마우스 커서가 있는 칸 } for(int j=0; j<parent.NUM_ROW; j++) for(int i=0; i<parent.NUM_COLUMN; i++) { if(parent.endFlag) //게임이 끝난 경우 { if(parent.data.charAt(j*parent.NUM_COLUMN+i)=='1') {
  • 17. offG.fillRect(i*20, j*20, 20, 20); //칸을 채워서 문제가 풀렸음을 표시 } } else { if(parent.temp[j*parent.NUM_COLUMN+i]==1) { offG.setColor(Color.blue); //게임 진행중일 때는 ●표시 offG.fillRect(i*20, j*20, 20, 20); } else if(parent.temp[j*parent.NUM_COLUMN+i]==2) { offG.setColor(Color.red); //게임 진행중일 때는 X 표시 offG.drawLine(i*20, j*20, i*20+20, j*20+20); offG.drawLine(i*20, j*20+20, i*20+20, j*20); } } } if(drag) //마우스를 드래그한 경우 { offG.setColor(Color.orange); if(startX==endX) { if(startY<endY) { offG.fillRect(20*startX, 20*startY, 20, 20*(endY- startY+1)); offG.setColor(Color.red); offG.drawString(String.valueOf(endY-startY+1), endX*20+2, (endY+1)*20-2); } else { offG.fillRect(20*endX, 20*endY, 20, 20*(startY- endY+1)); offG.setColor(Color.red); offG.drawString(String.valueOf(startY-endY+1), endX*20+2, (endY+1)*20-2); } } else if(startY==endY) { if(startX<endX) {
  • 18. offG.fillRect(20*startX, 20*startY, 20*(endX-startX+1), 20); offG.setColor(Color.red); offG.drawString(String.valueOf(endX-startX+1), endX*20+2, (endY+1)*20-2); } else { offG.fillRect(20*endX, 20*endY, 20*(startX-endX+1), 20); offG.setColor(Color.red); offG.drawString(String.valueOf(startX-endX+1), endX*20+2, (endY+1)*20-2); } } } for(int j=0; j<parent.NUM_ROW; j++) //격자 출력 for(int i=0; i<parent.NUM_COLUMN; i++) { offG.setColor(Color.black); offG.drawRect(i*20, j*20, 20, 20); } offG.setColor(Color.black); for(int i=0; i<=20*parent.NUM_COLUMN; i+=20*5) { offG.drawLine(i-1, 0, i-1, 20*parent.NUM_ROW); offG.drawLine(i+1, 0, i+1, 20*parent.NUM_ROW); } for(int i=0; i<=20*parent.NUM_ROW; i+=20*5) { offG.drawLine(0, i-1, 20*parent.NUM_COLUMN, i-1); offG.drawLine(0, i+1, 20*parent.NUM_COLUMN, i+1); } g.drawImage(offScr, 0, 0, this); //가상 화면을 실제 화면으로 복사 } public void update(Graphics g) { paint(g); } @Override public void mousePressed(MouseEvent e) //플레이어가 마우스 버튼을 누른 경우 { int x = e.getX();
  • 19. int y = e.getY(); if((x/20)>=parent.NUM_COLUMN) return; if((y/20)>=parent.NUM_ROW) return; if(parent.endFlag)return; startX = x/20; startY = y/20; } public void mouseReleased(MouseEvent e) //플레이어가 마우스 버튼을 놓은 경우 { int x = e.getX(); int y = e.getY(); if((x/20)>=parent.NUM_COLUMN) return; if((y/20)>=parent.NUM_ROW) return; if(parent.endFlag)return; if((e.getModifiers() & InputEvent.BUTTON3_MASK)!=0) //마우스 오른쪽 버튼 { setTemp(x, y, 2); } else //마우스 왼쪽 버튼 { setTemp(x, y, 1); } parent.display(); //퍼즐이 풀렸는지 검사 this.drag = false; repaint(); } public void mouseMoved(MouseEvent e) //마우스가 움직인 경우 { int x = e.getX(); int y = e.getY(); if((x/20)>=parent.NUM_COLUMN) return; if((y/20)>=parent.NUM_ROW) return; parent.showLocation(x/20, y/20); //column 과 row 에 마우스 커서의 위치를 표시 repaint(); } public void mouseExited(MouseEvent e) //마우스가 보드를 벗어난 경우 { parent.showLocation(-1, -1); //column 과 row 에 마우스 커서의 위치를 표시하지 않음 this.drag = false; repaint(); }
  • 20. public void mouseClicked(MouseEvent e) {} public void mouseEntered(MouseEvent e) { } public void mouseDragged(MouseEvent e) //마우스를 드래그한 경우 { int x = e.getX(); int y = e.getY(); if((x/20)>=parent.NUM_COLUMN) return; if((y/20)>=parent.NUM_ROW) return; parent.showLocation(x/20, y/20); //column 과 row 에 마우스 커서의 위치를 표시 this.drag = true; endX = x/20; endY = y/20; repaint(); } private void setTemp(int x, int y, int value) //플레이어의 입력을 temp 배열에 저장 { int i; if(drag) { if(startX==endX) { if(startY<endY) { if(parent.temp[startX+startY*parent.NUM_COLUMN] != 0) { for(i=startY; i<=endY; i++) parent.temp[startX+i*parent.NUM_COLUMN] = 0; } else { for(i=startY; i<=endY; i++) parent.temp[startX+i*parent.NUM_COLUMN] = value; } } else if(startY>endY) { if(parent.temp[startX+startY*parent.NUM_COLUMN] != 0) { for(i=endY; i<=startY; i++)
  • 21. parent.temp[startX+i*parent.NUM_COLUMN] = 0; } else { for(i=endY; i<=startY; i++) parent.temp[startX+i*parent.NUM_COLUMN] = value; } } else //startY == endY { if(parent.temp[startX+startY*parent.NUM_COLUMN]!=0) parent.temp[startX+startY*parent.NUM_COLUMN] = 0; else parent.temp[startX+startY*parent.NUM_COLUMN] = value; } } else if(startY==endY) { if(startX<endX) { if(parent.temp[startX+startY*parent.NUM_COLUMN] != 0) { for(i=startX; i<=endX; i++) parent.temp[i+startY*parent.NUM_COLUMN] = 0; } else { for(i=startX; i<=endX; i++) parent.temp[i+startY*parent.NUM_COLUMN] = value; } } else if(startX>endX) { if(parent.temp[startX+startY*parent.NUM_COLUMN] != 0) { for(i=endX; i<=startX; i++) parent.temp[i+startY*parent.NUM_COLUMN] = 0; } else { for(i=endX; i<=startX; i++) parent.temp[i+startY*parent.NUM_COLUMN] = value; }
  • 22. } else // startX == endX { if(parent.temp[startX+startY*parent.NUM_COLUMN]!=0) parent.temp[startX+startY*parent.NUM_COLUMN] = 0; else parent.temp[startX+startY*parent.NUM_COLUMN] = value; } } } else { if(parent.temp[x/20+y/20*parent.NUM_COLUMN]!=0) parent.temp[x/20+y/20*parent.NUM_COLUMN] = 0; else parent.temp[x/20+y/20*parent.NUM_COLUMN] = value; } } }
  • 23. Column.java import java.awt.*; //Color 상수 등을 위한 awt 패키지 선언 public class Column extends Canvas { Nemonemo parent; //Nemonemo 클래스의 객체를 저장 Image offScr; //더블버퍼링을 위한 가상 화면 Graphics offG; public Column(Nemonemo parent) //Nemonemo 클래스의 객체를 보관하고 모든 열의 연속한 '1'의 개수를 계산 { this.parent = parent; //Nemonemo 클래스의 객체를 보관 getColumn(); } public void getColumn() //데이터에 맞춰 column 의 숫자를 생성 { for(int i=0; i<parent.NUM_COLUMN; i++) //모든 열에 연속한 '1'의 개수를 계산 { parent.numOfColumn[i] = getNumber(i); } } int getNumber(int start) //해당하는 열의 연속한 '1'의 개수를 계산 { int count = 0; //연속된 '1'의 개수 int pos = 0; //몇 번째 연속된 '1'의 개수를 나타내는 수인지를 표시 for(int i = start; i<parent.NUM_COLUMN * parent.NUM_ROW; i+=parent.NUM_COLUMN) //같은 열에 속한 data 의 값을 비교 { if(parent.data.charAt(i)=='0' && count>0) //연속하지 않은 경우('0'인 경우) { parent.columnNums[start][pos++] = count; count = 0; } else if(parent.data.charAt(i)=='1' && count>=0) //연속한 경우('1'인 경우) { count++; } } if(count>0) parent.columnNums[start][pos++] = count; if(pos==0) parent.columnNums[start][pos++] = 0;
  • 24. return pos; } public void paint (Graphics g) //화면에 column 을 출력 { offScr = createImage(20*parent.NUM_COLUMN+1, 121); //가상 화면 생성 offG = offScr.getGraphics(); if(parent.mouseX!=-1) { offG.setColor(Color.yellow); offG.fillRect(20*parent.mouseX, 0, 19, 120); //마우스 커서가 있는 열의 경우 } int CountofColumn[] = new int[parent.NUM_COLUMN]; int CountofTemp[] = new int[parent.NUM_COLUMN]; int right[] = new int[parent.NUM_COLUMN]; for(int i=0; i<parent.NUM_COLUMN; i++) { for(int j=0; j<parent.NUM_ROW; j++) { if(parent.data.charAt(j*parent.NUM_COLUMN+i) == '1') CountofColumn[i] += 1; if(parent.temp[j*parent.NUM_COLUMN+i] == 1) CountofTemp[i] += 1; } if(CountofColumn[i]==CountofTemp[i]) right[i] = 1; else right[i] = 0; } for(int i=0; i<parent.NUM_COLUMN; i++) { offG.setColor(Color.black); offG.drawLine(i*20, 0, i*20, 220); for(int j=0; j<parent.numOfColumn[i]; j++) //숫자 출력 { if(right[i] == 1) offG.setColor(Color.blue); else offG.setColor(Color.black); if(String.valueOf(parent.columnNums[i][j]).length()<2) offG.drawString(String.valueOf(parent.columnNums[i][j]), i*20+9, (100- parent.numOfColumn[i]*20+j*20)+39); else
  • 25. offG.drawString(String.valueOf(parent.columnNums[i][j]), i*20+1, (100- parent.numOfColumn[i]*20+j*20)+39); } } offG.setColor(Color.black); for(int i=0; i<=20*parent.NUM_COLUMN; i+=20*5) { offG.drawLine(i-1, 0, i-1, 120); offG.drawLine(i+1, 0, i+1, 120); } offG.drawLine(200, 0, 200, 120); offG.drawLine(0, 120, 200, 120); g.drawImage(offScr, 0, 0, this); } public void update(Graphics g) { paint(g); } }
  • 26. Row.java import java.awt.*; //Color 상수 등을 위한 awt 패키지 선언 public class Row extends Canvas{ Nemonemo parent; //Nemonemo 클래스의 객체를 저장 Image offScr; //더블버퍼링을 위한 가상 화면 Graphics offG; public Row(Nemonemo parent) //Nemonemo 클래스의 객체를 보관하고 모든 행의 연속한 '1'의 개수를 계산 { this.parent = parent; //Nemonemo 클래스의 객체를 보관 getRow(); } public void getRow() //데이터에 맞춰 row 의 숫자를 생성 { for(int i=0; i<parent.NUM_ROW; i++) //모든 행에 연속한 '1'의 개수를 계산 { parent.numOfRow[i] = getNumber(i); } } int getNumber(int start) //해당하는 행의 연속한 '1'의 개수를 계산 { int count = 0; //연속된 '1'의 개수 int pos = 0; //몇 번째 연속된 '1'의 개수를 나타내는 수인지를 표시 for(int i=start*parent.NUM_COLUMN; i<(start+1)*parent.NUM_COLUMN; i++) //같은 행에 속한 data 의 값을 비교 { if(parent.data.charAt(i)=='0' && count>0) //연속하지 않은 경우('0'인 경우) { parent.rowNums[start][pos++] = count; count = 0; } else if(parent.data.charAt(i)=='1' && count>=0) //연속한 경우('1'인 경우) { count++; } } if(count>0) parent.rowNums[start][pos++] = count; if(pos==0) parent.rowNums[start][pos++] = 0;
  • 27. return pos; } public void paint (Graphics g) //화면에 row 를 출력 { offScr = createImage(121, 20*parent.NUM_ROW+1); //가상 화면 생성 offG = offScr.getGraphics(); if(parent.mouseY!=-1) { offG.setColor(Color.yellow); offG.fillRect(0, 20*parent.mouseY, 120, 19); //마우스 커서가 있는 행의 경우 } int CountofRow[] = new int[parent.NUM_ROW]; int CountofTemp[] = new int[parent.NUM_ROW]; int right[] = new int[parent.NUM_ROW]; for(int i=0; i<parent.NUM_ROW; i++) { for(int j=0; j<parent.NUM_COLUMN; j++) { if(parent.data.charAt(i*parent.NUM_COLUMN+j) == '1') CountofRow[i] += 1; if(parent.temp[i*parent.NUM_COLUMN+j] == 1) CountofTemp[i] += 1; } if(CountofRow[i]==CountofTemp[i]) right[i] = 1; else right[i] = 0; } for(int i=0; i<parent.NUM_ROW; i++) { offG.setColor(Color.black); offG.drawLine(0, i*20, 120, i*20); for(int j=0; j<parent.numOfRow[i]; j++) //숫자 출력 { if(right[i] == 1) offG.setColor(Color.blue); else offG.setColor(Color.black); if(String.valueOf(parent.rowNums[i][j]).length()<2) { offG.drawString(String.valueOf(parent.rowNums[i][j]), (100-parent.numOfRow[i]*20)+j*20+27, i*20+18); offG.setColor(Color.black); } else { offG.drawString(String.valueOf(parent.rowNums[i][j]), (100-parent.numOfRow[i]*20)+j*20+21, i*20+18); offG.setColor(Color.black); }
  • 28. } } offG.setColor(Color.black); for(int i=0; i<=20*parent.NUM_ROW; i+=20*5) { offG.drawLine(0, i-1, 120, i-1); offG.drawLine(0, i+1, 120, i+1); } offG.drawLine(0, 200, 120, 200); offG.drawLine(120, 0, 120, 200); g.drawImage(offScr, 0, 0, this); } public void update(Graphics g) { paint(g); } }