JavaRush /Java blogi /Random-UZ /JavaRush-dagi "O'yinlar" bo'limi: Foydali nazariya

JavaRush-dagi "O'yinlar" bo'limi: Foydali nazariya

Guruhda nashr etilgan
JavaRush-ning "O'yinlar" bo'limida siz mashhur kompyuter o'yinlarini yozish uchun qiziqarli loyihalarni topasiz. Mashhur "2048", "Sapper", "Snake" va boshqa o'yinlarning o'z versiyasini yaratmoqchimisiz? Bu oddiy. Biz o'yin yozishni bosqichma-bosqich jarayonga aylantirdik. BobO'zingizni o'yin ishlab chiqaruvchisi sifatida sinab ko'rish uchun siz ilg'or dasturchi bo'lishingiz shart emas, ammo ma'lum bir Java bilimlari hali ham talab qilinadi. Bu erda siz o'yin yozishda foydali bo'ladigan ma'lumotlarni topasiz .

1. Meros

JavaRush o'yin mexanizmi bilan ishlash merosdan foydalanishni o'z ichiga oladi. Ammo bu nima ekanligini bilmasangiz nima bo'ladi? Bir tomondan, siz ushbu mavzuni tushunishingiz kerak: u 11-darajada o'rganiladi . Boshqa tomondan, vosita ataylab juda oddiy bo'lishi uchun yaratilgan, shuning uchun siz meros bo'yicha yuzaki bilimga ega bo'lishingiz mumkin. Xo'sh, meros nima? Oddiy qilib aytganda, meros ikki sinf o'rtasidagi munosabatdir. Ulardan biri ota-onaga, ikkinchisi esa bolaga (vorisi sinf) aylanadi. Bunday holda, ota-ona sinf o'zining avlod sinflari borligini bilmasligi ham mumkin. Bular. u merosxo'r sinflar mavjudligidan hech qanday alohida foyda olmaydi. Ammo meros avlod sinfiga ko'p afzalliklarni beradi. Va asosiysi, ota-sinfning barcha o'zgaruvchilari va usullari bolalar sinfida paydo bo'ladi, xuddi ota-sinfning kodi bolalar sinfiga ko'chirilgandek. Bu mutlaqo to'g'ri emas, lekin merosni soddalashtirilgan tushunish uchun bu yordam beradi. Merosni yaxshiroq tushunish uchun bir nechta misollar. 1-misol: eng oddiy meros.
public class Родитель {

}
Child klassi kengaytma kalit so'zidan foydalangan holda Parent sinfidan meros oladi .
public class Потомок extends Родитель {

}
2-misol: Asosiy sinf o'zgaruvchilaridan foydalanish.
public class Родитель {

   public int age;
   public String name;
}
Child klassi Parent klassining yoshi va nom o'zgaruvchilaridan xuddi unda e'lon qilingandek foydalanishi mumkin .
public class Потомок extends Родитель {

   public void printInfo() {

     System.out.println(name+" "+age);
   }
}
3-misol: Ota-onalar sinf usullaridan foydalanish.
public class Родитель {

   public int age;
   public String name;

   public getName() {
      return name;
   }
}
Child klassi Parent sinfining o'zgaruvchilari va usullaridan xuddi unda e'lon qilingandek foydalanishi mumkin. Ushbu misolda biz getName () usulidan foydalanamiz .
public class Потомок extends Родитель {

   public void printInfo() {

     System.out.println(getName()+" "+age);
   }
}
Descendant sinfi kompilyator nuqtai nazaridan shunday ko'rinadi:
public class Потомок extends Родитель {

   public int age; //  унаследованная переменная
   public String name; //  унаследованная переменная

   public getName() { //  унаследованный метод.
      return name;
  }
   public void printInfo() {

     System.out.println(getName()+" "+age);
   }
}

2. Usulni bekor qilish

