Saya pikir saya bisa menghasilkan semua status yang mungkin untuk satu tick game, tetapi dengan empat pemain dan 5 aksi dasar (4 gerakan dan tempat bom) memberikan 5 ^ 4 status di level pertama dari tree game.
Benar! Anda perlu mencari semua tindakan 5 ^ 4 (atau bahkan 6 ^ 4, karena Anda bisa berjalan ke 4 arah, berhenti dan "pasang bom"?) Untuk setiap centang game. TETAPI, ketika seorang pemain sudah memutuskan untuk pindah, dibutuhkan beberapa waktu hingga langkah tersebut dijalankan (mis. 10 tick game). Selama periode ini jumlah kemungkinan berkurang.
Nilai itu akan meningkat secara eksponensial dengan setiap level berikutnya. Apakah saya melewatkan sesuatu? Apakah ada cara untuk mengimplementasikannya atau haruskah saya menggunakan algoritma yang sama sekali berbeda?
Anda dapat menggunakan Hash-Table untuk hanya menghitung status permainan "subtree" yang sama satu kali. Bayangkan pemain A berjalan naik dan turun, sementara semua pemain lain "menunggu", Anda berakhir dalam keadaan permainan yang sama. Sama seperti untuk "kiri-kanan" atau "kanan-kiri". Juga memindahkan "atas-kemudian-kiri" dan "kiri-kemudian-atas" menghasilkan kondisi yang sama. Menggunakan Tabel-Hash Anda dapat "menggunakan kembali" skor yang dihitung untuk kondisi permainan yang telah dievaluasi. Ini mengurangi kecepatan pertumbuhan yang cukup banyak. Secara matematis, ini mengurangi basis fungsi pertumbuhan eksponensial Anda. Untuk mendapatkan gambaran tentang seberapa banyak hal itu mengurangi kompleksitas, mari kita lihat pergerakan yang mungkin dilakukan hanya untuk satu pemain dibandingkan dengan posisi yang dapat dijangkau di peta (= status permainan yang berbeda) jika pemain hanya dapat bergerak ke atas / bawah / kiri / kanan / berhenti .
kedalaman 1: 5 bergerak, 5 status berbeda, 5 status tambahan untuk rekursi ini
kedalaman 2: 25 bergerak, 13 status berbeda, 8 status tambahan untuk rekursi ini
kedalaman 3: 6125 bergerak, 25 status berbeda, 12 status tambahan untuk rekursi ini
Untuk memvisualisasikannya, jawab diri Anda sendiri: bidang mana di peta yang dapat dijangkau dengan satu gerakan, dua gerakan, tiga gerakan. Jawabannya adalah: Semua bidang dengan jarak maksimum = 1, 2 atau 3 dari posisi awal.
Saat menggunakan HashTable, Anda hanya perlu mengevaluasi setiap kondisi permainan yang dapat dijangkau (dalam contoh kami 25 pada kedalaman 3) satu kali. Sedangkan tanpa HashTable Anda perlu mengevaluasinya beberapa kali, yang berarti 6125 evaluasi, bukannya 25 pada level kedalaman 3. Yang terbaik: Setelah Anda menghitung entri HashTable, Anda dapat menggunakannya kembali dalam langkah waktu berikutnya ...
Anda juga dapat menggunakan subtingkat "cut" deepening deepening dan pemangkasan alpha-beta yang tidak layak dicari secara lebih mendalam. Untuk catur, ini mengurangi jumlah node yang dicari menjadi sekitar 1%. Pengantar singkat tentang pemangkasan alpha-beta dapat ditemukan sebagai video di sini: http://www.teachingtree.co/cs/watch?concept_name=Alpha-beta+Pruning
Awal yang baik untuk studi lebih lanjut adalah http://chessprogramming.wikispaces.com/Search . Halaman ini terkait dengan catur, tetapi algoritma pencarian dan optimisasi cukup sama.
Algoritma AI lain (tetapi kompleks) - yang akan lebih cocok untuk permainan - adalah "Temporal Difference Learning".
Salam
Stefan
PS: Jika Anda mengurangi jumlah status gim yang mungkin (mis. Ukuran peta yang sangat kecil, hanya satu bom per pemain, tidak ada yang lain), ada peluang untuk menghitung sebelum evaluasi untuk semua kondisi gim.
--edit--
Anda juga bisa menggunakan hasil perhitungan minimax yang dihitung secara offline untuk melatih jaringan saraf. Atau Anda dapat menggunakannya untuk mengevaluasi / membandingkan strategi yang diimplementasikan dengan tangan. Misalnya Anda dapat menerapkan beberapa "kepribadian" yang disarankan dan beberapa heuristik yang mendeteksi, di mana situasi strategi mana yang baik. Karenanya Anda harus "mengklasifikasikan" situasi (misalnya status permainan). Ini juga dapat ditangani oleh jaringan neuron: Latih jaringan neuron untuk memprediksi strategi kode tangan mana yang memainkan yang terbaik dalam situasi saat ini dan jalankan. Ini harus menghasilkan keputusan real-time yang sangat bagus untuk game nyata. Jauh lebih baik daripada pencarian batas bawah yang dapat dicapai jika tidak, karena tidak masalah berapa lama perhitungan offline dilakukan (sebelum sebelum permainan).
- edit # 2 -
Jika Anda hanya menghitung ulang gerakan terbaik Anda setiap 1 detik, Anda juga bisa mencoba melakukan perencanaan level yang lebih tinggi. Apa yang saya maksud dengan itu? Anda tahu berapa banyak gerakan yang dapat Anda lakukan dalam 1 detik. Jadi, Anda dapat membuat daftar posisi yang dapat dijangkau (mis. Jika ini adalah 3 gerakan dalam 1 detik, Anda akan memiliki 25 posisi yang dapat dijangkau). Maka Anda dapat merencanakan seperti: pergi ke "posisi x dan tempatkan bom". Seperti yang disarankan beberapa orang lainnya, Anda dapat membuat peta "bahaya", yang digunakan untuk algoritme perutean (cara menuju ke posisi x? Jalur mana yang harus dipilih [ada beberapa variasi yang mungkin dalam kebanyakan kasus]). Ini kurang memakan memori dibandingkan dengan HashTable yang sangat besar, tetapi menghasilkan hasil yang kurang optimal. Tetapi karena menggunakan lebih sedikit memori, itu bisa lebih cepat karena efek caching (lebih baik menggunakan cache memori L1 / L2 Anda).
TAMBAHAN: Anda bisa melakukan pra-pencarian yang hanya berisi gerakan untuk masing-masing pemain untuk memilah variasi yang mengakibatkan kehilangan. Karenanya, keluarkan semua pemain lain dari permainan ... Simpan kombinasi mana yang dapat dipilih setiap pemain tanpa kehilangan. Jika hanya ada gerakan yang kehilangan, cari kombinasi gerakan tempat pemain tetap hidup dalam waktu lama. Untuk menyimpan / memproses struktur pohon semacam ini, Anda harus menggunakan array dengan indeks-pointer seperti ini:
class Gamestate {
int value;
int bestmove;
int moves[5];
};
#define MAX 1000000
Gamestate[MAX] tree;
int rootindex = 0;
int nextfree = 1;
Setiap negara bagian memiliki "nilai" evaluasi dan tautan ke Gamestates berikutnya ketika memindahkan (0 = berhenti, 1 = naik, 2 = kanan, 3 = turun, 4 = kiri) dengan menyimpan indeks array dalam "pohon" dalam gerakan [0 ] untuk bergerak [4]. Untuk membangun pohon Anda secara rekursif ini bisa terlihat seperti ini:
const int dx[5] = { 0, 0, 1, 0, -1 };
const int dy[5] = { 0, -1, 0, 1, 0 };
int search(int x, int y, int current_state, int depth_left) {
// TODO: simulate bombs here...
if (died) return RESULT_DEAD;
if (depth_left == 0) {
return estimate_result();
}
int bestresult = RESULT_DEAD;
for(int m=0; m<5; ++m) {
int nx = x + dx[m];
int ny = y + dy[m];
if (m == 0 || is_map_free(nx,ny)) {
int newstateindex = nextfree;
tree[current_state].move[m] = newstateindex ;
++nextfree;
if (newstateindex >= MAX) {
// ERROR-MESSAGE!!!
}
do_move(m, &undodata);
int result = search(nx, ny, newstateindex, depth_left-1);
undo_move(undodata);
if (result == RESULT_DEAD) {
tree[current_state].move[m] = -1; // cut subtree...
}
if (result > bestresult) {
bestresult = result;
tree[current_state].bestmove = m;
}
}
}
return bestresult;
}
Jenis struktur pohon ini jauh lebih cepat, karena mengalokasikan memori secara dinamis sangat lambat! Tapi, menyimpan pohon pencarian juga cukup lambat ... Jadi ini lebih merupakan inspirasi.