You are on page 1of 9

Прізвище: Храновський

Ім'я: Микола
Група: КН-304

Кафедра: САПР
Дисципліна: Методи та системи штучного інтелекту
Перевірив: Головацький Р. І.

ЗВІТ
до лабораторної роботи №4
“Неінформовані методи пошуку рішення задач в просторі й стані. Алгоритм А*”
Мета роботи – розглянути метод оціночних функцій А*, набути практичні
навички у його використанні та програмуванні.

Завдання – дослідити рішення задачі «Гра у 15» за допомогою методу оціночних


функцій А*.
Варіант 30

2 4 5

8 11 14 9

3 1 7 13

12 15 10 6

Теоретичні відомості
Неінформований пошук – стратегія пошуку рішення в просторі
станів, в якій не використовується додаткова інформація про стани, крім тієї,
яка представлена в конкретній задачі. Все, на що здатен метод не
інформованого пошуку, – створювати синів та відрізняти цільовий стан від
нецільового.
На відміну від алгоритмів повного перебору (пошук в
глибину/ширину) алгоритм A* дозволяє суттєво зменшити кількість станів
для перебору шляхом застосування деякої додаткової інформації, евристики.
В якості такої інформації пропонується брати передбачувану кількість
перестановок, необхідних для отримання цільового стану.
Алгоритм A* передбачає наявність двох списків вершин графа:
відкритого та закритого. В першому знаходяться вершини, які ще не
перевірені алгоритмом, а в другому – ті вершини, які вже зустрічались під
час пошуку рішення.
На кожному новому кроці, із списку відкритих вершин вибирається
вершина з найменшою вагою. Вага (F) кожної вершини обчислюється як
сума відстані від початкової вершини до поточної (G) та евристичне
припущення про відстань від поточної вершини до цільової (H).  Fi = Gi + Hi,
де i – поточна вершина (стан ігрового поля).
Для обчислення евристичного припущення H можна використати
наступні метрики:

Евклідова відстань:

Відстань міських кварталів:

Відстань Чебішева:
Код програми
package Lab5;

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

class State {
final static int UP = 4, DOWN = 1, LEFT = 2, RIGHT = 3;
final static int N = 4;
int[][] mas = new int[N][N];
public int depth = 0;
public double H = 0;
public double F = 0;

public State(int[][] mas) {


this.mas = mas;
}

public State(State s) {
this.mas = s.mas;
updateH();
}

public State(String str) {


int i = 0, j = 0;
for (String line : str.split("\n")) {
j = 0;
for (String s : line.split(" ")) {
mas[i][j++] = Integer.parseInt(s);
}
i++;
}
updateH();
}

public boolean move(int dirrection) {


boolean p = false;
int i = 0, j = 0;
outer: for (i = 0; i < N; i++)
for (j = 0; j < N; j++)
if (mas[i][j] == 0)
break outer;
switch (dirrection) {
case UP:
if (i != N - 1) {
mas[i][j] = mas[i + 1][j];
mas[i + 1][j] = 0;
p = true;
}
break;
case DOWN:
if (i != 0) {
mas[i][j] = mas[i - 1][j];
mas[i - 1][j] = 0;
p = true;
}
break;
case LEFT:
if (j != N - 1) {
mas[i][j] = mas[i][j + 1];
mas[i][j + 1] = 0;
p = true;
}
break;
case RIGHT:
if (j != 0) {
mas[i][j] = mas[i][j - 1];
mas[i][j - 1] = 0;
p = true;
}
break;
}

if (p) {
return true;
} else
return false;
}

public void updateH() {


H = 0;
H += Math.abs(mas[0][0] - 1); H += Math.abs(mas[0][1] - 2); H +=
Math.abs(mas[0][2] - 3); H += Math.abs(mas[0][3] - 4);
H += Math.abs(mas[1][0] - 5); H += Math.abs(mas[1][1] - 6); H +=
Math.abs(mas[1][2] - 7); H += Math.abs(mas[1][3] - 8);
H += Math.abs(mas[2][0] - 9); H += Math.abs(mas[2][1] - 10); H +=
Math.abs(mas[2][2] - 11); H += Math.abs(mas[2][3] - 12);
H += Math.abs(mas[3][0] - 13); H += Math.abs(mas[3][1] - 14); H
+= Math.abs(mas[3][2] - 15);

// H = 0;
// H = Math.max(mas[0][0] - 1, H);H = Math.max(mas[0][1] - 2, H);H =
// Math.max(mas[0][2] - 3, H);H = Math.max(mas[0][3] - 4, H);
// H = Math.max(mas[1][0] - 5, H);H = Math.max(mas[1][1] - 6, H);H =
// Math.max(mas[1][2] - 7, H);H = Math.max(mas[1][3] - 8, H);
// H = Math.max(mas[2][0] - 9, H);H = Math.max(mas[2][1] - 10, H);H =
// Math.max(mas[2][2] - 11, H);H = Math.max(mas[2][3] - 12, H);
// H = Math.max(mas[3][0] - 13, H);H = Math.max(mas[3][1] - 14, H);H =
// Math.max(mas[3][2] - 15, H);

// H = 0;
// H = (mas[0][0] != 1) ? H + 1 : H;
// H = (mas[0][1] != 2) ? H + 1 : H;
// H = (mas[0][2] != 3) ? H + 1 : H;
// H = (mas[0][3] != 4) ? H + 1 : H;
// H = (mas[1][0] != 5) ? H + 1 : H;
// H = (mas[1][1] != 6) ? H + 1 : H;
// H = (mas[1][2] != 7) ? H + 1 : H;
// H = (mas[1][3] != 8) ? H + 1 : H;
// H = (mas[2][0] != 9) ? H + 1 : H;
// H = (mas[2][1] != 10) ? H + 1 : H;
// H = (mas[2][2] != 11) ? H + 1 : H;
// H = (mas[2][3] != 12) ? H + 1 : H;
// H = (mas[3][0] != 13) ? H + 1 : H;
// H = (mas[3][1] != 14) ? H + 1 : H;
// H = (mas[3][2] != 15) ? H + 1 : H;
}

public void updateF() {


F = H + depth;
}

public int[][] getMas() {


int[][] newArray = new int[N][N];
for (int i = 0; i < N; i++)
System.arraycopy(mas[i], 0, newArray[i], 0, N);
return newArray;
}

public String toString() {


String result = "";
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++)
result += mas[i][j] + " ";
result += "\n";
}
return result;
}