Ba'zida shunday vaziyatlar bo'ladiki, biz o'z Descendant sinfimizni barcha o'zgaruvchilar va usullar bilan birga juda foydali Ota-sinfdan meros qilib oldik, lekin ba'zi usullar biz xohlagan tarzda ishlamaydi. Yoki umuman biz xohlamagan tarzda emas. Bunday vaziyatda nima qilish kerak? Biz yoqtirmaydigan usulni bekor qilishimiz mumkin. Bu juda sodda tarzda amalga oshiriladi: bizning Descendant sinfimizda biz oddiygina Ota-klass usuli bilan bir xil imzo (sarlavha) bilan usulni e'lon qilamiz va unga kodimizni yozamiz. 1-misol: Usulni bekor qilish.
public class Родитель {

   public String name;

   public void setName (String nameNew) {
       name = nameNew;
  }

   public getName() {
      return name;
  }
}
printInfo() usuli "Luka, Yo'q!!!" iborasini chop etadi.
public class Потомок extends Родитель {

   public void setName (String nameNew) {
       name = nameNew + ",No!!!";
  }

   public void printInfo() {

      setName("Luke");
      System.out.println( getName());
   }
}
Descendant sinfi kompilyator nuqtai nazaridan shunday ko'rinadi:
public Потомок extends Родитель {

   public String name; //  унаследованная переменная

   public void setName (String nameNew) { //  Переопределенный метод взамен унаследованного

       name = nameNew + ", No!!!";
   }
   public getName() { //  унаследованный метод.

      return name;
   }
   public void printInfo() {

     setName("Luke");
     System.out.println(getName());
   }
}
2-misol: merosning ozgina sehri (va usulni bekor qilish).
public class Родитель {

   public getName() {
      return "Luke";
  }
   public void printInfo() {

     System.out.println(getName());
   }
}
public class Потомок extends Родитель {

   public getName() {
      return "I'm your father, Luke";
  }
}
Bu misolda: agar usul printInfo(Ota-sinfdan) Descendant sinfida bekor qilinmasa, bu usul Descendant sinfining ob'ektida chaqirilganda, uning usuli Ota-klass getName()emas, balki .getName()
Родитель parent = new Родитель ();
parent.printnInfo();
Ushbu kod ekranda "Luqo" yozuvini ko'rsatadi .
Потомок child = new Потомок ();
child.printnInfo();
Bu kodda "Men sizning otangizman, Luqo" yozuvi aks etadi ; .
Descendant sinfi kompilyator nuqtai nazaridan shunday ko'rinadi:
public class Потомок extends Родитель {

   public getName() {
      return "I'm your father, Luke";
   }
   public void printInfo() {

     System.out.println(getName());
   }
}

3. Ro'yxatlar

Agar siz hali ro'yxatlar bilan tanishmagan bo'lsangiz, bu erda tezkor boshlang'ich. JavaRush kursining 6-7 darajalari haqida to'liq ma'lumotni topishingiz mumkin . Ro'yxatlar massivlar bilan juda ko'p umumiyliklarga ega:
  • ma'lum turdagi juda ko'p ma'lumotlarni saqlashi mumkin;
  • elementlarni ularning indeksi/raqami bo'yicha olish imkonini beradi;
  • element indekslari 0 dan boshlanadi.
