Hello rakan-rakan dan rakan sekerja masa depan! Baru-baru ini, saya mengambil ujian untuk mengambil bahagian dalam projek sebenar, lulus, tetapi kebetulan kerana keadaan peribadi saya tidak dapat mengambil bahagian dalam RP itu sendiri. Selepas masalah menarik seperti ujian RP, masalah kursus biasa menjadi hobi yang kurang menarik, terutamanya kerana saya telah menyelesaikan kebanyakannya. Oleh itu, supaya bakat saya tidak disia-siakan untuk terus belajar, saya memutuskan untuk mencipta permainan web berbilang pemain. Pautan ke permainan lain:
Tic Tac Toe kelihatan seperti permainan yang paling mudah bagi saya, jadi saya memutuskan untuk memecahkan tugas itu kepada beberapa subtugas:
Algoritma pertama adalah menyemak seluruh medan
- Aplikasi konsol untuk menguji logik permainan
- Berbilang pemain
- Melampirkan pangkalan data pemain pada aplikasi konsol
- Mencipta reka bentuk bahagian hadapan, menulis templat halaman, antara muka permainan
- Menyatukan semuanya
- padang
- dua pemain yang bergilir-gilir, seorang meletakkan pangkah, yang kedua sifar. ianya mudah.
String[][] strings = {{"O", "O", "_"},
{"_", "X", "O"},
{"X", "X", "X"},
for (String [] ss : strings){
for (String s : ss) System.out.print(s + " ");
System.out.println(); //для перевода строки
}
skrin akan memaparkan:
O O _
_ X O
X X X
Tetapi sebagai tambahan kepada paparan, kami juga mempunyai perbandingan nilai, dan di sini pilihan sudah mungkin. Anda boleh membandingkan rentetan, anda boleh mencipta kelas penghitungan khas ( enum
), tetapi saya lebih suka membandingkan nombor, dan menggantikannya dengan "X" dan "O" hanya apabila dipaparkan pada skrin. Biarkan ia, sebagai contoh, 1 - "X", 2 - "O", 0 - "_". Jadi, bagaimanakah anda menyemak medan untuk padanan tiga X atau O?
Algoritma pertama adalah menyemak seluruh medan
int[][] canvas = {{00, 01, 02},
{10, 11, 12},
{20, 21, 22}}
Kombinasi kemenangan:
00-01-02, 10-11-12, 20-21-22, 00-10-20, 01-11-21, 02-12-22, 00-11-22, 20-11-02 — всего 8.
Menyemak dengan membandingkan nombor, tetapi ternyata anda perlu menyemak SELURUH medan, kesemua 8 kombinasi, setiap kali. Sudah tentu, ini tidak banyak, ini bukan carian untuk nombor Armstrong dalam julat dari 0 hingga 1 bilion, terdapat lebih sedikit daripada tiada pengiraan di sini, tetapi anda masih mahukan sesuatu yang lebih optimum daripada menyemak seluruh medan. Idea kedua yang datang kepada saya adalah untuk menyemak hanya sel yang ditanda pada langkah sebelumnya, jadi kita masih boleh menentukan pemenang, kerana kita akan tahu siapa yang membuat langkah ini. Oleh itu, daripada semua 8 kombinasi, kita hanya mendapat 2, 3 atau 4 kombinasi, bergantung pada sel, lihat gambar: Sekarang kita perlu memikirkan bagaimana untuk menentukan gabungan mana yang perlu dilancarkan? Di sinilah saya menyedari bahawa menggunakan tatasusunan dua dimensi tidak begitu mudah. Saya memutuskan untuk melihat pilihan lain. Pada mulanya saya mendapat idea bahawa medan itu boleh disimpan dalam nombor sembilan digit, sebagai contoh, medan yang sama yang kami paparkan pada skrin boleh ditulis seperti ini: 220012111, saya akan menerangkan dengan jari saya apa itu ialah... Kod adalah sama, 1 - “X”, 2 - “O” , 0 – " ", yang bermaksud 220012111 = "OO__XOXXX", atau jika selepas setiap digit ketiga anda memasukkan pemisah baris dan menambah ruang untuk kejelasan:
О О _
_ Х О
Х Х Х
di sini sekali lagi, mudah untuk penyimpanan, peranti untuk paparan telah dicipta, tetapi menyusahkan untuk perbandingan! Penyelesaiannya ditemui apabila saya menomborkan sel 1-9, kemudian saya berfikir, kerana dalam pengaturcaraan kira detik bermula dari 0 dan menomborkannya seperti dalam gambar. Adakah anda tidak perasan sebarang keanehan? jika anda melihat gambar di atas, ia akan menjadi jelas bahawa penyelesaian dengan 2 kombinasi mempunyai nombor siri ganjil, 4 kombinasi mempunyai nombor siri 4, 3 kombinasi mempunyai selebihnya. Jadi saya sampai pada kesimpulan bahawa anda perlu mengekalkan padang permainan dalam susunan nombor biasa: lelaran mudah antara nombor, keupayaan untuk membandingkan mengikut algoritma yang dipilih, output mudah ke skrin. Bagi algoritma perbandingan itu sendiri. Mari kita berurutan: dalam semua pilihan terdapat semakan baris dan lajur, kami hanya menyemaknya. jika carian tidak membuahkan hasil, kami menyemak nombor sel untuk genap/ganjil, jika ganjil, kemudian kami kembali ke permainan, tidak ada gunanya menyemak lebih lanjut, jika ia genap, kami menyemak sama ada sel ini terletak pada pepenjuru kiri, nombor pepenjuru ini apabila dibahagikan dengan 4 mempunyai baki 0. Jika ia terletak, kita semak padanan, jika tiada padanan ditemui, maka kita semak nombor 4, jika tidak, kembali ke permainan, jika ya, kami pergi lebih jauh melalui kod dan mengembalikan hasil pemeriksaan pepenjuru terakhir. Mungkin, bagi orang yang tidak bersedia, ini sukar difahami selepas membaca set surat di atas, tetapi seseorang mungkin mengatakan bahawa terdapat banyak huruf dalam kod itu sendiri, yang boleh menjadi lebih mudah, saya akan gembira untuk membincangkan perkara ini. Kami telah menyelesaikan bidang, kini kami perlu berurusan dengan dua pengguna yang bergilir-gilir dan setiap daripada mereka mempunyai tanda mereka sendiri, X atau O. Pada peringkat pertama, kami tidak mempunyai sebarang fungsi berbilang pengguna, jadi cara paling mudah ialah menggunakan ikon satu demi satu. X sentiasa membuat langkah pertama, O sentiasa membuat yang kedua, kemudian X lagi, dan seterusnya. Ia mohon untuk diperiksa ( benar/salah ), dan jika benar – maka pemain semasa ialah X, jika palsu – maka O dan pada permulaan setiap pergerakan flag=!flag Ia tetap menerima isyarat daripada pemain tentang yang mana sel yang mereka pilih. Di sini kami memerlukan BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
Pemain kami yang tidak dapat dilupakan akan memasukkan nombor sel ke dalam konsol, dan menekan Enter akan bergerak. Sel yang sepadan dengan nombor yang dimasukkan akan menukar nilainya daripada 0 kepada 1 atau 2, bergantung pada keadaan semasa kotak semak, yang telah dibincangkan dalam perenggan di atas. Di sinilah pentingnya untuk mengesahkan input supaya tiada siapa boleh menukar X kepada O apabila sel sudah diisi :) Apakah yang boleh dimasukkan oleh pemain ke dalam konsol?
- baris kosong
- huruf, tanda baca, kurungan... dalam satu perkataan, bukan nombor
- nombor yang salah - negatif atau di luar saiz tatasusunan, sel yang diduduki.
Integer.parseInt("2");
Ia membuang pengecualian NumberFormatException
jika ia tidak boleh mendapatkan digit daripada rentetan yang diberikan. Kami boleh memberikan perlindungan daripada dua titik pertama dengan memintas pengecualian ini. Untuk titik ketiga, saya akan mencipta kaedah lain yang menyemak nilai yang dimasukkan, tetapi adalah paling tepat untuk mengalihkan permintaan rentetan ke kaedah berasingan di mana pengesahan akan dilakukan, dan ia hanya akan mengembalikan nombor. Untuk meringkaskan, kami mencipta medan, membuat kaedah yang memaparkannya, membuat kaedah yang menyemak "adakah pemain ini menang sejam?", dan mengesahkan nombor yang dimasukkan. Terdapat sedikit lagi yang perlu dilakukan, semak untuk seri - kaedah berasingan yang dijalankan melalui tatasusunan dan mencari 0, dan memaparkan keputusan permainan. Itu sahaja, kod sudah siap, permainan ternyata kecil, hanya satu kelas, jadi copy-pasters yang sukar boleh, tanpa memahami, hanya menyalin segala-galanya ke dalam projek mereka dan menjalankannya sendiri, saya sendiri begitu, tetapi sekarang saya cuba untuk tidak berbuat demikian dan bukan kepada sesiapa yang saya cadangkan :) Semoga berjaya kepada semua orang dalam mempelajari JAVA! ps mata yang lain - berbilang pemain dan pangkalan data akan datang kemudian, saya sudah mula mengkaji bahan :)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class GameField {
static int [] canvas = {0,0,0,
0,0,0,
0,0,0};
//012, 345, 678, 036, 147, 258, 048, 246
public static void main(String[] args){
boolean b;
boolean isCurrentX = false;
do {
isCurrentX = !isCurrentX;
drawCanvas();
System.out.println("mark " + (isCurrentX ? "X" : "O"));
int n = getNumber();
canvas[n] = isCurrentX ? 1 : 2;
b = !isGameOver(n);
if (isDraw()){
System.out.println("Draw");
return;
}
} while (b);
drawCanvas();
System.out.println();
System.out.println("The winner is " + (isCurrentX ? "X" : "O") + "!");
}
static int getNumber(){
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (true){
try {
int n = Integer.parseInt(reader.readLine());
if (n >= 0 && n < canvas.length && canvas[n]==0){
return n;
}
System.out.println("Choose free cell and enter its number");
} catch (NumberFormatException e) {
System.out.println("Please enter the number");
} catch (IOException e) {
}
}
}
static boolean isGameOver(int n){
// 0 1 2
// 3 4 5
// 6 7 8
//поиск совпадений по горизонтали
int row = n-n%3; //номер строки - проверяем только её
if (canvas[row]==canvas[row+1] &&
canvas[row]==canvas[row+2]) return true;
//поиск совпадений по вертикали
int column = n%3; //номер столбца - проверяем только его
if (canvas[column]==canvas[column+3])
if (canvas[column]==canvas[column+6]) return true;
//мы здесь, значит, первый поиск не положительного результата
//если meaning n находится на одной из граней - возвращаем false
if (n%2!=0) return false;
//проверяем принадлежит ли к левой диагонали meaning
if (n%4==0){
//проверяем есть ли совпадения на левой диагонали
if (canvas[0] == canvas[4] &&
canvas[0] == canvas[8]) return true;
if (n!=4) return false;
}
return canvas[2] == canvas[4] &&
canvas[2] == canvas[6];
}
static void drawCanvas(){
System.out.println(" | | ");
for (int i = 0; i < canvas.length; i++) {
if (i!=0){
if (i%3==0) {
System.out.println();
System.out.println("_____|_____|_____");
System.out.println(" | | ");
}
else
System.out.print("|");
}
if (canvas[i]==0) System.out.print(" " + i + " ");
if (canvas[i]==1) System.out.print(" X ");
if (canvas[i]==2) System.out.print(" O ");
}
System.out.println();
System.out.println(" | | ");
}
public static boolean isDraw() {
for (int n : canvas) if (n==0) return false;
return true;
}
}
GO TO FULL VERSION