49236

Обход Шахматной Доски Конем

Курсовая

Информатика, кибернетика и программирование

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

Русский

2013-12-23

206.97 KB

77 чел.

УРАЛЬСКИЙ   ГОСУДАРСТВЕННЫЙ   ГОРНЫЙ   УНИВЕРСИТЕТ

КАФЕДРА ИНФОРМАТИКИ

                                      

                                            

КУРСОВАЯ РАБОТА

ПО ПРОГРАММИРОВАНИЮ

Обход Шахматной Доски Конем

Выполнила: Таранова М. В.

гр. АСУ-09-2

              

Екатеринбург

2010

Оглавление

  1.  Постановка задачи
  2.  Алгоритм обхода
  3.  Пример работы программы
  4.  Листинг:

clBoard.java

clFrame.java


Постановка задачи

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

Конь, как известно, ходит Г-образно. Т.е. на две клетки в каком-либо направлении (вверх, вниз, вправо, влево) и на одну клетку в перпендикулярном. Таким образом, конем, можно сделать максимум восемь различных ходов из заданной клетки (или меньше, если конь находится у края доски).

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

Оригинальное правило, дающее линейный по времени алгоритм обхода доски, было предложена Варнсдорфом(Warnsdorff) в 1983 году. Я реализовала его в своей курсовой работе.

Алгоритм обхода

Алгоритм формулируется очень просто: следующий ход коня нужно делать на клетку, откуда существует наименьшее количество возможных ходов. Если клеток с одинаковым количеством ходом несколько, то можно выбрать любую.

На практике это реализуется, например, следующим образом. Перед каждым ходом коня вычисляется рейтинг ближайших доступных полей - полей, на которых конь еще не был, и на которые он может перейти за один ход. Рейтинг поля определяется числом ближайших доступных с него полей. Чем меньше рейтинг, тем он лучше. Потом делается ход на поле с наименьшим рейтингом (на любое из таковых, если их несколько), и так далее, пока есть куда ходить.

Эвристика всегда работает на досках от 5x5 до 76x76 клеток, при больших размерах доски конь может зайти в тупик. Кроме того, базирующийся на правиле алгоритм не дает всех возможных решений (т.е. путей коня): можно пойти против правила и все равно получить удовлетворяющий условию задачи обход.

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

Кроме этого, я хотела бы пояснить, как выполняется ход. Мы уже говорили, что существует восемь возможных ходов. Все они закодированы цифрами от 0 до 7. На рис. показаны все возможные варианты ходов.

Каждый ход можно представить как перемещение на заданное количество клеток по горизонтали и по вертикали. Например, нулевому ходу соответствует перемещение на две клетки по горизонтали, и "-1" клетку по вертикали (знак минус указывает на направление перемещения). 

Заполнение массива доступности немного сложнее. Каждый его элемент соответствует клетке на доске, но здесь мы записываем информацию о том, со скольких клеток можно походить на заданную. Например, на клетку а1 можно походить из двух клеток (с2 и b3). Массив этот перед началом решения задачи имеет следующий вид:

 

Пример работы программы

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

Создано поле 5х5, конь стоит в позиции 2х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(".");/// выбор текущей директории где работает программа

   OpenImage.setTitle("Загрузка изображения темной клетки из файла...");/// заголовок

   OpenImage.setFile("*.jpg;*.png");/// маска файлов изображений (которые точно откроются)

   OpenImage.setVisible(true);// показываем диалог

   String StrFile=OpenImage.getFile();// принимаем имя файла

   String StrDir=OpenImage.getDirectory();// принимаем путь к директории

   BufferedImage image=null;// изображение приёмник(temp image)

   

   if((StrFile!=null)&&(StrDir!=null))

    {

    File ImageFile=new File(StrDir+StrFile);

    /// если файл существует и его возможно прочитать то пробуем загрузить из него изображение

    if(ImageFile.canRead())

    {

     try {

      image = ImageIO.read(ImageFile);/// загружаем изображение в image (приемник)

     } catch (IOException e1) {

      e1.printStackTrace();

     }

    };

    };/// end if

   ImageCellsBlack=image;/// загрузили и сохраняем для дальнейшего использования...

   

   }

  else if(ob==BoardCellsWhiteImage)///"Изображение для светлых клеток из файла"

   {

   OpenImage.setDirectory(".");/// выбор текущей директории где работает программа

   OpenImage.setTitle("Загрузка изображения светлой клетки из файла...");/// заголовок

   OpenImage.setFile("*.jpg;*.png");/// маска файлов изображений (которые точно откроются)

   OpenImage.setVisible(true);// показываем диалог

   String StrFile=OpenImage.getFile();// принимаем имя файла

   String StrDir=OpenImage.getDirectory();// принимаем путь к директории

   BufferedImage image=null;// изображение приёмник(temp image)

   

   if((StrFile!=null)&&(StrDir!=null))

    {

    File ImageFile=new File(StrDir+StrFile);

    /// если файл существует и его возможно  то пробуем загрузить из него изображение

    if(ImageFile.canRead())

    {

     try {

      image = ImageIO.read(ImageFile);/// загружаем изображение в image (приемник)

     } catch (IOException e1) {

      e1.printStackTrace();

     }

    };

    };/// end if

   ImageCellsWhite=image;/// загрузили и сохраняем для дальнейшего использования...

   }

  else if(ob==BoardCellsHorseImage)///Изображение для коня из файла

   {

   OpenImage.setDirectory(".");/// выбор текущей директории где работает программа

   OpenImage.setTitle("Загрузка изображения коня из файла...");/// заголовок

   OpenImage.setFile("*.jpg;*.png");/// маска файлов изображений (которые точно откроются)

   OpenImage.setVisible(true);// показываем диалог

   String StrFile=OpenImage.getFile();// принимаем имя файла

   String StrDir=OpenImage.getDirectory();// принимаем путь к директории

   BufferedImage image=null;// изображение приёмник(temp image)

   

   if((StrFile!=null)&&(StrDir!=null))

    {

    File ImageFile=new File(StrDir+StrFile);

    /// если файл существует и его возможно  то пробуем загрузить из него изображение

    if(ImageFile.canRead())

    {

     try {

      image = ImageIO.read(ImageFile);/// загружаем изображение в image (приемник)

     } catch (IOException e1) {

      e1.printStackTrace();

     }

    };

    };/// end if

   ImageCellsHorse=image;/// загрузили и сохраняем для дальнейшего использования...

   };

  };

  };

};

 

