$29
• Objectives
In this assignment you will practice the Abstraction, Inheritance and Polymorphism concepts of Object Oriented Programming.
Keywords: OOP, inheritance, polymorphism, (pure) abstract class
• Problem De nition
TL;DR: Implement Player and its inherited classes(Berserk, Tracer, Ambusher, Paci st, Dummy), GameParser, Board, and GameEngine.
Ahh... Another homework, another challenge.. Let’s see, is there any way to create a fun homework?
....
Found 1 result(s): Fortnite + King of the Hill challenge. Ooh, Fortnite on Terminal, and KOTH? I’m interested!
Let’s change its name, I don’t want to deal with another lawsuit. CengNite? Sounds cool.
Playing Fortnite 7/24... Here’s a mini spoiler:
Pausing Fortnite for a while...
Creating new Player classes...
Pouring concrete on the abstract class... (Get it?)
Overriding already implemented methods... (Why though?)
Inheriting $5M from Nigerian prince...
Buying new Fortnite skins...
Still brawling with C++ Memory Manager... (I missed Swift...)
Preparing test cases...
Ready.
As an aspiring Computer Engineering student, your next task -if you accept- is to create a Fortnite Simulation. So, you’re going to parse an input le, implement a -pure- abstract class, also few concrete classes, and the algorithms. Basically, it’s going to be a Fortnite with a King of the Hill extension, on Terminal.
1
• Speci cations
3.1 Player
The courageous challengers. It’s uniquely identi ed by playerID.
Its attributes are HP, coordinate, weapon (damage) and armor (damage reduction).
Players will act according to their Priority List. While taking turns, Players will take turn according to priority. Lower ID == More priority.
c l a s s Player f
p r o t e c t e d :
c o n s t uint id ;
Coordinate coordinate ;
i n t HP ;
• DO NOT MODIFY THE UPPER PART
• ADD OWN PROTECTED METHODS/PROPERTIES BELOW
p u b l i c : /
Main C o n s t r u c t o r .
@param
i d
The ID o f t h e
p l a y e r . [0 100) .
@param
x
X
c o o r d i n a t e
o f
t h e
p l a y e r .
@param
y
Y
c o o r d i n a t e
o f
t h e
p l a y e r .
/
Player(uint id , i n t x , i n t y) ;
v i r t u a l ~Player ( ) ;
uint getID ( ) c o n s t ;
c o n s t Coordinate& getCoord ( ) c o n s t ;
i n t getHP ( ) c o n s t ;
•
Board ID i s two d e c i m a l ID f o r t h e P l a y e r .
P l a y e r ID = 0 , 91
Board ID = " 0 0 " , "91"
@return BoardID o f t h e u s e r .
/
std : : string getBoardID ( ) c o n s t ;
v i r t u a l
Armor getArmor ( ) c o n s t
=
0 ;
v i r t u a l
Weapon getWeapon ( ) c o n s t
= 0 ;
/
Every p l a y e r has a d i f f e r e n t
p r i o r i t y
move l i s t .
I t ’ s e x p l a i n e d i n t h e P l a y e r s ’ h e a d e r .
@return The move p r i o r i t y
l i s t
f o r t h e
p l a y e r .
/
std : : vector<Move> getPriorityList ( ) c o n s t = 0 ;
v i r t u a l
/
Get
t h e f u l l name o f t h e
p l a y e r .
2
Example ( T r ac e r with ID 9 2 ) = " T r ac e r9 2 "
Example ( T r ac e r with ID 1 ) = " T r ac e r0 1 "
@return F u l l name o f t h e p l a y e r .
/
v i r t u a l c o n s t std : : string getFullName ( ) c o n s t = 0 ;
•
Decide whether t h e p l a y e r i s dead .
@return t r u e i f t h e p l a y e r ’ s hp <= 0 , f a l s e o t h e r w i s e .
/
b o o l isDead ( ) c o n s t ;
•
Execute t h e g i v e n move f o r t h e p l a y e r ’ s c o o r d i n a t e s .
Important n o t e : P r i o r i t y l i s t d o e s NOT matter h e r e .
NOOP and ATTACK a r e no op .
Do not f o r g e t t o p r i n t t h e move .
" playerFullName ( playerHP ) moved UP/DOWN/LEFT/RIGHT. "
" Tr ac e r0 0 ( 1 0 0 ) moved UP. "
@param move Move t o make .
/
v o i d executeMove(Move move) ;
•
Attack t h e g i v e n
p l a y e r ,
and
d e c i d e whether
t h e a t t a c k e d
p l a y e r i s dead .
Important
n o t e :
P r i o r i t y
l i s t
d o e s
NOT matter h e r e .
Formulae
: RHS ’ s
HP = max( (LHS ’ s
damage
RHS ’ s armor ) ,
0 )
Do not f o r g e t t o
p r i n t t h e a t t a c k .
" lhsFullName ( lhsHP ) ATTACKED rhsFullName ( rhsHP ) ! ( damageDone )
" Tr ac e r0 0 ( 1 0 0 ) ATTACKED Tr a ce r0 1 ( 1 0 0 ) ! ( 5)"
@param p l a y e r P l a y e r t o be a t t a c k e d .
@return t r u e i f a t t a c k e d p l a y e r i s dead , f a l s e o t h e r w i s e .
/
b o o l attackTo(Player player) ;
•
Return
d i f f e r e n t
c o l o r s
f o r d i f f e r e n t
P l a y e r
c l a s s e s
( o v e r r i d e ! ) .
Note :
This
method
i s o p t i o n a l . You
may
l e a v e
t h i s
as
i s .
@return The
a s s o c i a t e d
c o l o r code
with
t h e c l a s s .
/
v i r t u a l Color : : Code getColorID ( ) c o n s t f r e t u r n Color : : FG_DEFAULT ; g
• DO NOT MODIFY THE UPPER PART
• ADD OWN PUBLIC METHODS/PROPERTIES BELOW
• ;
3
There will be 5 di erent types of Players:
fBerserk, Tracer, Ambusher, Pacifist, Dummyg
3.1.1 Berserk:
Now Playing: Eminem - Not Afraid... (Wait, why not Berzerk?)
Berserk is not afraid to kill, not afraid to die. A necessity for every CengNite round.
HP = 100, Weapon = PISTOL, Armor = WOODEN
PriorityList = fATK / UP / LEFT / DOWN / RIGHTg.
Name = Berserk, ColorID = FG RED.
3.1.2 Tracer
Now Playing: Iron Maiden - Run To The Hills...
Tracer will run to the hill rst. If there are obstacles, blood will be shed..
HP = 100, Weapon = SHOVEL, Armor = BRICK
PriorityList = fUP / LEFT / DOWN / RIGHT / ATKg.
Name = Tracer, ColorID = FG YELLOW.
3.1.3 Ambusher
Now Playing: Sepultura - Ambush...
Ambusher doesn’t care about the *** hill at all. So join them and make every other player leave this land!
HP = 100, Weapon = SEMIAUTO, Armor = NOARMOR
PriorityList = fATKg.
Name = Ambusher, ColorID = FG BLUE.
3.1.4 Paci st
Now Playing: John Lennon - Imagine...
Paci st believes that there is nothing to kill or die for. Well, this is CengNite, everything is real here!
Especially the STORM. Run Paci st, Run!
HP = 100, Weapon = NOWEAPON, Armor = METAL
PriorityList = fUP / LEFT / DOWN / RIGHTg.
Name = Pacifist, ColorID = FG GREEN.
4
3.1.5 Dummy
Now Playing: Toby Fox - Dummy...
... (Dummy cannot speak! It cannot attack, it cannot defend, what the *** is he doing in here?)
... (Wait, what? 1000 HP? You must be kidding.)
... (Can he start on the hill? Gosh...)
HP = 1000, Weapon = NOWEAPON, Armor = NOARMOR
PriorityList = fNOOPg.
Name = Dummy, ColorID = FG DEFAULT.
3.2 GameParser
GameParser is responsible for parsing the given input le, and creating Players accordingly.
c l a s s GameParser f
p u b l i c :
•
Parse t h e
f i l e
with
g i v e n
name and
c r e a t e p l a y e r s
a c c o r d i n g l y .
GameParser DOES NOT
have
any r e s p o n s i b i l i t y
o v e r
t h e s e P l a y e r s .
Note : The
f i l e
w i l l
always
e x i s t s ,
and
t h e r e
w i l l
be
no e r r o n e o u s i n p u t .
@param f i l e n a m e The
name
o f t h e
f i l e t o
be p a r s e d .
@return
p a i r . f i r s t :
Board
s i z e .
p a i r . s e co n d : The
v e c t o r
o f
t h e
c o n s t r u c t e d
p l a y e r s .
/
s t a t i c std : : pair<i n t , std : : vector<Player > > parseFileWithName( c o n s t std : : - string& filename) ;
• ;
This part is left blank intentionally.
Well, not really, I couldn’t t anything here.
Here are some lyrics for you:
Never gonna give you up
Never gonna let you down
Never gonna run around and desert you
Never gonna make you cry
Never gonna say goodbye
Never gonna tell a lie and hurt you
5
3.3 Board
Board class is the backbone of any CengNite games. It’s responsible for Coordinates, the Players’ visibility areas, creating the hill and the STORM, and such. The Board will get angry when a Player tries to go out of bounds, or on top of another Player. Don’t do that.
c l a s s Board f
p r i v a t e :
c o n s t uint boardSize ;
std : : vector<Player > players ;
• DO NOT MODIFY THE UPPER PART
• ADD OWN PRIVATE METHODS/PROPERTIES BELOW
p u b l i c :
Board(uint boardSize , std : : vector<Player > players) ; ~Board ( ) ;
uint getSize ( ) c o n s t ;
•
Decide
whether
t h e c o o r d i n a t e i s i n
t h e board l i m i t s .
@param
c o o r d
C o o r d i n a t e
t o s e a r c h .
@return
t r u e
i f
c o o r d i s
i n l i m i t s ,
f a l s e o t h e r w i s e .
/
b o o l isCoordInBoard( c o n s t Coordinate& coord) c o n s t ;
•
Decide
whether
t h e g i v e n
c o o r d i n a t e i s
i n storm .
@param c o o r d
C o o r d i n a t e
t o
s e a r c h .
@return
t r u e
i f
c o v e r e d
i n
storm , f a l s e
o t h e r w i s e .
/
b o o l isStormInCoord( c o n s t Coordinate &coord) c o n s t ;
•
Decide
whether
t h e g i v e n
c o o r d i n a t e
i s t h e h i l l .
@param
c o o r d
C o o r d i n a t e
t o
s e a r c h .
@return
t r u e
i f
t h e c o o r d
i s a t t h e
v e r y c e n t e r o f t h e board , f a l s e -
o t h e r w i s e .
/
b o o l isCoordHill( c o n s t Coordinate& coord) c o n s t ;
•
I n d e x i n g .
Find t h e p l a y e r i n
c o o r d i n a t e .
n u l l p t r
i f
p l a y e r
d o e s not e x i s t s i n g i v e n c o o r d i n a t e s , o r ! isCoordInBoard
@param
c o o r d The
c o o r d i n a t e t o s e a r c h .
@return
The
p l a y e r
i n c o o r d i n a t e .
/
Player o p e r a t o r [ ] ( c o n s t Coordinate& coord) c o n s t ;
•
C a l c u l a t e t h e new c o o r d i n a t e with t h e g i v e n move and c o o r d i n a t e .
NOOP and ATTACK a r e no op , r e t u r n c o o r d .
The new c o o r d i n a t e cannot be o u t s i d e o f t h e b o r d e r s .
6
I f i t ’ s t h e c a s e , r e t u r n c o o r d .
Also , i f t h e r e ’ s a n o t h e r p l a y e r i n t h e new c o o r d i n a t e , r e t u r n c o o r d .
@param move Move t o be made .
@param c o o r d The c o o r d i n a t e t o be moved .
@return C a l c u l a t e d c o o r d i n a t e a f t e r t h e move .
/
Coordinate calculateCoordWithMove(Move move , c o n s t Coordinate &coord) c o n s t ;
•
Find t h e v i s i b l e
c o o r d i n a t e s from
g i v e n c o o r d i n a t e .
E x p l a n a t i o n : The
immediate UP/DOWN/LEFT/RIGHT t i l e s must
be c a l c u l a t e d .
There c o u l d
be max o f 4
t i l e s ,
and
min
o f
2
t i l e s
( on c o r n e r s ) .
Every found
c o o r d i n a t e
must
be
i n
t h e
board
l i m i t s .
I f t h e
g i v e n
c o o r d i n a t e
i s
not
i n
board ,
r e t u r n a
v e c t o r
with s i z e = 0 . -
Order
d o e s NOT matter .
Example :
01
02HH
v i s i b l e C o o r d s F r o m C o o r d ( C o o r d i n a t e ( 0 , 0 ) ) == f ( 1 , 0 ) , ( 0 , 1 ) g
v i s i b l e C o o r d s F r o m C o o r d ( C o o r d i n a t e ( 1 , 1 ) ) == f ( 1 , 0 ) , ( 2 , 1 ) , ( 1 , 2 ) , ( 0 , - 1 ) g
v i s i b l e C o o r d s F r o m C o o r d ( C o o r d i n a t e ( 1 , 0 ) ) == f g
@param c o o r d The c o o r d i n a t e t o s e a r c h .
@return A l l c o o r d i n a t e s v i s i b l e .
/
std : : vector<Coordinate> visibleCoordsFromCoord( c o n s t Coordinate &coord) c o n s t -
;
•
C a l c u l a t e t h e storm a c c o r d i n g t o t h e currentRound .
@param currentRound The c u r r e n t round b e i n g p l a y e d .
/
v o i d updateStorm(uint currentRound) ;
• DO NOT MODIFY THE UPPER PART
• ADD OWN PUBLIC METHODS/PROPERTIES BELOW
• ;
7
3.4 GameEngine
c l a s s GameEngine f
p r i v a t e :
uint currentRound ;
Board board ;
• DO NOT MODIFY THE UPPER PART
• ADD OWN PRIVATE METHODS/PROPERTIES BELOW
p u b l i c :
•
C o n s t r u c t o r .
GameEngine "owns" t h e s e
p l a y e r s .
GameEngine a l s o
"owns"
t h e
v e c t o r ,
t o o .
@param b o a r d S i z e
The s i d e
l e n g t h o f
t h e board .
@param p l a y e r s A l l p l a y e r s
t o p a r t i c i p a t e i n t h e game .
/
GameEngine(uint boardSize , std : : vector<Player > players) ; ~GameEngine ( ) ;
c o n s t Board& getBoard ( ) c o n s t ;
•
I n d e x i n g .
Find t h e p l a y e r with g i v e n ID .
n u l l p t r i f not e x i s t s .
@param i d ID o f t h e p l a y e r .
@return The p l a y e r with g i v e n ID .
/
Player o p e r a t o r [ ] ( uint id) c o n s t ;
•
Decide whether t h e game i s f i n i s h e d .
@return t r u e i f t h e r e i s o n l y 1 p l a y e r ( a l i v e ) , on top o f t h e h i l l ; o r -
t h e r e a r e 0 p l a y e r s . F a l s e o t h e r w i s e .
/
b o o l isFinished ( ) c o n s t ;
•
Take t u r n f o r e v e r y p l a y e r .
How t o :
Announce t u r n s t a r t ( c o u t ) .
Example :START ROUND 1
board . updateStorm ( currentRound )
For e v e r y p l a y e r ( s o r t e d a c c o r d i n g t o t h e i r IDs ) t h a t i s n ’ t dead (HP <= -
0 ) :
takeTurnForPlayer ( p l a y e r ) . Announce t u r n end ( c o u t ) .
Example :END ROUND 1
/
v o i d takeTurn ( ) ;
•
The most im p o r t an t ( a l g o r i t h m w i s e ) method .
8
How t o :
Get
p l a y e r with ID . Return NOOP
i f
not
e x i s t s .
Get
p l a y e r ’ s
p r i o r i t y
l i s t .
Get
p l a y e r ’ s
v i s i b i l i t y
from
t h e
board
( v i s i b l e C o o r d s F r o m C o o r d ) .
I f
t h e p l a y e r
i s
i n t h e
storm
( isStormInCoord ) ,
announce t h e damage and
-
g i v e
p l a y e r stormDamage .
Example : Tr a ce r 01 ( 1 0 )
i s
STORMED! (
10)
I f dead , announce
t h e
death ,
remove
p l a y e r from
t h e board/ l i s t /anywhere ,
-
and r e t u r n NOOP.
Example : Tr a ce r 01 ( 0 ) DIED .
For
MOVE i n
p l a y e r ’ s
p r i o r i t y
l i s t :
I f
t h e MOVE
i s
NOOP:
r e t u r n NOOP.
E l s e
i f
t h e MOVE
i s ATTACK:
Get
a l l
p l a y e r s
t h a t
t h i s
p l a y e r can
a t t a c k
( board [ c o o r d ] -
f o r
each
i n v i s i b i l i t y C o o r d s ) .
I f
none ,
c o n t i n u e .
E l s e :
Pick
t h e
one
with
most p r i o r i t y
( l o w e s t
ID) .
i s P l a y e r D e a d
= p l a y e r . attackTo ( t h a t P l a y e r ) .
i f i s P l a y e r I s D e a d :
announce t h e death .
remove t h a t P l a y e r
from t h e
board/ l i s t /anywhere .
r e t u r n ATTACK.
E l s e
(UP/DOWN/LEFT/RIGHT) :
calculateCoordWithMove (move) .
I f
t h e
new
c o o r d i n a t e
i s
d i f f e r e n t
than t h e
p l a y e r ’ s ( -
meaning
i t ’ s
a b l e t o
do
t h a t move)
AND
t h e
p l a y e r
i s
g e t t i n g c l o s e r t o t h e
h i l l ;
p l a y e r . executeMove (MOVE) .
r e t u r n MOVE.
E l s e :
c o n t i n u e .
// I f t h e p r i o r i t y l i s t i s e x h a u s t e d ;
r e t u r n NOOP.
@param p l a y e r P l a y e r ID t o move .
@return move Decided move .
/
Move takeTurnForPlayer(uint playerID) ;
•
Find t h e winner p l a y e r .
n u l l p t r i f t h e r e a r e 0 p l a y e r s l e f t , o r t h e game i s n ’ t f i n i s h e d y e t .
@return The winner p l a y e r .
/
Player getWinnerPlayer ( ) c o n s t ;
• DO NOT MODIFY THE UPPER PART
• ADD OWN PUBLIC METHODS/PROPERTIES BELOW
• ;
9
• Class Diagram
• Input Format
The input will be in this format:
Board Size: <s>
Player Count: <n>
Player<0>ID::Player<0>Type::Player<0>xCoord::Player<0>yCoord
Player<1>ID::Player<1>Type::Player<1>xCoord::Player<1>yCoord
...
Player<n-1>ID::Player<n-1>Type::Player<n-1>xCoord::Player<n-1>yCoord
10
5.1 Input Example
• Board Size : 3
2 Player Count : 2
• 0 : : Tracer : : 2 : : 0
4 1 : : Berserk : : 2 : : 2
The starting for the given input:
00
HH
01
• Extras
6.1 Input
1. There will be no erroneous input.
2. Input generator is also shared with you. Every input le will be created by that generator.
3. Player count will be n > 0 && n < 100.
4. Board size will be n > 2; n < 28; n%2 == 1
6.2 Output Notes
1. The grades will be determined with black-box testing, hence you need to be careful about spaces, typos, etc.
2. Output Format is speci ed in the source code, and there will be plenty of I/O examples provided to you.
6.3 Helpers
There are Color.h, Entity.h, Coordinate.h, BoardPrinter.h les provided to you as-is, for your convenience. Do not forget to check these les before implementing!
6.4 Memory
GameParser and Board is NOT responsible for the Players at any time.
Only GameParser CAN create Players, and it MUST be GameEngine’s responsibility to remove/delete these Players.
A player must be removed (from Board, from GameEngine, from memory) if it’s dead, immediately. The winner (if there is) must be removed after GameEngine is deallocated.
• Grading
For your convenience, there are multiple partial tests already given to you in StudentPack. The rest of the points can be earned with proper memory management and proper outputs. The example I/O will be shared on COW, and a simple one is in StudentPack.
11
• Regulations
Programming Language: You must code your program in C++ (11). Your submission will be compiled with g++ with -std=c++11 ag on department lab machines.
Allowed Libraries: You may include and use C++ Standard Library. Use of any other library (especially the external libraries found on the internet) is forbidden.
Memory Management: When an instance of a class is destructed, the instance must free all of its owned/used heap memory. Class-wise memory management is explained to you in source-code. Any heap block, which is not freed at the end of the program will result in grade deduction. Please check your codes using valgrind {leak-check=full for memory-leaks.
Late Submission: You have a total of 10 days for late submission. You can spend this credit for any of the assignments or distribute it for all. For each assignment, you can use at most 3 days-late.
Cheating: In case of cheating, the university regulations will be applied.
Newsgroup: It’s your responsibility to follow the newsgroup (news.ceng.metu.edu.tr) for discus-sions and possible updates on a daily basis.
• Submission
Submission will be done via CengClass. Create a zip le named hw4.zip that contains:
Player.h Player.cpp
GameParser.h GameParser.cpp Board.h
Board.cpp
GameEngine.h GameEngine.cpp
fBerserk/Tracer/Ambusher/Paci st/Dummyg .h / .cpp
Do not submit a le that contains a main function. Such a le will be provided and your code will be compiled with it. Also, do not submit a Make le. In Make le, there’s a command "zipper" that will automatically zip the requested les. Caution: it requires lesToUpload.txt, do not delete that.
Note: The submitted zip le should not contain any directories! The following command sequence is expected to run your program on a Linux system:
• unzip hw4.zip
• make clean
• make all
• make run
• -optional- make valgrind
12
10 Addendum
10.1 Storm
So, how does the Storm work? There are 2 methods given to you for calculations, one is stormWidthForRound, and one is stormDamageForRound. They will calculate the storm damage and the width according to the currentRound given.
You may noticed that hill cannot be stormed, but the width can be much more than the board size itself. It’s intended, and the damage is also intended, so you must use these methods accordingly (hill should not be covered in storm in any case).
Here’s an image which shows how the storm is built up:
Hint: Don’t think too complex, if your calculations seems to have too many edge cases, there is most probably a better way to do that. Think about square(s).
13
10.2 Players, What NOT to do
You MUST NOT store any info regarding the type of the Player. You SHOULD NOT act according to the type of the Player (you may check the name of the player instead of storing a type, don’t do that.)
You SHOULD NOT have any code like:
Armor Player : : getArmor ( ) c o n s t f
i f ( t h i s >type == BERSERK) f
r e t u r n WOODEN
g
.
.
.
o r
i f ( t h i s >fullName ( ) contains BERSERK) f
r e t u r n WOODEN
g
.
.
.
g
Every class must implement/override necessary methods. There will be white-box tests which will check for this structures, and if you write such code on the upper part, your homework WILL NOT be graded at all.
Good luck, have fun.
- engin
14