@Override
public boolean equals(Object o) {
State s = (State) o;
if (arrayEquals(getMas(), s.getMas())) {
return true;
} else {
return false;
}
}

public boolean arrayEquals(int[][] a, int[][] b) {


for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
if (a[i][j] != b[i][j])
return false;
return true;
}
}

class MyFrame extends JFrame {


State result = new State(new int[][] { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10,
11, 12 }, { 13, 14, 15, 0 } });
State result1 = new State(new int[][] { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 10,
11, 12 }, { 13, 15, 14, 0 } });
LinkedList<String> CLOSED = null;
Queue<State> OPEN = null;

public MyFrame() {
super("GameEight");
setBounds(100, 100, 250, 450);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new FlowLayout(FlowLayout.CENTER));
JTextField s11 = new JTextField("8", 4); JTextField s12 = new
JTextField("2", 4);
JTextField s13 = new JTextField("7", 4); JTextField s14 = new
JTextField("1", 4);
JTextField s21 = new JTextField("15", 4); JTextField s22 = new
JTextField("14", 4);
JTextField s23 = new JTextField("5", 4); JTextField s24 = new
JTextField("9", 4);
JTextField s31 = new JTextField("5", 4); JTextField s32 = new
JTextField("1", 4);
JTextField s33 = new JTextField("0", 4); JTextField s34 = new
JTextField("10", 4);
JTextField s41 = new JTextField("14", 4); JTextField s42 = new
JTextField("6", 4);
JTextField s43 = new JTextField("9", 4); JTextField s44 = new
JTextField("12", 4);
add(s11); add(s12); add(s13);
add(s14);
add(s21); add(s22); add(s23);
add(s24);
add(s31); add(s32); add(s33);
add(s34);
add(s41); add(s42); add(s43);
add(s44);

JButton btnCalc = new JButton("Proceed");


add(btnCalc);
JButton btnStep = new JButton("Step");
add(btnStep);

JTextArea ta = new JTextArea(16, 18);