/**

 * Точка входа в приложение (программу обхода доски конем)

 * @param args

 */

public static void main(String[] args)

{

 // создаем экземпляр окна программы

 clFrame frame = new clFrame();

 // устанавливам иные размеры

 frame.setSize(600, 500);

 // и обязательно показываем

 frame.setVisible(true);

 // далее через меню выполняем нужные действия

};

};


 

А также другие работы, которые могут Вас заинтересовать

17600. Облік та аналіз зовнішньоекономічної діяльності 554.5 KB
  Облік та аналіз зовнішньоекономічної діяльності Лекція 1. ПРЕДМЕТ ЗАВДАННЯ ЗАГАЛЬНОТЕОРЕТИЧНІ І СПЕЦИФІЧНІ ОСНОВИ ДИСЦИПЛІНИ План Предмет курсу. Основні завдання та задачі. Нормативноправове забезпечення бухгалтерського обліку зовнішньоекономічної
17601. Экономика и организация малого бизнеса 3.95 MB
  Экономика и организация малого бизнеса: курс лекций Лекция 1. Предпринимательство: сущность функции принципы деловые качества 1.1.Сущность и функции предпринимательства его отличие от других видов деятельности. 1.2. Исторические предпосылки и основы предпринимате...
17602. ЕКОНОМІЧНІ ТЕОРІЇ ТА БАЗИСНІ ІНСТИТУТИ НАЦІОНАЛЬНОЇ ЕКОНОМІКИ 124 KB
  ТЕМА 2 ЕКОНОМІЧНІ ТЕОРІЇ ТА БАЗИСНІ ІНСТИТУТИ НАЦІОНАЛЬНОЇ ЕКОНОМІКИ План 1.Економічні теорії та базисні інститути національної економіки 2. Теорія дії триєдиних економічних законів 3. Базисні відносини та Інститути національної економіки Формування нац...
17603. ПРОГРАМУВАННЯ ТА ПРОГНОЗУВАННЯ НАЦІОНАЛЬНОЇ ЕКОНОМІКИ 301.5 KB
  PAGE 31 ТЕМА: ПРОГРАМУВАННЯ ТА ПРОГНОЗУВАННЯ НАЦІОНАЛЬНОЇ ЕКОНОМІКИ ПЛАН 1. Суть державного програмування види програм. Цільові комплексні програми розвитку національної економіки 2. Програми економічного й соціального розвитку. Міжнародні програ...
17604. Характеристика економічного потенціалу 342.5 KB
  ТЕМА Характеристика економічного потенціалу. План 1. Поняття та склад потенціалу національної економіки 2. Природноресурсний потенціал 3. Демографічний та трудовий потенціал 4. Науковотехнічний потенціал 5. Інформаційний потенціал 6. Виробничий потенціал ...
17605. ФУНКЦІОНУВАННЯ ІНФРАСТРУКТУРИ НАЦІОНАЛЬНОГО РИНКУ 251.5 KB
  ТЕМА: ФУНКЦІОНУВАННЯ ІНФРАСТРУКТУРИ НАЦІОНАЛЬНОГО РИНКУ План 1 Національний ринок України і його проблеми 2. Проблеми національного ринку 3. Сутність і функціонуеання ринкової інфраструктури 4. Вплив ринкової інфраструктури на формування конкурентного середов