// Stwórz klasę reprezentującą robota. Powinien on przyjmować w konstruktorze swoje ID, // imię, atak oraz obronę. // Jeżeli w konstruktorze podano atak lub obronę mniejszą niż 1 lub większą niż 10 //to wyrzuć błąd (throw new Error("Złe statystyki!")). // Dodatkowo każdy robot powinien posiadać pole prywatne level, które na początku wynosi 1. // Wszystkie pola powinny być prywatne. ID powinno być tylko do odczytu. Do każdego pola //zastosuj tam gdzie pasują settery i gettery (możesz zmienić nazwy pól na takie z podkreślnikami, żeby nie było konfliktów nazw). // Robot powinien mieć dodatkowo metodę levelUp(), która zwiększa losowo jego obronę lub // atak o 1. Dodatkowo zwiększa to level o 1. // Następnie stwórz metodę fight(anotherRobot), która przyjmuje jako argument innego robota. // Sprawdź kto wygrał walkę, według wzoru: hitpoints = atakAtakujacego - obronaAtakowanego. // Wygrywa ten robot, który zadał więcej hitpoints. Jeżeli równo, to walka kończy się remisem. // Jeżeli nie było remisu, wykonaj na wygranym metodę .levelUp(). // Wypisz w konsoli jaki był wynik. Zwróć ID zwycięzcy lub null w przypadku remisu. // Jeżeli chcesz i Cię to ciekawi to stwórz funkcję genRobot(), która wygeneruje nowego // robota, z losowymi statystykami w zakresie 1-10, dowolnym ID i losowym imieniem. //Imię możesz wylosować za pomocą: function randRoboName(){ const roboNameParts = ['robo', 'mech', 'zord', 'mega', 'tron', 'zulu', 'johnny5', 'x-512', 'bot', 'auto', 'prime', 'ultra', 'war', 'supreme', 'master', 'alpha', 'beta']; const roboNameJoins = [' ', '-', '', '.']; const partsCount = ~~(Math.random()*4+1); let name = ''; for(let i = 0; i < partsCount; i++){ const joiner = i === (partsCount-1) ? '' : roboNameJoins[~~(Math.random()*roboNameJoins.length)]; name += roboNameParts[~~(Math.random()*roboNameParts.length)] + joiner; } return name.substr(0, 1).toUpperCase() + name.substr(1); } //Teraz stwórz arenę: wygeneruj 10 botów, następnie wykonaj walkę każdego z każdym. //Spróbuj wymyślić taki sposób, żeby walka była uczciwa, tzn. aby każdy robot zaczynał //walkę z innym robotem, który też jeszcze nie walczył itp. i wypisz w konsoli obiekt //zwycięzkiego robota. Wygrywa ten robot, który ma największy level. class Robot{ private _level: number = 1; //Dodatkowe pola dzięki którym będzie można ocenić ile walk przebył robot private _numberOfGames: number = 0; //oraz z kim już walczył public foughtWithIds : number[] = []; constructor(private readonly _id : number, private _name : string, private _attack : number, private _defense : number){ if (_defense < 1 || _defense > 10 || _attack < 1 || _attack > 10){ throw new Error("Złe statystyki!"); } } get id(){ return this._id; } get name(){ return this._name; } get attack(){ return this._attack; } get defense(){ return this._defense; } get level(){ return this._level; } get numberOfGames(){ return this._numberOfGames; } set numberOfGames(newNumber){ this._numberOfGames = newNumber; } levelUp() : void{ this._level++; const roll = Math.random() < 0.5; if (roll){ this._attack++; } else { this._defense++; } } } //Mini funkcja assert, dzięki której sprawdzimy czy walki są uczciwe function assert(toBeTrue, msg) { if (!toBeTrue) throw new Error(msg); } //Walka jest dosyć prosta i podąża za instrukcją - sprawdzamy który robot zadał więcej hitpoints function fight(firstRobot: Robot, anotherRobot: Robot): number | null{ assert(Math.abs(firstRobot.numberOfGames - anotherRobot.numberOfGames) <= 1, 'Robots don\'t have the same chances!'); //Bardzo ważne jest zapisywanie w jakiejś formie z kim walczył robot i ile razy (do tego drugiego wystarczy oczywiście tablica.length, ale dla czytelności dodałem osobną zmienną) firstRobot.numberOfGames++; anotherRobot.numberOfGames++; firstRobot.foughtWithIds.push(anotherRobot.id); anotherRobot.foughtWithIds.push(firstRobot.id); const hitpointsMe = firstRobot.attack - anotherRobot.defense; const hitpointsAnother = anotherRobot.attack - firstRobot.defense; if (hitpointsAnother === hitpointsMe){ console.log('Remis'); return null; } else { const winner : Robot = hitpointsAnother > hitpointsMe ? anotherRobot : firstRobot; winner.levelUp(); console.log('Wygrał robot', winner.name, 'o ID', winner.id); return winner.id; } } //Przechowujemy ID aktualnego robota let currId : number = 1; //Funkcja losująca robota function genRobot() : Robot{ const name = randRoboName(); const id = currId++; const attack = ~~(Math.random()*9+1); const defense = ~~(Math.random()*9+1); return new Robot(id, name, attack, defense); } //Tworzymy ich 10 let robots : Robot[] = []; for(let i = 0; i < 10; i++){ robots.push(genRobot()); } //Poniżej algorytm walki //Tak na prawdę system walki musi spełniać następujące założenia: // * Jeżeli to możliwe to powinny ze sobą walczyć takie roboty, które odbyły tyle samo walk // * Każdy robot powinien walczyć z każdym innym // * Dwa roboty nie powinny walczyć ze sobą dwukrotnie // * Robot nie może walczyć ze sobą // * Na koniec każdy robot powinien mieć taką samą liczbę odbytych walk //Funkcja pomicnicza potrzebna do waruacji bez powtórzeń function factor(n : number) : number { if ((n == 0) || (n == 1)) return 1 else { var result = (n * factor(n-1) ); return result } } //Liczba walk jakie muszą się odbyć jest równa wariacji bez powtórzeń podzielonej przez dwa (bo interesuje nas walka A-B, ale B-A już nie) function numOfFights(numOfRobots : number) : number{ return factor(numOfRobots)/factor(numOfRobots-2) / 2; //Wariacja bez powtórzeń, podzielona przez dwa, ponieważ 2 roboty nie muszą się bić ze sobą 2 razy po 2 różnych stronach } //Najważniejsza część: znajdowanie walki, która spełni powyższe założenia: function oneEqualGame(robots: Robot[]) { //Sortujemy tak, żeby najpierw walczyły roboty które najmniej walczyły robots.sort((robotA, robotB) => robotA.numberOfGames - robotB.numberOfGames); //Będzie walczył pierwszy. Szukamy innego robota, z którym jeszcze pierwszy robot nie walczył i który ma też jak najmniej walk const robotToFightWith : Robot = robots.find(robot => robot.id !== robots[0].id && robot.foughtWithIds.indexOf(robots[0].id) === -1); //Kiedy już go znajdziemy uruchamiamy walkę fight(robots[0], robotToFightWith); } //Liczymy ile ma być walk const totalNumberOfFights = numOfFights(robots.length); console.log('Zostanie rozegranych', totalNumberOfFights, 'meczy'); //Tyle też "równych walk" przeprowadzamy for(let i = 0; i < totalNumberOfFights; i++){ oneEqualGame(robots); } //Na koniec szukamy zwycięzcy - miał być to robot z najwyższym levelem robots.sort((robotA, robotB) => robotB.level - robotA.level); //Jeżeli chcesz - możesz pomyśleć jak wybrać wszystkie z najwyższym levelem - jeżeli będzie kilka ex aequo console.log('Zwycięzcą został robot', robots[0]);