مرحبا أصدقاء وزملاء المستقبل! لقد أجريت مؤخرًا اختبارًا للمشاركة في مشروع حقيقي، ونجحت في اجتيازه، لكن حدث أنه بسبب ظروف شخصية لم أتمكن من المشاركة في البرنامج نفسه. بعد هذه المشاكل المثيرة للاهتمام مثل اختبار 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 - "_". إذًا، كيف يمكنك التحقق من الحقل بحثًا عن تطابق ثلاثي 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.
يتم التحقق من خلال مقارنة الأرقام، ولكن اتضح أنك بحاجة إلى التحقق من الحقل بأكمله، وجميع المجموعات الثمانية، في كل مرة. بالطبع، هذا ليس كثيرًا، هذا ليس بحثًا عن أرقام أرمسترونج في النطاق من 0 إلى 1 مليار، ولا يوجد سوى عدد قليل من الحسابات هنا، لكنك لا تزال تريد شيئًا أكثر مثالية من التحقق من الحقل بأكمله. الفكرة الثانية التي طرأت على ذهني هي التحقق فقط من الخلية التي تم وضع علامة عليها في الحركة السابقة، حتى نتمكن من تحديد الفائز، لأننا سنعرف من قام بهذه الخطوة. وبالتالي، بدلاً من جميع المجموعات الثمانية، نحصل على 2 أو 3 أو 4 مجموعات فقط، اعتمادًا على الخلية، انظر الصورة: الآن نحن بحاجة إلى معرفة كيفية تحديد المجموعة التي يجب إطلاقها؟ هذا هو المكان الذي أدركت فيه أن استخدام مصفوفة ثنائية الأبعاد ليس أمرًا مريحًا للغاية. قررت النظر في خيارات أخرى. في البداية خطرت لي فكرة أن الحقل يمكن أن يبقى في رقم مكون من تسعة أرقام، مثلا نفس الحقل الذي عرضناه على الشاشة يمكن كتابته هكذا: 220012111، سأشرح بأصابعي ما هو هو... الكود هو نفسه، 1 - "X"، 2 - "O"، 0 - " "، مما يعني 220012111 = "OO__XOXXX"، أو إذا قمت بعد كل رقم ثالث بإدخال فاصل أسطر وإضافة مسافات لـ وضوح:
О О _
_ Х О
Х Х Х
هنا مرة أخرى، مناسب للتخزين، تم اختراع جهاز للعرض، ولكنه غير مناسب للمقارنة! الحل وجد عندما قمت بترقيم الخلايا من 1 إلى 9 ففكرت، لأنه في البرمجة يبدأ العد التنازلي من 0 وترقيمه كما في الصورة، ألم تلاحظوا أي خصوصيات؟ إذا نظرت إلى الصورة أعلاه، فسيصبح من الواضح أن الحلول التي تحتوي على مجموعتين لها رقم تسلسلي فردي، و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