Ro'yxatlarning afzalliklari: massivlardan farqli o'laroq, ro'yxatlar hajmini dinamik ravishda o'zgartirishi mumkin. Yaratilgandan so'ng darhol ro'yxat 0 o'lchamiga ega bo'ladi. Ro'yxatga elementlar qo'shganda uning hajmi kattalashadi. Ro'yxatni yaratishga misol:
ArrayList<String> myList = new ArrayList<String>(); // создание нового списка типа ArrayList
Burchak qavslaridagi qiymat ro'yxat saqlashi mumkin bo'lgan ma'lumotlar turidir. Ro'yxat bilan ishlashning ba'zi usullari:
Kod Kod nima qilishining qisqacha tavsifi
ArrayList<String> list = new ArrayList<String>(); Satrlarning yangi ro'yxatini yaratish
list.add("name"); Ro'yxatning oxiriga element qo'shing
list.add(0, "name"); Ro'yxatning boshiga element qo'shing
String name = list.get(5); Indeks bo'yicha elementni oling
list.set(5, "new name"); Elementni indeksi bo'yicha o'zgartiring
int count = list.size(); Ro'yxatdagi elementlar sonini oling
list.remove(4); Ro'yxatdagi elementni olib tashlang
Ushbu maqolalardan ro'yxatlar haqida ko'proq bilib olishingiz mumkin:
  1. ArrayList klassi
  2. Rasmlardagi ishchi ArrayList
  3. ArrayList dan elementni olib tashlash

4. Massivlar

Matritsa nima? Matritsa ma'lumotlar bilan to'ldirilishi mumkin bo'lgan to'rtburchaklar jadvaldan boshqa narsa emas. Boshqacha qilib aytganda, bu ikki o'lchovli massivdir. Siz bilganingizdek, Java-dagi massivlar ob'ektlardir. Standart bir o'lchovli massiv turi intquyidagicha ko'rinadi:
int [] array = {12, 32, 43, 54, 15, 36, 67, 28};
Keling, buni vizual tarzda tasavvur qilaylik:
0 1 2 3 4 5 6 7
12 32 43 54 15 36 67 28
Yuqori satr hujayra manzillarini ko'rsatadi. Ya'ni, 67 raqamini olish uchun siz 6 indeksli massiv elementiga kirishingiz kerak:
int number = array[6];
Bu erda hamma narsa juda oddiy. Ikki o'lchovli massiv - bu bir o'lchovli massivlar massivi. Agar bu haqda birinchi marta eshitayotgan bo'lsangiz, to'xtating va uni boshingizda tasavvur qiling. Ikki o'lchovli massiv quyidagicha ko'rinadi:
0 Bir o'lchovli massiv Bir o'lchovli massiv
1 Bir o'lchovli massiv
2 Bir o'lchovli massiv
3 Bir o'lchovli massiv
4 Bir o'lchovli massiv
5 Bir o'lchovli massiv
6 Bir o'lchovli massiv
7 Bir o'lchovli massiv
Kodda:
int [][] matrix = {
{65, 99, 87, 90, 156, 75, 98, 78}, {76, 15, 76, 91, 66, 90, 15, 77}, {65, 96, 17, 25, 36, 75, 54, 78}, {59, 45, 68, 14, 57, 1, 9, 63}, {81, 74, 47, 52, 42, 785, 56, 96}, {66, 74, 58, 16, 98, 140, 55, 77}, {120, 99, 13, 90, 78, 98, 14, 78}, {20, 18, 74, 91, 96, 104, 105, 77} }
0 0 1 2 3 4 5 6 7
65 99 87 90 156 75 98 78
1 0 1 2 3 4 5 6 7
76 15 76 91 66 90 15 77
2 0 1 2 3 4 5 6 7
65 96 17 25 36 75 54 78
3 0 1 2 3 4 5 6 7
59 45 68 14 57 1 9 63
4 0 1 2 3 4 5 6 7
81 74 47 52 42 785 56 96
5 0 1 2 3 4 5 6 7
66 74 58 16 98 140 55 77
6 0 1 2 3 4 5 6 7
120 99 13 90 78 98 14 78
7 0 1 2 3 4 5 6 7
20 18 74 91 96 104 105 77
47 qiymatini olish uchun siz [4][2] manzilidagi matritsa elementiga kirishingiz kerak.
int number = matrix[4][2];
E'tibor bergan bo'lsangiz, matritsa koordinatalari klassik to'rtburchaklar koordinata tizimidan (kartezian koordinata tizimi) farq qiladi. Matritsaga kirishda avval y ni, keyin esa x ni belgilaysiz , matematikada esa avval x(x, y) ni belgilash odatiy holdir. Siz o'zingizdan shunday deb so'rashingiz mumkin: "Nega tasavvuringizdagi matritsani teskari o'zgartirmaysiz va elementlarga odatdagi tarzda (x, y) orqali kira olmaysiz? Bu matritsaning mazmunini o'zgartirmaydi." Ha, hech narsa o'zgarmaydi. Ammo dasturlash dunyosida matritsalarga "avval y, keyin x" ko'rinishida murojaat qilish odatiy holdir. Buni tabiiy deb qabul qilish kerak. Endi matritsani dvigatelimizga (sinfga Game) proyeksiya qilish haqida gapiraylik. Ma'lumki, dvigatelda berilgan koordinatalarda o'yin maydonining hujayralarini o'zgartiradigan ko'plab usullar mavjud. Masalan, setCellValue(int x, int y, String value). U ma'lum bir katakchani koordinatalari (x, y) qiymatiga o'rnatadi value. Siz sezganingizdek, bu usul birinchi navbatda klassik koordinatalar tizimidagi kabi aynan x ni oladi. Dvigatelning qolgan usullari xuddi shunday ishlaydi. O'yinlarni ishlab chiqishda ko'pincha matritsaning holatini ekranda takrorlash kerak bo'ladi. Buni qanday qilish kerak? Birinchidan, tsiklda siz matritsaning barcha elementlarini takrorlashingiz kerak. Ikkinchidan, ularning har biri uchun INVERTED koordinatalari bilan ko'rsatish usulini chaqiring. Misol:
private void drawScene() {
    for (int i = 0; i < matrix.length; i++) {
        for (int j = 0; j < matrix[i].length; j++) {
            setCellValue(j, i, String.valueOf(matrix[i][j]));
        }
    }
}
Tabiiyki, inversiya ikki yo'nalishda ishlaydi. Siz (i, j) usuliga setCellValueo'tishingiz mumkin , lekin ayni paytda matritsadan [j][i] elementini olishingiz mumkin. Inversiya biroz qiyin bo'lib tuyulishi mumkin, ammo buni yodda tutish kerak. Va har doim, agar biron bir muammo yuzaga kelsa, qalam bilan qog'oz varag'ini olib, matritsani chizish va u bilan qanday jarayonlar sodir bo'layotganini takrorlash kerak.

