Разработка программы для реализации алгоритма обхода шахматной доски конем
Особенности пользовательского интерфейса, реализующего диалог программного приложения с пользователем для создания шахматной доски с конем, на которой выбираются размер поля, клетки и другие параметры. Анализ алгоритма заполнения массива доступности.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | курсовая работа |
Язык | русский |
Дата добавления | 19.08.2017 |
Размер файла | 314,2 K |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
Размещено на http://www.allbest.ru
Размещено на http://www.allbest.ru
1. Постановка задачи
Эта интересная головоломка была предложена математиком Эйлером. Задание, на первый взгляд, достаточно простое - нужно шахматным конём, находящимся на произвольной клетке шахматной доски, обойти все остальные клетки доски, размер которой также задан произвольно. При этом на одну клетку можно походить только один раз.
Конь, как известно, ходит Г-образно. Т.е. на две клетки в каком-либо направлении (вверх, вниз, вправо, влево) и на одну клетку в перпендикулярном. Таким образом, конем, можно сделать максимум восемь различных ходов из заданной клетки (или меньше, если конь находится у края доски).
Для решения этой задачи на компьютере необходимо разработать правила, в соответствии с которыми компьютер будет выбирать ход. В принципе, очередной ход можно выбирать случайным образом.
Оригинальное правило, дающее линейный по времени алгоритм обхода доски, было предложена Варнсдорфом в 1983 году. Я реализовала его в своей курсовой работе.
2. Алгоритм обхода
Алгоритм формулируется очень просто: следующий ход коня нужно делать на клетку, откуда существует наименьшее количество возможных ходов. Если клеток с одинаковым количеством ходом несколько, то можно выбрать любую.
На практике это реализуется, например, следующим образом. Перед каждым ходом коня вычисляется рейтинг ближайших доступных полей - полей, на которых конь еще не был, и на которые он может перейти за один ход. Рейтинг поля определяется числом ближайших доступных с него полей. Чем меньше рейтинг, тем он лучше. Потом делается ход на поле с наименьшим рейтингом (на любое из таковых, если их несколько), и так далее, пока есть куда ходить.
Эвристика всегда работает на досках от 5x5 до 76x76 клеток, при больших размерах доски конь может зайти в тупик. Кроме того, базирующийся на правиле алгоритм не дает всех возможных решений (т.е. путей коня): можно пойти против правила и все равно получить удовлетворяющий условию задачи обход.
Существует линейный алгоритм для досок любого размера, который делит доску на меньшие части, но, из-за обилия особых случаев, он довольно сложный и не такой интересный, как эта элегантная эвристика.
Рис. 1
программный интерфейс алгоритм
Кроме этого, я хотела бы пояснить, как выполняется ход. Мы уже говорили, что существует восемь возможных ходов. Все они закодированы цифрами от 0 до 7. На рис. 1 показаны все возможные варианты ходов.
Каждый ход можно представить как перемещение на заданное количество клеток по горизонтали и по вертикали. Например, нулевому ходу соответствует перемещение на две клетки по горизонтали, и "-1" клетку по вертикали (знак минус указывает на направление перемещения).
Заполнение массива доступности немного сложнее. Каждый его элемент соответствует клетке на доске, но здесь мы записываем информацию о том, со скольких клеток можно походить на заданную. Например, на клетку а1 можно походить из двух клеток (с2 и b3). Массив этот перед началом решения задачи имеет следующий вид:
Рис. 2
3. Пример работы программы
Диалог создания шахматной доски с конем, на которой мы выбираем размер поля, размер клетки, положение коня и иные параметры. Так же можно загрузить изображения элементов доски из файлов.
Рис. 3
Создано поле 5х5, конь стоит в позиции 2х4. Теперь, когда поле уже создано, можно запустить алгоритм обхода доски конем.
Рис. 4
Результат обхода алгоритма виден на доске, числами показан порядок обхода доски конем. Можно стереть порядок обхода и запустить алгоритм заново. Также можно ходить конем с помощью стрелочек и мыши.
Рис. 6
4. Листинг программы
clBoard.java
//// version 8 final recomment
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.Timer;
public class clBoard extends JPanel
{
private static final long serialVersionUID = 1L;
/**
* Конструктор (по умолчанию) класса доски
*/
clBoard()
{
super();/// вызов конструктора предка
this.setLayout(null);/// убираем менеджер размещения, т.к. сами будет распологать фигуры
};
/**
* Главный конструктор создания доски с одним конем
* @param Diagonal Размер доски, т.е. колич. клеток по горизонтали и вертикали.
* @param Size Размер в пикселях клеток на доске.
* @param ImageCellsStretch Растягивать ли изображение до размера клетки.
* @param ImageWhiteCells Изображение светлой ячейки, если null то рисуется белый квадрат.
* @param ImageBlackCells Изображение темной ячейки, если null то рисует черный квадрат.
* @param FirstCellWhite Флаг того что первая ячейка на доске белая, при false - темная.
* @param ImageHorse Изображение этого одного коня, с прозрачными областями(+Альфа-канал).
* @param PosX Позиция коня по горизонтали: 0,1,2..(Size-1)
* @param PosY Позиция коня по вертикали: 0,1,2..(Size-1)
*/
clBoard(int Diagonal, int Size,boolean ImageCellsStretch, BufferedImage ImageWhiteCells,BufferedImage ImageBlackCells,boolean FirstCellWhite,Image ImageHorse,int PosX, int PosY)
{
this();//вызывает конструктор по умолчанию
BoardSizeInit(Diagonal,Size);///инициализируем размерные параметры доски
//создаем озображение белой клетки под размеры ячейки
BufferedImage imageWhiteCells=new BufferedImage(CellsSize,CellsSize,BufferedImage.TYPE_3BYTE_BGR);
Graphics2D gImageWhiteCells=imageWhiteCells.createGraphics();//создаем графический контекст этого изображения, для рисования на нем
//создаем озображение черной клетки
BufferedImage imageBlackCells=new BufferedImage(CellsSize,CellsSize,BufferedImage.TYPE_3BYTE_BGR);
Graphics2D gImageBlackCells=imageBlackCells.createGraphics();
//если аргумент конструктора изображения клетки нулевое(null), то создаем изображение клетки по умолчанию
if(ImageWhiteCells==null)
{
gImageWhiteCells.setBackground(Color.white);// выбираем фоновый цвет
gImageWhiteCells.clearRect(0, 0, CellsSize,CellsSize);//очищаем всю область изображения клетки фоновым цветом
}
else////если изображение не нулевое, то мы его рисуем на (для) изображении клетки
{
if(ImageCellsStretch==true)///растягивание (подгон под размер области)изображения под квадратную клетку
{
gImageWhiteCells.drawImage(ImageWhiteCells, 0, 0, CellsSize, CellsSize, null);
/// CellsSize, CellsSize - размеры области, в которую должен уместиться рисунок, он сам подгоняется под размеры области(растягивается, сжимается)
}
else
{
gImageWhiteCells.drawImage(ImageWhiteCells, 0, 0, null);
/// null - нет хозяина(сервера) у графиша, которого надо было бы уведомить о том что "рисунок" обновился,
//он должен выполнить соотв. действия (перепрорисовка объекта)
};
};
///аналогично, что и для белой клетки
if(ImageBlackCells==null)
{
gImageBlackCells.setBackground(Color.black);
gImageBlackCells.clearRect(0, 0, CellsSize,CellsSize);
}
else
{
if(ImageCellsStretch==true)
{
gImageBlackCells.drawImage(ImageBlackCells, 0, 0, CellsSize, CellsSize, null);
}
else
{
gImageBlackCells.drawImage(ImageBlackCells, 0, 0, null);
};
};
///вызываем функцию, которая на основе изобр. черной и белой клетки создаст единое изображение доски,где клетки будут выложены в соответ. порядке
BoardFonCreate(imageWhiteCells,imageBlackCells,FirstCellWhite);
///создаем изображение коня(в классе)
HorseImage=new BufferedImage(CellsSize, CellsSize,BufferedImage.TYPE_4BYTE_ABGR);/// с прозрачностью
Graphics2D gImageHorseCells=HorseImage.createGraphics();
if(ImageHorse==null)
{///если изображение коня нулевое, то рисуем изображение по умолчанию - красный квадратик по центру
gImageHorseCells.setBackground(Color.red);
gImageHorseCells.clearRect(CellsSize/2-5, CellsSize/2-5, 10, 10);
}
else
{
if(ImageCellsStretch==true)
{
gImageHorseCells.drawImage(ImageHorse, 0, 0,CellsSize,CellsSize, null);
}
else
{
gImageHorseCells.drawImage(ImageHorse, 0, 0, null);
}
};
///создаем коня и ставим его на определенную позицию на доске(изображение коня хранится в классе доски т.к. кони не нуждаются в индивидуальности внешнего вида)
Horse=new clHorse(PosX,PosY);
this.add(Horse);///добавляем коня (предок коня это кнопка), на доску (которая является потомком от JPanel)
this.revalidate();//обновляем доску
//создаем экземпляр класса, который содержит в себе тело алгоритма, связанное с графикой(с доской)
Runs=new clRun();
//создаем изображение на котором будет рисоваться порядок обхода доски (числа), в результате работы алгоритма,рисуется поверх доски
RunsImage=new BufferedImage(BoardSize,BoardSize,BufferedImage.TYPE_4BYTE_ABGR);
};
/**
* Проверяет и устанавливает значения размера доски (в клетках и пикселях(BoardDiagonal*CellsSize)),
* и применяет их к панели(доске) JPanel(clBoard),
* при неверных значениях, устанавливает на минимальные, верхней границы для значений нету.
* @param Diagonal Размер доски в клетках, для квадратной доски.
* @param Size Размер в пикселях для клетки поля, рекомендуется не менее 40.
* @return true - верные параметры, false - параметры с ошибками, при любых значениях размеры применяются.
*/
boolean BoardSizeInit(int Diagonal, int Size)
{
boolean Ok=false;//флаг возврата
if((Diagonal>0)&&(Size>0))//проверка правильности параметров
{
BoardDiagonal=Diagonal;
CellsSize=Size;
Ok=true;
}
else
{
BoardDiagonal=1;
CellsSize=10;
Ok=false;
};
BoardSize=BoardDiagonal*CellsSize;///вычисляем ширину(высоту)доски в пикселях
this.setPreferredSize(new Dimension(BoardSize,BoardSize));/// устанавливает размер панели
return Ok;
};
/**
* Количество клеток по диагонали на доске (штуки, клетки)
*/
public int BoardDiagonal=1;
/**
* Размер ячейки поля в пикселях (на доске), ячейки квадратные.
*/
int CellsSize=1;
/**
* Размер доски по горизонтали и вертикали (пиксели)
*/
int BoardSize=0;
/**
* Изображение (фоновое) доски
*/
BufferedImage BoardFon=null;
/**
* Изображение коня (с прозрачными областями)
*/
BufferedImage HorseImage=null;
/**
* Рисование доски т.е. Переопределение функции рисования объекта JPanel.
*/
protected void paintComponent(Graphics g)
{
// если фон готов, то рисуем его
if(BoardFon!=null){g.drawImage(BoardFon, 0,0, this);};
// если изображение порядка обходя(чисел) готово, то рисуем его
if(RunsImage!=null){g.drawImage(RunsImage, 0, 0, this);};
// при перемещении коня мышью, рисуем его под указателем мыши
if(BoardHorseMoveMouse==true)
{
// проверяем то что конь в горизонтальных пределах доски, если нет то не даем ему выйти за пределы
if((EventBoardHorseMovedelX+CellsSize)>BoardSize)
{
EventBoardHorseMovedelX=BoardSize-CellsSize;
}
else if(EventBoardHorseMovedelX<0)
{
EventBoardHorseMovedelX=0;
};
// проверяем то что конь в горизонтальных пределах доски, если нет то не даем ему выйти за пределы
if((EventBoardHorseMovedelY+CellsSize)>BoardSize)
{
EventBoardHorseMovedelY=BoardSize-CellsSize;
}
else if(EventBoardHorseMovedelY<0)
{
EventBoardHorseMovedelY=0;
};
// рисуем изображение коня в пределах поля
g.drawImage(HorseImage, EventBoardHorseMovedelX, EventBoardHorseMovedelY, null);
};
};
/**
* Создает фоновое изображение шахматной доски из плотного массива светлых и темных клеток,
* если изображение не иниц.(null), то фон не рисуется,
* порядок расположения клеток "по строчно, через одну", какая первая ячейка на поле первая определяется параметром.
* @param whiteCells Изображение светлой ячейки(клетки).
* @param blackCells Изображение темной ячейки(клетки).
* @param firstCellWhite если true - то первая клетка поля светлая, если false - то темная
* @return true - фон нарисован, false - фон не нарисован, из-за того что изобращения не иниц. или не иниц. размеры доски.
*/
public boolean BoardFonCreate(BufferedImage whiteCells,BufferedImage blackCells,boolean firstCellWhite)
{
if((whiteCells!=null)&&(blackCells!=null)&&(BoardSize>0)&&(CellsSize>0)&&(BoardDiagonal>0))
{
BoardFon=new BufferedImage(BoardSize, BoardSize,BufferedImage.TYPE_INT_RGB);
int kX=0;///координаты "точки рисования"
int kY=0;
boolean firstCell=firstCellWhite;/// флаг для первой ячейки
Graphics Fon = BoardFon.createGraphics();/// для рисования
Fon.clearRect(0, 0, BoardFon.getWidth(), BoardFon.getHeight());///очищаем
for(int j=0;j<BoardDiagonal;j++)///цикл рисования по строкам
{
kY=j*CellsSize;
kX=0;// новая строка
for(int i=0;i<BoardDiagonal;i++)///цикл рисования внутри строки
{
if(((i%2==0)&&(firstCell==true))||((i%2>0)&&(firstCell==false)))
{
// белая в случае если четная ячейка и первая ячейка белая
// белая в случае если нечетная ячейка и первая ячейка черная
Fon.drawImage(whiteCells, kX, kY, CellsSize, CellsSize, null);
}
else
{
// между белыми
Fon.drawImage(blackCells, kX, kY, CellsSize, CellsSize, null);
};
kX=kX+CellsSize;//передвигаемся в строке вправо для рисования следующей ячейки(клетки)
};//end for i
/// следующая строка начинается с противоположного цвета ячейки
firstCell=!firstCell;
};// end for j
return true;
};
return false;
};
/**
* Флаг того что по доске перетаскивается конь, с помощью мыши
*/
boolean BoardHorseMoveMouse=false;
/**
* Начальные координаты коня до перетаскивания, X по горизотали (пиксели)
*/
int EventBoardHorseMovekX=0;
/**
* Начальные координаты коня до перетаскивания, Y по вертикали (пиксели)
*/
int EventBoardHorseMovekY=0;
/**
* Изменение координат, X по горизотали (пиксели)
*/
int EventBoardHorseMovedelX=0;
/**
* Изменение координат, Y по вертикали (пиксели)
*/
int EventBoardHorseMovedelY=0;
/**
* Координаты мыши при нажатии ЛКМ, в системе координат коня (JButton), X по горизотали (пиксели)
*/
int EventBoardHorseMovePressX=0;
/**
* Координаты мыши при нажатии ЛКМ, в системе координат коня (JButton), Y по вертикали (пиксели)
*/
int EventBoardHorseMovePressY=0;
/**
* Перепрорисовка панели (доски)
*/
void RePaint(){this.repaint();};
/**
* Начальные координаты при перемещении стрелками,
* перед первой частью "Г"-образного хода,
* т.е. позиция ячейки по горизонтали (штуки, клетки).
*/
int firstCellPosX=0;
/**
* Начальные координаты при перемещении стрелками,
* перед первой частью "Г"-образного хода,
* т.е. позиция ячейки по вертикали (штуки, клетки).
*/
int firstCellPosY=0;
/**
* Код клавиши которая была нажата первой: "первая стрелка"
*/
int firstKeyCode=0;
/**
* Составляющая смещения у первой части "Г"-образного хода
* (длинна отрезка в клетках -1)
*/
final int firstPartG=2;
/**
* Напраление первой части "Г"-образного хода,
* чтобы вторая часть была перпендикулярна первой (буква "Г"),
* true - вертикально, false - горизонтально.
*/
boolean firstLine=false;
/**
* Код клавиши которая была нажата второй: вторая стрелка т.е. после первой стрелка
*/
int secondKeyCode=0;
/**
* Составляющая смещения у второй части "Г"-образного хода
* (длинна отрезка в клетках -1)
*/
final int secondPartG=1;
/**
* экземпляр Коня (принадлежащий доске)
*/
public clHorse Horse=null;
/**
* Класс Конь наследованный от класса JButton, для дальнейшего размещения на панели т.е. доске.
* Изображение Коня не содержиться в классе, а берется из класса Доски, а также берутся параметры и функции.
* (Классы Конь и Доска не разделимы совсем).
*/
class clHorse extends JButton
{
private static final long serialVersionUID = 1L;
/**
* Конструктор по умолчанию, инициализирует коня
*/
clHorse()
{
this.setBounds(0, 0, CellsSize, CellsSize);///помещаем коня на доску(по умолчанию)
this.addKeyListener(new KeyMoveListener());//добавляем слушателя события нажатия клавиш для коня
mouseMoveListener=new MouseMoveListener();//слушатель событий мыши применительно к коню
this.addMouseListener(mouseMoveListener);
this.addMouseMotionListener(mouseMoveListener);
};
/**
* Конструктор инициализирует коня с помещением его на определенную позицию
* @param PosX номер клетки по горизонтали
* @param PosY номер клетки по вертикали
*/
clHorse(int PosX, int PosY)
{
this();//вызываем конструктор (по умолчанию) коня
HorseMove(PosX,PosY);///переносит коня в определенное место на доске
};
/**
* Позиция Коня по горизонтали, ячейки: 0,1,2...CellsNumberX-1
*/
int CellPositionX=0;
/**
* Позиция Коня по вертикали, ячейки: 0,1,2...CellsNumberY-1
*/
int CellPositionY=0;
/**
* Флаг того что мы перемещаем коня с помощью стрелок
*/
boolean HorseMoveKey=false;
/**
* Флаг того что мы перемещаем коня с помощью перетаскивания мышью
*/
boolean HorseMoveMouse=false;
/**
* Перемещает коня в соотв. с "Г"-образным ходом из текущей позиции(местонахождения)
* @param PosX - номер клетки по горизонтали, в которую нужно перейти "Г"-образным ходом
* @param PosY - номер клетки по вертикали, в которую нужно перейти "Г"-образным ходом
* @return true - если ход был выполнен, false - если невозможно сходить "Г"-образным ходом
*/
boolean HorseIsMove(int PosX, int PosY)
{
boolean flag=false;
if((PosX<BoardDiagonal)&&(PosX>=0)&&(PosY<BoardDiagonal)&&(PosY>=0))
{
//flag=false;
// горизонталь - верикаль
if(((PosX-CellPositionX)==firstPartG)||((CellPositionX-PosX)==firstPartG))
{
if(((PosY-CellPositionY)==secondPartG)||((CellPositionY-PosY)==secondPartG))
{
flag=true;
};
};
// верикаль - горизонталь
if((flag==false)&&(((PosY-CellPositionY)==firstPartG)||((CellPositionY-PosY)==firstPartG)))
{
if(((PosX-CellPositionX)==secondPartG)||((CellPositionX-PosX)==secondPartG))
{
flag=true;
};
};
}
else
{
flag=false;
};
if(flag==true)
{
HorseMove(PosX, PosY);
};
return flag;
}
/**
* Вручную переносит(перемещает) коня в пределах доски(без учета "Г"-образного хода)
* @param PosX - номер клетки по горизонтали, в которую нужно перейти
* @param PosY - номер клетки по вертикали, в которую нужно перейти
* @return true - если координаты в пределах доски, false - если параметры неверны(они сбрасываются в 0)
*/
public boolean HorseMove(int PosX, int PosY)
{
boolean flag=true;
if((PosX<BoardDiagonal)&&(PosX>=0))
{
CellPositionX=PosX;
}
else
{
CellPositionX=0;
flag=false;
};
if((PosY<BoardDiagonal)&&(PosY>=0))
{
CellPositionY=PosY;
}
else
{
CellPositionY=0;
flag=false;
};
this.setBounds(CellPositionX*CellsSize, CellPositionY*CellsSize, CellsSize, CellsSize);
return flag;
}
/**
* Переопределенная функция рисования самого коня(класса, объекта)
*/
protected void paintComponent(Graphics g)
{
///оболочка(одежда, изображения) коня рисуется лишь в том случае, когда есть изображение(не null) и не перетаскивается мышью(т.к. он рисуется доской при перетаскивании)
if((HorseImage!=null)&&(HorseMoveMouse==false))////т.к. при перетаскивании конь рисуется на доске
{
g.drawImage(HorseImage, 0, 0, null);
};
};
/**
* удаляем бордюр JButton
*/
protected void paintBorder(Graphics g){};
/**
* класс слушателя событий, связанных с клавишами
* @author Машунечка
*/
public class KeyMoveListener implements KeyListener
{
/**
* функция, которая обрабатывает нажатие клавиш
*/
public void keyPressed(KeyEvent arg0)
{
boolean first=false;//флаг совершения первой части "Г"-образного хода
boolean second=false;//флаг совершения второй части "Г"-образного хода
int secondPartGlocal=secondPartG;//локальная копия смещения при второй части "Г"-образного хода
///после того как совершена вторая часть "Г"-образного хода и мы нажали стрелку противоположную той,
///которую нажали ранее, томы можем выбирать варианты второй части "Г"-образного хода
// т.е. вторая часть "Г"-образного хода совершается несколько раз(более 1 раза)
if((arg0.getKeyCode()!=secondKeyCode)&&(secondKeyCode!=0))
{
secondPartGlocal=2*secondPartG;
};
//**рассмотрение стрелок по вертикали
///начинаем рассматривать клавиши для хода конем лишь в том случае:
///если флаг перемещения сброшен или (стоит и первая часть хода была по горизонтали)
if((HorseMoveKey==false)||((HorseMoveKey==true)&&(firstLine==false)))
/// рассмотрение стрелки вверх
if(arg0.getKeyCode()==KeyEvent.VK_UP)///стрелка вверх
{//первая часть хода
/// если направление вверх "Г" не выйдет за доску
if((CellPositionY>=firstPartG)&&(HorseMoveKey==false))
{
firstCellPosX=CellPositionX;//исходная позиция сохраняется
firstCellPosY=CellPositionY;
///записывается новая позиция по вертикали
CellPositionY=CellPositionY-firstPartG;
//отмечается, что совершена первая часть хода
first=true;
firstLine=true;///по вертикали
}
else if((arg0.getKeyCode()!=secondKeyCode)&&(CellPositionY>=secondPartGlocal)&&(HorseMoveKey==true))
{//вторая часть хода
///записывается новая позиция по вертикали
CellPositionY=CellPositionY-secondPartGlocal;
//отмечается, что совершена вторая часть хода
second=true;
};
}
else if(arg0.getKeyCode()==KeyEvent.VK_DOWN)///стрелка вниз
{
if((CellPositionY<(BoardDiagonal-firstPartG))&&(HorseMoveKey==false))
{
firstCellPosX=CellPositionX;
firstCellPosY=CellPositionY;
CellPositionY=CellPositionY+firstPartG;
first=true;
firstLine=true;
}
else if((arg0.getKeyCode()!=secondKeyCode)&&(CellPositionY<(BoardDiagonal-secondPartGlocal))&&(HorseMoveKey==true))
{
CellPositionY=CellPositionY+secondPartGlocal;
second=true;
}
};
//**рассмотрение стрелок по горизонтали
///начинаем рассматривать клавиши для хода конем лишь в том случае:
///если флаг перемещения сброшен или (стоит и первая часть хода была по вертикали)
if((HorseMoveKey==false)||((HorseMoveKey==true)&&(firstLine==true)))
if(arg0.getKeyCode()==KeyEvent.VK_RIGHT)///стрелка вправо
{
if((CellPositionX<(BoardDiagonal-firstPartG))&&(HorseMoveKey==false))
{
firstCellPosX=CellPositionX;
firstCellPosY=CellPositionY;
CellPositionX=CellPositionX+firstPartG;
first=true;
firstLine=false;
}
else if((arg0.getKeyCode()!=secondKeyCode)&&(CellPositionX<(BoardDiagonal-secondPartGlocal))&&(HorseMoveKey==true))
{
CellPositionX=CellPositionX+secondPartGlocal;
second=true;
}
}
else if(arg0.getKeyCode()==KeyEvent.VK_LEFT)///стрелка влево
{
if((CellPositionX>=firstPartG)&&(HorseMoveKey==false))
{
firstCellPosX=CellPositionX;
firstCellPosY=CellPositionY;
CellPositionX=CellPositionX-firstPartG;
first=true;
firstLine=false;
}
else if((arg0.getKeyCode()!=secondKeyCode)&&(CellPositionX>=secondPartGlocal)&&(HorseMoveKey==true))
{
CellPositionX=CellPositionX-secondPartGlocal;
second=true;
}
};
//если была совершена первая часть хода, то перемещаем коня по правилу
///и запоминаем код клавиши(стрелочки), которая была нажата,
///и устанавливается флаг перемещения коня с помощью стрелок
if(first==true)
{
HorseMove(CellPositionX,CellPositionY);
firstKeyCode=arg0.getKeyCode();
HorseMoveKey=true;
};
//если была совершена первая часть хода, то перемещаем коня по правилу
///и запоминаем код клавиши(стрелочки), которая была нажата
if(second==true)
{
HorseMove(CellPositionX,CellPositionY);
secondKeyCode=arg0.getKeyCode();
};
};
/**
* функция, которая обрабатывает отпускание клавиш
*/
public void keyReleased(KeyEvent arg0)
{
//если отпустили клавишу, которая была нажата на первой части хода, то
if(firstKeyCode==arg0.getKeyCode())
{
firstKeyCode=0;//код клавиши сбрасывается
HorseMoveKey=false;//сбрасывается флаг перемещения коня с помощью стрелок
// >=37(проще !=0) код клавиши второй части хода не сброшен(т.е. был выполнен)
if(secondKeyCode>=37)
{
//перемещаем коня в свою же позицию
HorseMove(CellPositionX,CellPositionY);
}
else
{
//перемещаем коня на изначальное место
HorseMove(firstCellPosX,firstCellPosY);
}
secondKeyCode=0;//код клавиши сбрасывается
HorseMove(CellPositionX,CellPositionY);
};
};
public void keyTyped(KeyEvent arg0){};
};
/**
* экземпляр слушателя событий мыши
*/
MouseMoveListener mouseMoveListener=null;
/**
* класс слушателя событий мыши
* @author Машунечка
*/
public class MouseMoveListener implements MouseListener,MouseMotionListener
{
// клики
public void mouseClicked(MouseEvent e){};
// появление мыши в компоненте
public void mouseEntered(MouseEvent e){};
// выход мыши из компоненнта
public void mouseExited(MouseEvent e){};
// нажатие кнопки мыши
public void mousePressed(MouseEvent e)
{
///если левая кнопка то начинаем перетаскивать
if((e.getModifiers() & MouseEvent.BUTTON3_MASK)==0)
{
///сохраняем начальные координаты коня на доске
EventBoardHorseMovekX=getX();/// или CellPositionX*CellsSize
EventBoardHorseMovekY=getY();
/// запоминаем координаты курсора мыши на коне
EventBoardHorseMovePressX=e.getX();
EventBoardHorseMovePressY=e.getY();
EventBoardHorseMovedelX=0;
EventBoardHorseMovedelY=0;
}
};
public void mouseReleased(MouseEvent e)
{
if((BoardHorseMoveMouse==true)&&((e.getModifiers() & MouseEvent.BUTTON3_MASK)==0))
{
HorseMoveMouse=false;
BoardHorseMoveMouse=false;
RePaint();
///при отпускании клавиши вычисляются координаты ячейки(клетки) по координатам центра коня
HorseIsMove((EventBoardHorseMovedelX+CellsSize/2)/CellsSize,(EventBoardHorseMovedelY+CellsSize/2)/CellsSize);
};
};
public void mouseDragged(MouseEvent arg0)
{
///левая кнопка
if((arg0.getModifiers() & MouseEvent.BUTTON3_MASK)==0)
{
if(BoardHorseMoveMouse==false)
{
HorseMoveMouse=true;
BoardHorseMoveMouse=true;
};
/// тут EventBoardHorseMovedel становяться координатами левого угла
EventBoardHorseMovedelX=EventBoardHorseMovekX+arg0.getX()-EventBoardHorseMovePressX;
EventBoardHorseMovedelY=EventBoardHorseMovekY+arg0.getY()-EventBoardHorseMovePressY;
RePaint();
}
};
public void mouseMoved(MouseEvent arg0){};
};
};
/**
*изображение по размерам доски содержит порядок обхода(числа) при работе алгоритма
*/
BufferedImage RunsImage;
/**
* цвет чисел на RunsImage
*/
Color RunsColor=Color.green;
/**
* шрифт чисел на RunsImage
*/
Font RunsFont=getFont();
/**
* метрики шрифта RunsFont
*/
FontMetrics RunsFontMetrics;
/**
* инициализация шрифта, метрик, изображения на(в) RunsImage(если оно не созданно)
*/
public void RunsImageInit()
{
if(RunsImage==null)
{
RunsImage=new BufferedImage(BoardSize,BoardSize,BufferedImage.TYPE_4BYTE_ABGR);
};
Graphics gRunsImage=RunsImage.getGraphics();
if(CellsSize>30)
{
RunsFont=gRunsImage.getFont();
//устанавливаем размер шрифта по размеру клетки
RunsFont=RunsFont.deriveFont((float)((int)(CellsSize/2)));
}
else
{
RunsFont=gRunsImage.getFont();
RunsFont=RunsFont.deriveFont((float)15.0);
};
RunsFont=RunsFont.deriveFont(Font.BOLD);
///инициализируем метрики шрифта
RunsFontMetrics=getFontMetrics(RunsFont);
};
/**
* Рисует на RunsImage в клетке номер порядка обхода
* @param X - номер ячейки(клетки) по горизонтали
* @param Y - номер ячейки(клетки) по вертикали
* @param Nomer - номер, который будет рисоваться
*/
void RunsMetkaCells(int X, int Y, int Nomer)
{
if(RunsImage==null)
{
RunsImage=new BufferedImage(BoardSize,BoardSize,BufferedImage.TYPE_4BYTE_ABGR);
};
Graphics gRunsImage=RunsImage.getGraphics();
gRunsImage.setFont(RunsFont);
gRunsImage.setColor(RunsColor);
String strNomer=String.valueOf(Nomer);
gRunsImage.drawString(strNomer, X*CellsSize+CellsSize/2-RunsFontMetrics.stringWidth(strNomer)/2, Y*CellsSize+CellsSize/2+RunsFontMetrics.getHeight()/2);
};
/**
* экземпляр класса Выполнение алгоритма
*/
public clRun Runs=null;
/**
* Класс Выполнение алгоритма, выполняет итерации алгоритма по таймеру
* @author Машунечкая
*/
public class clRun
{
/**
* сам таймер, который запускает итерации алгоритма
*/
public Timer RunsTimer;
/**
* возможные ходы (X)
*/
private final int EnslavedX[]={-1,-2,-2,-1,1,2,2 ,1};// возможные ходы
/**
* возможные ходы (Y)
*/
private final int EnslavedY[]={-2,-1,1 ,2,2,1,-1,-2};
/**
* шахматное поле
*/
private int Ch [][]=null;
/**
* массив возможности хода (bool)
*/
private int ChBool [];
/**
* массив рейтинга возможных ходов
*/
private int ChReit [];
/**
* то же самое что и ChBool но используется при вычислении рейтинга
*/
private int ChBoolReit;
/**
* x и y временной псефдо коня который используется при вычислении рейтинга
*/
private int xhR, yhR;
/**
* размеры поля
*/
private int xCh, yCh;
/**
* текуще координаты коня
*/
private int xh, yh;
/**
* b-обчный bool
*/
private int b=0;
/**
* а-число сделанных ходов
*/
private int a=1;
/**
* номер хода в массивах Enslaved у которого наименьший рейтинг
*/
private int NR=0;
/**
* временные данные
*/
private int tmp=0;
/**
* конструктор по умолчанию инициализирует шахматное поле для выполнения алгоритма(не графика)
*/
clRun()
{
Ch=new int[BoardDiagonal+1][BoardDiagonal+1];
};
/**
* начальная инициализация перед началом алгоритма
*/
public void RunsInit()
{
Ch=new int[BoardDiagonal+1][BoardDiagonal+1];
ChBool=new int[8];//массив возможности хода (bool)
ChReit=new int[8];//массив рейтинга возможных ходов
ChBoolReit=0;// то же самое что и ChBool но используется при вычислении рейтинга
xhR=0; yhR=0;//x и y временной псефдо коня который используется при вычислении рейтинга
xCh=BoardDiagonal; yCh=BoardDiagonal;//размеры поля
xh=Horse.CellPositionX+1; yh=Horse.CellPositionY+1;// текуще координаты коня
b=0; a=1; // b-обчный bool , а-число сделанных ходов
NR=0; //номер хода в массивах Enslaved у которого наименьший рейтинг
tmp=0; // временные данные
////for (int i = 0; i < xCh; i++)for (int i2 = 0; i2 < yCh; i2++) Ch [i][i2] =0; //обнуление массива
Ch [xh][yh]=1;
RunsMetkaCells(Horse.CellPositionX,Horse.CellPositionY,1);
};
/**
* Ииц. и запускает таймер, и выполнение итераций алгорима
* @param leadTime задержка таймера (интервал) между выполнением итераций, значение только >0
*/
public void RunTimer(int leadTime)
{
RunsImageInit();
RunsInit();
actionTimer=new ActionTimer();
RunsTimer = new Timer(leadTime, actionTimer);
RunsTimer.start();
};
/**
* экземпляр слушателя события активации (срабатывания) таймера
*/
ActionTimer actionTimer=null;
/**
* Слушатель события активации (срабатывания) таймера, кот. выполняет итерации алгоритма
* @author Машунечка
*
*/
class ActionTimer implements ActionListener
{
public void actionPerformed(ActionEvent arg0)
{
if(b==0&&a!=1)//условия окончания действия алгоритма
{
RunsTimer.stop();//останавливает таймер
return;//прерывает выполнения функции
};
{
b=0;
tmp=8;
a++;///наращиваем число сделланных ходов, который показывает порядок обхода доски(отображается на пройденной клетке)
for (int i = 0; i <= 7; i++) ChReit [i] =0; //обнуление
for (int i = 0; i <= 7; i++) // вычисление возможности хода с позиции лошадки
{
//заполняем массив возможности хода, при ходе в пределах поля и на непройденную ячейку
ChBool[i]=1;
if (xh+EnslavedX[i]<1) ChBool[i]=0;
if (xh+EnslavedX[i]>xCh) ChBool[i]=0;
if (yh+EnslavedY[i]<1) ChBool[i]=0;
if (yh+EnslavedY[i]>yCh) ChBool[i]=0;
if ((xh+EnslavedX[i]<=xCh)&&(yh+EnslavedY[i]<=yCh)&&(xh+EnslavedX[i]>=0)&&(yh+EnslavedY[i]>=0)&&(Ch[xh+EnslavedX[i]] [yh+EnslavedY[i]] != 0))
ChBool[i]=0;
};
for (int i = 0; i <= 7; i++) //начисление рейтинга в массив ChReit
{
if (ChBool[i]==1)//если ход возможен то
{
xhR=xh+EnslavedX[i];
yhR=yh+EnslavedY[i];
for (int i2 = 0; i2 <= 7; i2++)
{
ChBoolReit=1;
if (xhR+EnslavedX[i2]<1) ChBoolReit=0;
if (xhR+EnslavedX[i2]>xCh) ChBoolReit=0;
if (yhR+EnslavedY[i2]<1) ChBoolReit=0;
if (yhR+EnslavedY[i2]>yCh) ChBoolReit=0;
if ((xhR+EnslavedX[i2]<=xCh)&&(yhR+EnslavedY[i2]<=yCh)&&(xhR+EnslavedX[i2]>=0)&&(yhR+EnslavedY[i2]>=0)&&(Ch[xhR+EnslavedX[i2]] [yhR+EnslavedY[i2]] != 0)) ChBoolReit=0;
ChReit [i]= ChReit [i]+ ChBoolReit;
};
}
};
for (int i = 0; i <= 7; i++)// выявление самого низкого рейтинга
{
if (ChReit [i]<tmp)
{
if (ChBool[i]==1)
{
tmp=ChReit [i];
NR=i;
}
};
}
for (int i = 0; i <= 7; i++) b=b+ChBool[i];//сколько ходов возможно (но всёравно b используется как бул в котором результат отличный от 0 =1)
if (b!=0) //делаем ход (вы не поверите, конём!)
{
xh=xh+EnslavedX[NR];
yh=yh+EnslavedY[NR];
Ch [xh][yh]=a;
RunsMetkaCells(xh-1, yh-1,a);
Horse.HorseIsMove(xh-1, yh-1);
};
};
};
};/// end ActionTimer
};
}
clFrame.java
//// version 8 final recomment
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
import javax.imageio.ImageIO;
import javax.swing.*;
/**
* Класс окна программы который содержит меню и доску (clBoard)
*/
public class clFrame extends JFrame
{
private static final long serialVersionUID = 1L;
/**
* Конструктор по умолчанию (для фрейма прогр)
*/
clFrame()
{
super("Ход конем - Таранова Мария АСУ-09-2");/// заголовок окна который направляется конструктору предка
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);/// устанавливаем событие на закрытие окна JFrame
this.setSize(400, 300);/// Размер по умолчанию для окна
this.setVisible(true);/// устанавливает Видимость окна программы (обязательно)
this.setMenuBar(menubar);/// добавляет меню бар (с элементами меню)
/// создание модального диалога "Создание шахматной доски с конем..."
dialogBoard = new DialogBoard(this,"Создание шахматной доски с конем...",true);
};
/**
* Конструктор с другим заголовком окна
* @param Title Новый заголовок окна
*/
clFrame(String Title)
{
this();/// вызываем Конструктор по умолчанию
this.setTitle(Title);/// устанавливаем новый заголовок для окна
};
/**
* Конструктор с заголовком и размерами для окна
* @param Title Новый заголовок окна
* @param width Ширина окна в пикселях
* @param height Высота окна в пикселях
*/
clFrame(String Title, int width, int height)
{
this(Title);/// устанавливаем новый заголовок для окна
this.setSize(width, height);/// устан. новые размеры
};
/**
* Инициализация добавления готовой доски(Board внутри JScrollPane(для прокрутки)) к окну программы
*/
private void initPanelBoard()
{
if(Board!=null)
{
scrollPanel=new JScrollPane(Board);
this.add(scrollPanel);
};
this.validate();
};
/**
* Экземпляр меню для программы
*/
clMenuBar menubar = new clMenuBar();
/**
* Класс меню для Программы, содержит все пункты, и обработку действий меню
*/
class clMenuBar extends MenuBar
{
private static final long serialVersionUID = 1L;
/**
* Конструктор по умолчанию, который проводит обязательную инициализацию пунктов меню
*/
clMenuBar()
{
// добавляем меню "Доска" и его подпункты
this.add(mBoard);
mNew.addActionListener(menuEvent);// добавляем слушателя активации пункта меню
mBoard.add(mNew);//добавляем пункт к соотв. меню
/// разделительная черта в меню
mBoard.addSeparator();
mExit.addActionListener(menuEvent);// добавляем слушателя активации пункта меню
mBoard.add(mExit);//добавляем пункт к соотв. меню
// добавляем меню "Выполнить обход"
this.add(mHorse);
mRun.addActionListener(menuEvent);// добавляем слушателя активации пункта меню
mHorse.add(mRun);//добавляем пункт к соотв. меню
mStop.addActionListener(menuEvent);// добавляем слушателя активации пункта меню
mHorse.add(mStop);//добавляем пункт к соотв. меню
mClear.addActionListener(menuEvent);// добавляем слушателя активации пункта меню
mHorse.add(mClear);//добавляем пункт к соотв. меню
mColor.addActionListener(menuEvent);// добавляем слушателя активации пункта меню
mHorse.add(mColor);//добавляем пункт к соотв. меню
/// Заранее отключаем лишние пунты меню, ведь доска еще изначально не создана,
/// затем после создания доски с конем они будут включены
mColor.setEnabled(false);
mClear.setEnabled(false);
mRun.setEnabled(false);
mStop.setEnabled(false);
};
/// объявление меню и подменю:
/**
* Меню "Доска" на менюбаре
*/
public Menu mBoard = new Menu("Доска");
/**
* Пункт меню("Доска") "Создать доску"
*/
public MenuItem mNew = new MenuItem("Создать доску");
/**
* Пункт меню("Доска") "Выход"
*/
public MenuItem mExit = new MenuItem("Выход");
/**
* Меню "Выполнить обход" на менюбаре
*/
public Menu mHorse = new Menu("Выполнить обход");
/**
* Пункт меню("Выполнить обход") "Выполнить обход"
*/
public MenuItem mRun = new MenuItem("Выполнить обход");
/**
* Пункт меню("Выполнить обход") "Остановить обход"
*/
public MenuItem mStop = new MenuItem("Остановить обход");
/**
* Пункт меню("Выполнить обход") "Очистить обход"
*/
public MenuItem mClear = new MenuItem("Очистить обход");
/**
* Пункт меню("Выполнить обход") "Выбрать цвет для обхода"
*/
public MenuItem mColor = new MenuItem("Выбрать цвет для обхода");
/**
* Экземпляр слушателя событии меню программы
*/
MenuEvent menuEvent=new MenuEvent();
/**
* Класс слушателя событий меню,
* все пункты меню различаюся по функции getSource() которая возвращает ссылку на объект который "создал(вызвал) событие"
* , содержит также действия по выполнению пунктов меню.
*/
class MenuEvent implements ActionListener
{
public void actionPerformed(ActionEvent arg0)
{
// Получаем ссылку на объект который вызвал событие
Object ob=arg0.getSource();
// начинаем сравнивать его с пунктами меню:
/// Создать доску
if(ob==mNew)
{
// запускаем модальные диалог (пока он есть все остальное(окна и другое) в программе блокируется)
dialogBoard.runDialogBoard();
// добавляем созданую диалогом доску к окну
initPanelBoard();
}
else if(ob==mClear)
{
if(Board!=null)
{
Board.RunsImage=null;/// обнуляем его (слой(изобранение) с числами(порядком обхода))
Board.RunsImageInit();/// функция автоматом создает пустое прозрачное изображение
Board.RePaint();/// перепроисовка доски(панели)
};
}
else if(ob==mExit)
{
System.exit(0);// выход из программы (0 - без ошибок)
}
else if(ob==mRun)
{
// если доска создана, то...
if(Board!=null)
{
int timer=400;/// значение таймера итераций по умолчанию
// JOptionPane - стандартный модальный диалог
// showInputDialog - диалог для ввода, QUESTION_MESSAGE - это его тип (вид, стиль, тип иконки)
String timerStr= JOptionPane.showInputDialog(null, "Введите задержку передвижения коня в миллисекундах.\n" +
"Допустимые значения от 0 до 30 секунд (30000 мс).\n" +
"Общее время выполнения равно количеству клеток на поле * задержку.\n" +
"Пример: 1 секунда = 1000 миллисекунд.\n" +
"Рекомендуемое значение 400 миллисекунд.",
"Выполнение обхода конем шахматной доски...", JOptionPane.QUESTION_MESSAGE);
/// timerStr приемник того что ввел пользователь в диалог
/// может быть null если была отмена
if(timerStr!=null)
{
/// создаем сканнер для перевода строки в число - количество мс задержки
Scanner scanner=new Scanner(timerStr);
/// проверяем присутствие целого числа
if(scanner.hasNextInt()==true)
{
/// получаем его в переменную таймер
timer=scanner.nextInt();
/// проверяем на правильность значения таймера
if((timer>=0)&&(timer<=30000))
{
// запускаем итерации алгоритма по заданному интервалу
Board.Runs.RunTimer(timer);
}
else
{
JOptionPane.showMessageDialog(null, "Было введено недопустимое значение для времени задержки \nпередвижения коня в миллисекундах.\nОперация не выполнена.", "Операция отменена", JOptionPane.ERROR_MESSAGE);
return;/// прерывание(обрывание выполнения) функции
};
}
else
{
JOptionPane.showMessageDialog(null, "Было введено недопустимое значение (не целое число)\n для времени задержки передвижения коня в миллисекундах.\nОперация не выполнена.", "Операция отменена", JOptionPane.ERROR_MESSAGE);
return;/// прерывание(обрывание выполнения) функции
};
}
else
{
JOptionPane.showMessageDialog(null, "Был отменен ввод времени задержки \nпередвижения коня в миллисекундах.\nОперация не выполнена.", "Обход доски отменен...", JOptionPane.WARNING_MESSAGE);
return;/// прерывание(обрывание выполнения) функции
};
};
}
else if(ob==mColor)
{
/// Color temp - приемник цвета выбранного на JColorChooser, может быть null если была отмена
// Board.RunsColor текущий цвет подается как выбранный по умолчанию на панели
if(Board!=null)/// тк работаем с доской ("цвет RunsColor внутри неё")
{
Color temp=JColorChooser.showDialog(null, "Выбор цвета для номеров клеток обхода доски", Board.RunsColor);
if((temp!=null))
{
Board.RunsColor=temp;
};
};/// end Board!=null
}
else if(ob==mStop)
{
// Останавливаем таймер и выполнение итераций алгоритма
if(Board!=null&&Board.Runs!=null&&Board.Runs.RunsTimer!=null)
{
Board.Runs.RunsTimer.stop();// стоп
};
};
};
};
};
/**
* Панель с полосами прокрутки
*/
JScrollPane scrollPanel=null;
/**
* Экземпляр шахматной доски
*/
clBoard Board=null;
/**
* Экземпляр диалога создания доски
*/
DialogBoard dialogBoard=null;
/**
* Сам диалог создания доски, подготавливает агрументы (параметры) для конструктора clBoard и загружаем изображения из файла
*
*/
class DialogBoard extends JDialog
{
private static final long serialVersionUID = 1L;
/**
* Конструктор создания модального диалога создания доски
* @param owner владелец, фрейм к которому привязан диалог
* @param title заголовок диалога
* @param modal модальность, лучше true
*/
DialogBoard(Frame owner, String title, boolean modal)
{
super(owner, title, modal);
// выставляем размер окна диалога
this.setSize(450, 320);
// сбрасываем менеджер размещения, тк все элементы будем распологать вручную по координатам
this.setLayout(null);
// иниц отдельных элементов
InitSpinners();
InitCells();
reSource();
// значения по умолчанию
BoardSpinner.setValue(new Integer(8));
CellsSpinner.setValue(new Integer(80));
HorseSpinnerX.setValue(new Integer(2));
HorseSpinnerY.setValue(new Integer(2));
CellFirst.setSelected(true);
BoardCellsHorse.setSelected(true);
};
/**
* Спиннер для: "Размер поля"
*/
JSpinner BoardSpinner=new JSpinner();
JLabel BoardLabel=new JLabel("Размер поля:");
/**
* Спиннер для: "Размер клетки"
*/
JSpinner CellsSpinner=new JSpinner();
JLabel CellsLabel=new JLabel("Размер клетки:");
JSpinner HorseSpinnerX=new JSpinner();
JSpinner HorseSpinnerY=new JSpinner();
JLabel HorseLabel=new JLabel("Положение коня:");
JLabel HorseX=new JLabel("X:");
JLabel HorseY=new JLabel("Y:");
// кнопки
JButton BoardCellsBlackColor=new JButton("Выбрать фоновый цвет для темных клеток");
JButton BoardCellsWhiteColor=new JButton("Выбрать фоновый цвет для светлых клеток");
// галочки и кнопки загрузить
JCheckBox BoardCellsBlack=new JCheckBox("Изображение для темных клеток из файла");
JButton BoardCellsBlackImage=new JButton("Загрузить...");
JCheckBox BoardCellsWhite=new JCheckBox("Изображение для светлых клеток из файла");
JButton BoardCellsWhiteImage=new JButton("Загрузить...");
JCheckBox BoardCellsHorse=new JCheckBox("Изображение для коня из файла");
JButton BoardCellsHorseImage=new JButton("Загрузить...");
JCheckBox CellsStretch=new JCheckBox("Растягивать изображение на клетке");
JCheckBox CellFirst=new JCheckBox("Первая клетка на поле светлая");
/**
* фоновый цвет по умолчанию для светлых клеток
*/
Color CellsWhite=Color.white;
/**
* фоновый цвет по умолчанию для темных клеток
*/
Color CellsBlack=Color.black;
JButton BoardRun=new JButton("Создать шахматную доску с конем");
JButton BoardCancel=new JButton("Отмена (Закрыть)");
/// изображения элементов доски: конь и клетки
BufferedImage ImageCellsBlack=null;
BufferedImage ImageCellsWhite=null;
BufferedImage ImageCellsHorse=null;
/// путь к файлам изображений
String StrCellsBlack=null;
String StrCellsWhite=null;
String StrCellsHorse=null;
/**
* Файловый диалог для выбора изображения для использования на доске
*/
FileDialog OpenImage=new FileDialog(this,"Загрузка изображения из файла",FileDialog.LOAD);
/**
* Иниц. на диалоге спиннеров и связанных элементов
*/
void InitSpinners()
{
// Bounds: коодринаты левого верхнего угла, ширина и высота область
BoardLabel.setBounds(10, 5, 100, 25);
// Устанавливается шрифт со измененным размером
this.setFont(this.getFont().deriveFont((float)14.0));
BoardLabel.setFont(getFont());
this.add(BoardLabel);/// добавляем на диалог элемент
BoardSpinner.setBounds(125, 5, 60, 25);
this.add(BoardSpinner);/// добавляем на диалог элемент
CellsLabel.setBounds(10, 40, 100, 25);
CellsLabel.setFont(getFont());
this.add(CellsLabel);/// добавляем на диалог элемент
CellsSpinner.setBounds(125, 40, 60, 25);
this.add(CellsSpinner);/// добавляем на диалог элемент
HorseLabel.setBounds(240, 15, 150, 25);
HorseLabel.setFont(getFont());
this.add(HorseLabel);/// добавляем на диалог элемент
HorseX.setBounds(240, 40, 50, 25);
HorseX.setFont(getFont());
this.add(HorseX);/// добавляем на диалог элемент
HorseSpinnerX.setBounds(260, 40, 50, 25);
this.add(HorseSpinnerX);/// добавляем на диалог элемент
HorseY.setBounds(340, 40, 50, 25);
HorseY.setFont(getFont());
this.add(HorseY);/// добавляем на диалог элемент
HorseSpinnerY.setBounds(360, 40, 50, 25);
this.add(HorseSpinnerY);/// добавляем на диалог элемент
};
void InitCells()
{
// первая ячейка белая
CellFirst.setBounds(10, 65, 250, 25);
CellFirst.setFont(getFont());
this.add(CellFirst);
// растягивать(подгонять) изображение на клетке
CellsStretch.setBounds(10, 90, 280, 25);
CellsStretch.setFont(getFont());
this.add(CellsStretch);
// выбор фонового цвета для темных клеток
BoardCellsBlackColor.setBounds(14, 120, 300, 20);
BoardCellsBlackColor.addActionListener(actionButton);
this.add(BoardCellsBlackColor);
// выбор фонового цвета для светлых клеток
BoardCellsWhiteColor.setBounds(14, 145, 300, 20);
BoardCellsWhiteColor.addActionListener(actionButton);
this.add(BoardCellsWhiteColor);
//**********************
// Изображения для элементов доски:
//**********************
BoardCellsBlack.setBounds(10, 170, 315, 25);
BoardCellsBlack.setFont(getFont());
this.add(BoardCellsBlack);
BoardCellsBlackImage.setBounds(325, 175, 110, 18);
BoardCellsBlackImage.addActionListener(actionButton);
this.add(BoardCellsBlackImage);
//***********************
BoardCellsWhite.setBounds(10, 195, 315, 25);
BoardCellsWhite.setFont(getFont());
this.add(BoardCellsWhite);
BoardCellsWhiteImage.setBounds(325, 200, 110, 18);
BoardCellsWhiteImage.addActionListener(actionButton);
this.add(BoardCellsWhiteImage);
//***********************
BoardCellsHorse.setBounds(10, 220, 315, 25);
BoardCellsHorse.setFont(getFont());
this.add(BoardCellsHorse);
BoardCellsHorseImage.setBounds(325, 225, 110, 18);
BoardCellsHorseImage.addActionListener(actionButton);
this.add(BoardCellsHorseImage);
//***********************
// создать доску
BoardRun.setBounds(10, 255, 255, 25);
BoardRun.addActionListener(actionButton);
this.add(BoardRun);
// отмена
BoardCancel.setBounds(275, 255, 160, 25);
BoardCancel.addActionListener(actionButton);
this.add(BoardCancel);
};
/**
* Иниц. значениями по умолчанию ("обнуление") графических ресурсов
*/
void reSource()
{
ImageCellsBlack=null;
ImageCellsWhite=null;
ImageCellsHorse=null;
CellsWhite=Color.white;
CellsBlack=Color.black;
};
/**
* Запуск диалога на выполнение
*/
public void runDialogBoard()
{
ImageCellsBlack=null;
ImageCellsWhite=null;
ImageCellsHorse=null;
BoardCellsHorse.setSelected(true);
this.setVisible(true);
};
/**
* экземпляр слушателя событий кнопки
*/
ActionButton actionButton=new ActionButton();
/**
* Класс слушателя событий кнопки на диалоге создания доски
*
*/
class ActionButton implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
Object ob=e.getSource();
Color tempColor=null;
if(ob==BoardCellsWhiteColor)///"Выбрать фоновый цвет для светлых клеток"
{
/// вызываем диалог выбора цвета, где tempColor приёмник выбранного цвета, возможно null если была отмена
tempColor=JColorChooser.showDialog(null,BoardCellsWhiteColor.getText()+"...", CellsWhite);
if(tempColor!=null)
{
CellsWhite=tempColor;
};
}
else if(ob==BoardCellsBlackColor)///"Выбрать фоновый цвет для темных клеток"
{
/// вызываем диалог выбора цвета, где tempColor приёмник выбранного цвета, возможно null если была отмена
tempColor=JColorChooser.showDialog(null,BoardCellsBlackColor.getText()+"...", CellsBlack);
if(tempColor!=null)
{
CellsBlack=tempColor;
};
}
else if(ob==BoardRun)////"Создать шахматную доску с конем"
{
int BoardSize=((Integer)BoardSpinner.getValue()).intValue();
if(!((BoardSize>0)&&((BoardSize<=500))))
{
JOptionPane.showMessageDialog(null, "Введены не правильное значение "+BoardLabel.getText()+"\nДоступные значения: >=1 AND <=500","Ошибка "+getTitle()+"!!!", JOptionPane.ERROR_MESSAGE);
return;/// прерываем выполнения функции, но не скрываем модальный диалог
};
int CellsSize=((Integer)CellsSpinner.getValue()).intValue();
if(!((CellsSize>20)&&(CellsSize<1000)))
{
JOptionPane.showMessageDialog(null, "Введены не правильное значение "+CellsLabel.getText()+"\nДоступные значения: >20 AND <1000","Ошибка "+getTitle()+"!!!", JOptionPane.ERROR_MESSAGE);
return;/// прерываем выполнения функции, но не скрываем модальный диалог
};
// тк позиция коня отсчитывается внутри от 0 (нуля0, а люди считают с 1 (единицы), по этому вычитаем единицу
int HorseXcell=((Integer)HorseSpinnerX.getValue()).intValue()-1;// начальное положение коня по горизонтали (справа налево)
int HorseYcell=((Integer)HorseSpinnerY.getValue()).intValue()-1;// начальное положение коня по вертикали (сверху вниз)
if(!((HorseXcell>=0)&&(BoardSize>HorseXcell)&&(HorseYcell>=0)&&(BoardSize>HorseYcell)))
{
JOptionPane.showMessageDialog(null, "Введены не правильное значение "+HorseLabel+" X или Y"+"\nДоступные значения: >=1 AND =<Размер поля","Ошибка "+getTitle()+"!!!", JOptionPane.ERROR_MESSAGE);
return;/// прерываем выполнения функции, но не скрываем модальный диалог
};
/// создаем изображение светлой клетки, на основе фонового цвета + если было загруженно изображение
BufferedImage imageCellsWhite=new BufferedImage(CellsSize,CellsSize,BufferedImage.TYPE_3BYTE_BGR);
Graphics gWhite=imageCellsWhite.getGraphics();
gWhite.setColor(CellsWhite);
gWhite.fillRect(0, 0, CellsSize, CellsSize);
if(BoardCellsWhite.isSelected()==true)
{
if(ImageCellsWhite!=null)
{
gWhite.drawImage(ImageCellsWhite, 0, 0, null);
}
else
{
JOptionPane.showMessageDialog(null, "Ошибка загрузки "+BoardCellsWhite.getText()+"\nСнимите галочку или Загрузите изображение","Ошибка "+getTitle()+"!!!", JOptionPane.ERROR_MESSAGE);
return;
};
};
/// создаем изображение темной клетки, на основе фонового цвета + если было загруженно изображение
BufferedImage imageCellsBlack=new BufferedImage(CellsSize,CellsSize,BufferedImage.TYPE_3BYTE_BGR);
Graphics gBlack=imageCellsBlack.getGraphics();
gBlack.setColor(CellsBlack);
gBlack.fillRect(0, 0, CellsSize, CellsSize);
if(BoardCellsBlack.isSelected()==true)
{
if(ImageCellsBlack!=null)
{
gBlack.drawImage(ImageCellsBlack, 0, 0, null);
}
else
{
JOptionPane.showMessageDialog(null, "Ошибка загрузки "+BoardCellsBlack.getText()+"\nСнимите галочку или Загрузите изображение","Ошибка "+getTitle()+"!!!", JOptionPane.ERROR_MESSAGE);
return;
};
};
/// загружаем изображение коня, если его нету (null) то в классе clBoard рисуется красный квадрат
if(BoardCellsHorse.isSelected()==true)
{
if(ImageCellsHorse!=null)
{
}
else
{
JOptionPane.showMessageDialog(null, "Ошибка загрузки "+BoardCellsHorse.getText()+"\nСнимите галочку или Загрузите изображение","Ошибка "+getTitle()+"!!!", JOptionPane.ERROR_MESSAGE);
return;
}
};
/// создаем шахматную доску запуская конструктор с нужными проверенными параметрами
Board=new clBoard(BoardSize,CellsSize, CellsStretch.isSelected(), imageCellsWhite, imageCellsBlack, CellFirst.isSelected(), ImageCellsHorse, HorseXcell, HorseYcell);
/// включение пунктов меню
menubar.mNew.setEnabled(false);
menubar.mColor.setEnabled(true);
menubar.mClear.setEnabled(true);
menubar.mRun.setEnabled(true);
menubar.mStop.setEnabled(true);
// скрваем диалог и теперь мы работаем с окном
setVisible(false);
}
else if(ob==BoardCancel)///"Отмена"
{
setVisible(false);
}
else if(ob==BoardCellsBlackImage)///Изображение для темных клеток из файла
{
OpenImage.setDirectory(".");/// выбор текущей директории где работает программа
Подобные документы
Разработка программы нахождения оптимального пути обхода шахматной доски шахматным конем с обязательной визуализацией процесса и пошаговой демонстрацией. Тестирование графического интерфейса. Исходный код программы, составление и проверка алгоритма.
курсовая работа [468,3 K], добавлен 11.12.2012Разработка программы для оценки шахматной ситуации на доске с использованием графического интерфейса. Способы вывода результатов. Библиотека визуальных компонентов. Модульная структура приложения, его внешний вид. Последовательность работы с приложением.
контрольная работа [132,2 K], добавлен 07.10.2010Создание программы движения коня по шахматной доске, ее функциональное и эксплуатационное назначение, требования пользователя к программному изделию. Виды скриншотов, информационная совместимость, программные ограничения и требования к документации.
курсовая работа [1,4 M], добавлен 17.02.2010Разработка программного комплекса и описание алгоритма. Разработка пользовательского интерфейса. Анализ тестовых испытаний программного блока. Защита пользователей от воздействия на них опасных и вредных факторов. Режимы работы программного комплекса.
дипломная работа [1,7 M], добавлен 14.03.2013Разработка программы в среде Delphi, показывающей на экране возможные варианты выбранной шахматной фигуры для хода. Спецификация исходных данных и функций программы, тексты разработанных классов приложения и их ключевые методы, тестирование программы.
курсовая работа [69,4 K], добавлен 19.10.2010Разработка приложения в среде Delphi для нахождения кратчайшего пути передвижения короля по заданному полю, соединяющего два заданных поля доски. Разработка и поиск алгоритма решения задачи, спецификация исходных данных и функций, тестирование программы.
курсовая работа [358,5 K], добавлен 19.10.2010Теоретические основы разработки приложения, реализующего подсвечивание ключевых слов. Описание используемых процедур и функций, структуры программы, интерфейса пользователя. Системные требования для работы приложения, анализ результаты его тестирования.
курсовая работа [1,2 M], добавлен 07.07.2012Определение понятия алгоритмов, принципы их решения людьми и всевозможными техническими устройствами. Применение компьютера для решения задач. Особенности использования метода последовательного укрупнения при создании шахматной доски по алгоритму.
презентация [1,1 M], добавлен 06.02.2012Задача о восьми ферзях как широко известная задача по расстановке фигур на шахматной доске. Характеристика алгоритмов решения задачи для доски 8х8. Рассмотрение особенностей программы, использующей алгоритм Лас-Вегаса, проведения статистического анализа.
контрольная работа [382,3 K], добавлен 06.08.2013Реализация приложения, которое выполняет считывание, обработку, визуализацию и аппроксимацию экспериментальных данных полиномиальной функции. Блок схема алгоритма аппроксимации методом наименьших квадратов. Разработка интерфейса и листинга программы.
курсовая работа [1,1 M], добавлен 07.07.2013