สวัสดีเพื่อน ๆ และเพื่อนร่วมงานในอนาคต! เมื่อเร็ว ๆ นี้ฉันได้ทำการทดสอบเพื่อเข้าร่วมในโครงการจริงและผ่านมันไป แต่มันก็เกิดขึ้นจนไม่สามารถมีส่วนร่วมใน RP ได้เนื่องจากสถานการณ์ส่วนตัว หลังจากปัญหาที่น่าสนใจเช่นการทดสอบ RP ปัญหาของหลักสูตรปกติก็กลายเป็นงานอดิเรกที่น่าดึงดูดน้อยลง โดยเฉพาะอย่างยิ่งเมื่อฉันได้แก้ไขปัญหาส่วนใหญ่ไปแล้ว ดังนั้น เพื่อไม่ให้พรสวรรค์ของฉันสูญเปล่าในการเรียนรู้ต่อ ฉันจึงตัดสินใจสร้างเกมบนเว็บที่มีผู้เล่นหลายคน ลิงค์เกมอื่นๆ:
Tic Tac Toe ดูเหมือนเป็นเกมที่ง่ายที่สุดสำหรับฉัน ดังนั้นฉันจึงตัดสินใจแบ่งงานออกเป็นงานย่อยหลายงาน:
อัลกอริธึมแรกคือการตรวจสอบทั้งฟิลด์
- แอปพลิเคชันคอนโซลสำหรับทดสอบตรรกะของเกม
- ผู้เล่นหลายคน
- การแนบฐานข้อมูลผู้เล่นเข้ากับแอปพลิเคชันคอนโซล
- การสร้างการออกแบบส่วนหน้า การเขียนเทมเพลตหน้า อินเทอร์เฟซเกม
- วางมันทั้งหมดเข้าด้วยกัน
- สนาม
- ผู้เล่นสองคนที่ผลัดกัน คนหนึ่งวางกากบาท คนที่สองเป็นศูนย์ มันง่ายมาก
String[][] strings = {{"O", "O", "_"},
{"_", "X", "O"},
{"X", "X", "X"},
for (String [] ss : strings){
for (String s : ss) System.out.print(s + " ");
System.out.println(); //для перевода строки
}
หน้าจอจะแสดง:
O O _
_ X O
X X X
แต่นอกเหนือจากการแสดงแล้ว เรายังมีการเปรียบเทียบค่าด้วย และที่นี่มีตัวเลือกต่างๆ ที่เป็นไปได้อยู่แล้ว คุณสามารถเปรียบเทียบสตริงได้ คุณสามารถสร้างคลาสการแจงนับพิเศษ ( enum
) ได้ แต่ฉันต้องการเปรียบเทียบตัวเลข และแทนที่ด้วย "X" และ "O" เมื่อแสดงบนหน้าจอเท่านั้น ปล่อยให้มันเป็นเช่น 1 - "X", 2 - "O", 0 - "_" แล้วคุณจะตรวจสอบสนามสำหรับการแข่งขัน Triple X หรือ O ได้อย่างไร?
อัลกอริธึมแรกคือการตรวจสอบทั้งฟิลด์
int[][] canvas = {{00, 01, 02},
{10, 11, 12},
{20, 21, 22}}
ชุดค่าผสมที่ชนะ:
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.
ตรวจโดยเทียบตัวเลขแต่ปรากฏว่าต้องตรวจทั้งช่องทั้ง 8 ชุดทุกครั้ง แน่นอนว่ายังไม่มาก นี่ไม่ใช่การค้นหาตัวเลขของ Armstrong ในช่วงตั้งแต่ 0 ถึง 1 พันล้าน ไม่มีการคำนวณที่นี่เลย แต่คุณยังคงต้องการบางสิ่งที่เหมาะสมกว่าการตรวจสอบทั้งฟิลด์ แนวคิดที่สองที่เข้ามาหาฉันคือตรวจสอบเฉพาะช่องที่ถูกทำเครื่องหมายไว้ในการเคลื่อนไหวครั้งก่อน เพื่อให้เรายังคงสามารถระบุผู้ชนะได้ เพราะเราจะรู้ว่าใครเป็นผู้ทำการเคลื่อนไหวนี้ ดังนั้นแทนที่จะเป็นชุดค่าผสมทั้งหมด 8 ชุด เราจะได้ชุดค่าผสมเพียง 2, 3 หรือ 4 ชุดเท่านั้น ขึ้นอยู่กับเซลล์ ดูภาพ: ตอนนี้เราต้องหาวิธีกำหนดว่าจะต้องเปิดใช้ชุดค่าผสมใด นี่คือจุดที่ฉันรู้ว่าการใช้อาร์เรย์สองมิติไม่สะดวกนัก ฉันตัดสินใจพิจารณาตัวเลือกอื่น ตอนแรกผมเกิดไอเดียว่าช่องสามารถเก็บเป็นตัวเลข 9 หลักได้ เช่น ช่องเดียวกับที่เราแสดงบนหน้าจอก็เขียนได้ดังนี้ 220012111 ฉันจะอธิบายด้วยนิ้วว่ามันคืออะไร คือ... รหัสเหมือนกัน 1 - “X”, 2 - “O” , 0 – " " ซึ่งหมายถึง 220012111 = "OO__XOXXX" หรือถ้าหลังจากทุก ๆ หลักที่สามคุณแทรกตัวแบ่งบรรทัดและเพิ่มช่องว่างสำหรับ ความชัดเจน:
О О _
_ Х О
Х Х Х
ที่นี่อีกแล้ว สะดวกแก่การจัดเก็บ มีอุปกรณ์แสดงผล แต่เทียบไม่สะดวก! พบวิธีแก้ปัญหาเมื่อฉันกำหนดหมายเลขเซลล์ 1-9 ฉันคิดว่าเพราะในการเขียนโปรแกรมการนับถอยหลังเริ่มจาก 0 และกำหนดหมายเลขตามภาพ คุณไม่สังเกตเห็นลักษณะเฉพาะใด ๆ เลยเหรอ? หากคุณดูภาพด้านบนจะเห็นได้ชัดว่าโซลูชันที่มี 2 ชุดค่าผสมมีหมายเลขซีเรียลคี่ ชุดค่าผสม 4 ชุดมีหมายเลขซีเรียล 4 ชุดค่าผสม 3 ชุดมีส่วนที่เหลือ ดังนั้นฉันจึงได้ข้อสรุปว่าคุณต้องรักษาสนามแข่งขันให้อยู่ในอาร์เรย์ตัวเลขปกติ: การวนซ้ำอย่างง่ายระหว่างตัวเลข ความสามารถในการเปรียบเทียบตามอัลกอริทึมที่เลือก เอาต์พุตอย่างง่ายไปยังหน้าจอ สำหรับอัลกอริธึมการเปรียบเทียบนั้นเอง ตามลำดับ: ในตัวเลือกทั้งหมดจะมีการตรวจสอบแถวและคอลัมน์เราตรวจสอบเท่านั้น หากการค้นหาไม่เป็นผล เราจะตรวจสอบหมายเลขเซลล์เป็นคู่/คี่ หากเป็นคี่ เราก็กลับเข้าสู่เกม ไม่มีประเด็นให้ตรวจสอบเพิ่มเติม หากเป็นคู่ เราจะตรวจสอบว่าเซลล์นี้อยู่บน เส้นทแยงมุมซ้ายจำนวนเส้นทแยงมุมนี้เมื่อหารด้วย 4 แล้วจะเหลือ 0 หากเป็นเท็จเราจะตรวจสอบการจับคู่หากไม่พบการจับคู่เราจะตรวจสอบหมายเลข 4 หากไม่ใช่ให้กลับเข้าเกมหาก ใช่ เราดำเนินการโค้ดเพิ่มเติมและส่งคืนผลลัพธ์ของการตรวจสอบเส้นทแยงมุมสุดท้าย อาจเป็นเรื่องยากที่จะเข้าใจสำหรับคนที่ไม่ได้เตรียมตัวหลังจากอ่านชุดตัวอักษรด้านบน แต่บางคนอาจบอกว่ามีตัวอักษรจำนวนมากในโค้ดเองซึ่งอาจง่ายกว่านี้ฉันยินดีที่จะหารือเรื่องนี้ เราได้แยกส่วนออกแล้ว ตอนนี้เราต้องจัดการกับผู้ใช้สองคนที่ผลัดกันและแต่ละคนมีสัญลักษณ์ X หรือ O เป็นของตัวเอง ในระยะแรก เราไม่มีฟังก์ชันการใช้งานแบบหลายผู้ใช้ ดังนั้น วิธีที่ง่ายที่สุดคือการใช้ไอคอนทีละไอคอน X จะทำการเคลื่อนไหวครั้งแรกเสมอ O จะทำการเคลื่อนไหวครั้งที่สองเสมอ จากนั้น X อีกครั้ง และต่อๆ ไป มันขอให้ตรวจสอบ ( จริง/เท็จ ) และถ้าเป็นจริง – ดังนั้นผู้เล่นปัจจุบันคือ X ถ้าเป็นเท็จ – แล้ว O และที่จุดเริ่มต้นของแต่ละการย้าย flag=!flag มันยังคงได้รับสัญญาณจากผู้เล่นเกี่ยวกับที่ เซลล์ที่พวกเขาเลือก ที่นี่เราต้องการให้BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
ผู้เล่นที่น่าจดจำของเราป้อนหมายเลขเซลล์ลงในคอนโซลแล้วกด Enter จะเป็นการเคลื่อนไหว เซลล์ที่สอดคล้องกับหมายเลขที่ป้อนจะเปลี่ยนค่าจาก 0 เป็น 1 หรือ 2 ขึ้นอยู่กับสถานะปัจจุบันของช่องทำเครื่องหมายซึ่งได้กล่าวถึงในย่อหน้าข้างต้น นี่คือจุดสำคัญที่จะต้องตรวจสอบความถูกต้องของอินพุตเพื่อไม่ให้ใครเปลี่ยน X เป็น O ได้เมื่อเซลล์เต็มแล้ว :) ผู้เล่นสามารถเข้าสู่คอนโซลอะไรได้บ้าง
- บรรทัดว่าง
- ตัวอักษร เครื่องหมายวรรคตอน วงเล็บ...ในคำเดียว ไม่ใช่ตัวเลข
- ตัวเลขไม่ถูกต้อง - ลบหรืออยู่นอกขนาดอาร์เรย์ เซลล์ที่ถูกครอบครอง
Integer.parseInt("2");
มันจะส่งข้อยกเว้นNumberFormatException
หากไม่สามารถรับตัวเลขจากสตริงที่กำหนด เราสามารถให้การป้องกันจากสองจุดแรกโดยการสกัดกั้นข้อยกเว้นนี้ สำหรับจุดที่สาม ฉันจะสร้างวิธีอื่นที่ตรวจสอบค่าที่ป้อน แต่จะถูกต้องที่สุดถ้าย้ายคำขอสตริงไปยังวิธีอื่นที่จะดำเนินการตรวจสอบความถูกต้อง และจะส่งกลับเฉพาะตัวเลขเท่านั้น โดยสรุป เราได้สร้างฟิลด์ สร้างวิธีการแสดง สร้างวิธีการตรวจสอบว่า "ผู้เล่นรายนี้ชนะภายในหนึ่งชั่วโมงหรือไม่" และตรวจสอบตัวเลขที่ป้อน เหลือเวลาอีกน้อยมากที่ต้องทำ ตรวจสอบการเสมอ - วิธีการแยกต่างหากที่รันผ่านอาเรย์และค้นหา 0 และแสดงผลเกม เพียงเท่านี้ รหัสก็พร้อมแล้ว เกมกลายเป็นเกมขนาดเล็ก มีเพียงคลาสเดียว ดังนั้นผู้คัดลอกพาสที่แข็งแกร่งสามารถคัดลอกทุกอย่างลงในโปรเจ็กต์ของพวกเขาและรันด้วยตัวเองโดยไม่เข้าใจ ฉันก็เป็นเช่นนั้น แต่ ตอนนี้ฉันพยายามไม่ทำอย่างนั้นและไม่ใช่กับใครก็ตามที่ฉันแนะนำ :) ขอให้ทุกคนโชคดีในการเรียนรู้ JAVA! ป.ล. ส่วนที่เหลือ - ผู้เล่นหลายคนและฐานข้อมูลจะมาในภายหลัง ฉันได้เริ่มศึกษาเนื้อหาแล้ว :)
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