5. Tasodifiy sonlar

Tasodifiy sonlar generatori bilan qanday ishlash kerak? Sinf Gameusulni belgilaydi getRandomNumber(int). Kaput ostida u java.util paketidagi sinfdan foydalanadi Random, ammo bu tasodifiy sonlar generatori bilan ishlash tamoyilini o'zgartirmaydi. Argument sifatida getRandomNumber(int)butun sonni oladi . Bu raqam generator qaytarishi mumkin bo'lgan yuqori chegara bo'ladi. Pastki chegara 0 ga teng. Muhim! Generator hech qachon yuqori chegara raqamini qaytarmaydi. Misol uchun, agar getRandomNumber(3)tasodifiy chaqirilsa, u 0, 1, 2 ni qaytarishi mumkin. Ko'rib turganingizdek, u 3 ni qaytara olmaydi. Jeneratordan foydalanish juda oddiy, ammo ko'p hollarda juda samarali. Ba'zi chegaralar ichida tasodifiy raqamni olishingiz kerak: Tasavvur qiling, sizga uch xonali raqam kerak (100..999). Ma'lumki, qaytarilgan minimal raqam 0. Demak, siz unga 100 qo'shishingiz kerak bo'ladi, lekin bu holda siz yuqori chegaradan oshib ketmaslik uchun ehtiyot bo'lishingiz kerak. Maksimal tasodifiy qiymat sifatida 999 ni olish uchun siz getRandomNumber(int)1000 argumentli usulni chaqirishingiz kerak. Ammo biz 100 ning keyingi qo'shilishi haqida eslaymiz: bu yuqori chegarani 100 ga tushirish kerakligini anglatadi. Ya'ni, kodni olish uchun kod. tasodifiy uch xonali raqam quyidagicha ko'rinadi:
int number = 100 + getRandomNumber(900);
Ammo bunday tartibni soddalashtirish uchun vosita getRandomNumber(int, int)birinchi argument sifatida qaytarish uchun minimal sonni oladigan usulni taqdim etadi. Ushbu usuldan foydalanib, oldingi misolni qayta yozish mumkin:
int number = getRandomNumber(100, 1000);
Tasodifiy raqamlar tasodifiy massiv elementini olish uchun ishlatilishi mumkin:
String [] names = {"Andrey", "Валентин", "Сергей"};
String randomName = names[getRandomNumber(names.length)]
Muayyan hodisalarni ma'lum bir ehtimollik bilan tetiklash. Insonning ertalab mumkin bo'lgan stsenariylarga ko'ra boshlanadi: Overslept - 50%; O'z vaqtida turish - 40%; Kutilganidan bir soat oldin turdi - 10%. Tasavvur qiling-a, siz ertalabki inson emulyatorini yozyapsiz. Hodisalarni ma'lum bir ehtimollik bilan boshlashingiz kerak. Buning uchun yana tasodifiy sonlar generatoridan foydalanish kerak. Amalga oshirish turli xil bo'lishi mumkin, ammo eng oddiyi quyidagi algoritmga amal qilishi kerak:
  1. biz raqamni yaratish kerak bo'lgan chegaralarni belgilaymiz;
  2. tasodifiy sonni yaratish;
  3. Olingan raqamni qayta ishlaymiz.