JScrollPane scroll = new JScrollPane(ta,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
add(scroll);

State start = new State(new int[][] {


{ Integer.parseInt(s11.getText()),
Integer.parseInt(s12.getText()), Integer.parseInt(s13.getText()),
Integer.parseInt(s14.getText()) },
{ Integer.parseInt(s21.getText()),
Integer.parseInt(s22.getText()), Integer.parseInt(s23.getText()),
Integer.parseInt(s24.getText()) },
{ Integer.parseInt(s31.getText()),
Integer.parseInt(s32.getText()), Integer.parseInt(s33.getText()),
Integer.parseInt(s34.getText()) },
{ Integer.parseInt(s41.getText()),
Integer.parseInt(s42.getText()), Integer.parseInt(s43.getText()),
Integer.parseInt(s44.getText()) } });

LinkedList<String> CLOSED = new LinkedList<String>();

Queue<State> OPEN = new PriorityQueue<State>(new Comparator<State>() {


public int compare(State s1, State s2) {
if (Double.compare(s1.F, s2.F) < 0)
return -1;
else
return 1;
}
});

start.depth = 0;
start.updateF();
OPEN.add(start);

btnStep.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
State tmp = null, s = null;
if (!OPEN.isEmpty()) {
ta.setText("");
tmp = OPEN.poll();
CLOSED.add(tmp.toString());
ta.append("Current: (depth=" + tmp.depth + ", F=" +
tmp.F + ")\n" + tmp);
ta.append("\nSons:\n");
s = new State(tmp.getMas());
s.depth = tmp.depth + 1;
if (s.move(State.UP)) {
if (!CLOSED.contains(s.toString())) {
if (!OPEN.contains(s)) {
ta.append(s.toString() + "\n");
s.updateH();
s.updateF();
OPEN.add(s);
}
}
}
s = new State(tmp.getMas());
s.depth = tmp.depth + 1;
if (s.move(State.LEFT)) {
if (!CLOSED.contains(s.toString())) {
if (!OPEN.contains(s)) {
ta.append(s.toString() + "\n");
s.updateH();
s.updateF();
OPEN.add(s);
}
}
}
s = new State(tmp.getMas());
s.depth = tmp.depth + 1;
if (s.move(State.RIGHT)) {
if (!CLOSED.contains(s.toString())) {
if (!OPEN.contains(s)) {
ta.append(s.toString() + "\n");
s.updateH();
s.updateF();
OPEN.add(s);
}
}
}
s = new State(tmp.getMas());
s.depth = tmp.depth + 1;
if (s.move(State.DOWN)) {
if (!CLOSED.contains(s.toString())) {
if (!OPEN.contains(s)) {
ta.append(s.toString() + "\n");
s.updateH();
s.updateF();
OPEN.add(s);
}
}
}
ta.append("OPEN: " + OPEN.size() + "\nCLOSED: " +
CLOSED.size());
}
}
});

btnCalc.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
State tmp = null, s = null;
int i = 0;

try {
while (!OPEN.isEmpty()) {
tmp = OPEN.poll();
CLOSED.add(tmp.toString());
if (check(tmp, result) || check(tmp,
result1))
throw new IndexOutOfBoundsException();
s = new State(tmp.getMas());
s.depth = tmp.depth + 1;
if (s.move(State.UP)) {
if (check(s, result) || check(s,
result1))
throw new
IllegalArgumentException();
if (!CLOSED.contains(s.toString())) {
if (!OPEN.contains(s)) {
s.updateH();
s.updateF();
OPEN.add(s);
}
}
}
s = new State(tmp.getMas());
s.depth = tmp.depth + 1;
if (s.move(State.LEFT)) {
if (check(s, result) || check(s,
result1))
throw new
IllegalArgumentException();
if (!CLOSED.contains(s.toString())) {
if (!OPEN.contains(s)) {
s.updateH();
s.updateF();
OPEN.add(s);
}
}
}
s = new State(tmp.getMas());
s.depth = tmp.depth + 1;
if (s.move(State.RIGHT)) {
if (check(s, result) || check(s,
result1))
throw new
IllegalArgumentException();
if (!CLOSED.contains(s.toString())) {
if (!OPEN.contains(s)) {
s.updateH();
s.updateF();
OPEN.add(s);
}
}
}
s = new State(tmp.getMas());
s.depth = tmp.depth + 1;
if (s.move(State.DOWN)) {
if (check(s, result) || check(s,
result1))
throw new
IllegalArgumentException();
if (!CLOSED.contains(s.toString())) {
if (!OPEN.contains(s)) {
s.updateH();
s.updateF();
OPEN.add(s);
}
}
}
System.out.println("Number of checked state:
" + i++);
}
ta.setText("Sorry, program could not\nfind the
solution");
} catch (IndexOutOfBoundsException e1) {
ta.setText(tmp + "\nDepth: " + tmp.depth + "\nOPEN
states: " + OPEN.size() + "\nCLOSED states: "
+ CLOSED.size() + "\nALL states: " +
(CLOSED.size() + OPEN.size()));
} catch (IllegalArgumentException e2) {
ta.setText(s + "\nDepth: " + s.depth + "\nOPEN
states: " + OPEN.size() + "\nCLOSED states: "
+ CLOSED.size() + "\nALL states: " +
(CLOSED.size() + OPEN.size()));
}
}
});

setVisible(true);
}

public boolean check(State s1, State s2) {


if (s1.toString().equals(s2.toString())) return true;
else return false;
}
}

public class Main {


public static void main(String[] args) {
new MyFrame();
}
}

Результат виконання програмного коду


Блок-схема алгоритму

Висновки: На даній лабораторній роботі ознайомився з методом оціночних


функцій А* (алгоритмом А*), під час пошуку рішення «Гри у 15».

You might also like