Shunday qilib, bu holda, chegara 10 bo'ladi. Keling, usulni chaqiramiz getRandomNumber(10)va u bizga nimani qaytarishi mumkinligini tahlil qilaylik. U 10 ta raqamni (0 dan 9 gacha) va bir xil ehtimollik bilan - 10% qaytarishi mumkin. Endi biz barcha mumkin bo'lgan natijalarni birlashtirishimiz va ularni mumkin bo'lgan voqealar bilan moslashtirishimiz kerak. Tasavvuringizga qarab kombinatsiyalar juda ko'p bo'lishi mumkin, lekin eng aniq tovushlar: "Agar tasodifiy raqam [0..4] ichida bo'lsa - "Uyqusiz" hodisasini chaqiring, agar raqam [5..8] ichida bo'lsa. ] - "O'z vaqtida uyg'onish" va agar raqam 9 bo'lsa, "Men kutilganidan bir soat oldin turdim". Hammasi juda oddiy: [0..4] ichida 5 ta raqam mavjud bo'lib, ularning har biri 10% ehtimollik bilan qaytishi mumkin, jami 50% bo'ladi; [5..8] ichida 4 ta raqam bor va 9 10% ehtimollik bilan paydo bo'ladigan yagona raqam. Kodda bu aqlli dizayn yanada sodda ko'rinadi:
int randomNumber = getRandomNumber(10);
if (randomNumber < 5) {
    System.out.println("Проспал ");
} else if (randomNumber < 9) {
    System.out.println("Встал вовремя ");
} else {
    System.out.println("Встал на час раньше положенного ");
}
Umuman olganda, tasodifiy raqamlardan foydalanishning ko'plab variantlari bo'lishi mumkin. Hammasi faqat sizning tasavvuringizga bog'liq. Ammo, agar siz qayta-qayta biron bir natija olishingiz kerak bo'lsa, ular eng samarali tarzda qo'llaniladi. Shunda bu natija avvalgisidan farq qiladi. Albatta, qandaydir ehtimol bilan. Ana xolos! Oʻyinlar boʻlimi haqida koʻproq maʼlumotga ega boʻlishni istasangiz, bu yerda yordam berishi mumkin boʻlgan foydali hujjatlar mavjud:
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION