From 777ac290876282112fda8fb4d53ab7724d6a99a2 Mon Sep 17 00:00:00 2001 From: sigonasr2 Date: Thu, 31 Aug 2023 20:33:12 -0500 Subject: [PATCH] Implemented memory swapper and memory guard abilities. --- olcCodeJam2023Entry/Image.h | 5 + olcCodeJam2023Entry/Unit.cpp | 105 +++++++++++++++++++-- olcCodeJam2023Entry/Unit.h | 53 +++++++++-- olcCodeJam2023Entry/VirusAttack.cpp | 38 +++++++- olcCodeJam2023Entry/assets/memoryguard.png | Bin 0 -> 2252 bytes olcCodeJam2023Entry/assets/platform.png | Bin 0 -> 1080 bytes olcCodeJam2023Entry/assets/refresher.png | Bin 0 -> 1095 bytes olcCodeJam2023Entry/assets/shieldIcon.png | Bin 0 -> 908 bytes olcCodeJam2023Entry/assets/turret.png | Bin 0 -> 1008 bytes 9 files changed, 183 insertions(+), 18 deletions(-) create mode 100644 olcCodeJam2023Entry/assets/memoryguard.png create mode 100644 olcCodeJam2023Entry/assets/platform.png create mode 100644 olcCodeJam2023Entry/assets/refresher.png create mode 100644 olcCodeJam2023Entry/assets/shieldIcon.png create mode 100644 olcCodeJam2023Entry/assets/turret.png diff --git a/olcCodeJam2023Entry/Image.h b/olcCodeJam2023Entry/Image.h index d79000e..88c5357 100644 --- a/olcCodeJam2023Entry/Image.h +++ b/olcCodeJam2023Entry/Image.h @@ -32,5 +32,10 @@ enum Image{ SPD_ICON, RESOURCE, MEMORY_COLLECTION_POINT_HIGHLIGHT, + MEMORY_GUARD, + REFRESHER, + TURRET, + PLATFORM, + GUARD_ICON, }; diff --git a/olcCodeJam2023Entry/Unit.cpp b/olcCodeJam2023Entry/Unit.cpp index 7dea115..0b94f40 100644 --- a/olcCodeJam2023Entry/Unit.cpp +++ b/olcCodeJam2023Entry/Unit.cpp @@ -10,7 +10,7 @@ std::string LeftShifter::unitName="Left Shifter"; std::string LeftShifter::unitDescription="Memory Shifts target memory 1 bit to the left."; std::vector LeftShifter::resourceCost={{RANGE,2},{ATKSPD,2},{MOVESPD,3},{PROCEDURE,1},{HEALTH,4}}; LeftShifter::LeftShifter(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) - :Unit(pge,UnitType::LeftShifter,LeftShifter::resourceCost,pos,12,*IMAGES[LEFT_SHIFTER],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,moveable){} + :Unit(pge,LeftShifter::resourceCost,pos,12,*IMAGES[LEFT_SHIFTER],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,moveable){} void LeftShifter::Attack(Unit&victim,std::vector>&otherUnits){ victim<<=1; @@ -20,7 +20,7 @@ std::string RightShifter::unitName="Right Shifter"; std::string RightShifter::unitDescription="Memory Shifts target memory 1 bit to the right."; std::vector RightShifter::resourceCost={{HEALTH,4},{RANGE,2},{ATKSPD,2},{MOVESPD,3},{PROCEDURE,1}}; RightShifter::RightShifter(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) - :Unit(pge,UnitType::RightShifter,RightShifter::resourceCost,pos,12,*IMAGES[RIGHT_SHIFTER],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,moveable){} + :Unit(pge,RightShifter::resourceCost,pos,12,*IMAGES[RIGHT_SHIFTER],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,moveable){} void RightShifter::Attack(Unit&victim,std::vector>&otherUnits){ victim>>=1; @@ -30,7 +30,7 @@ std::string BitRestorer::unitName="Bit Restorer"; std::string BitRestorer::unitDescription="Randomly restores 1 missing bit to a target."; std::vector BitRestorer::resourceCost={{PROCEDURE,6},{RANGE,1},{ATKSPD,1},{MOVESPD,1},{HEALTH,2}}; BitRestorer::BitRestorer(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) - :Unit(pge,UnitType::BitRestorer,BitRestorer::resourceCost,pos,12,*IMAGES[BIT_RESTORER],CONSTANT::HEALER_TARGET_COL,CONSTANT::HEALER_ATTACK_COL,friendly,moveable,true,false){} + :Unit(pge,BitRestorer::resourceCost,pos,12,*IMAGES[BIT_RESTORER],CONSTANT::HEALER_TARGET_COL,CONSTANT::HEALER_ATTACK_COL,friendly,moveable,true,false){} void BitRestorer::Attack(Unit&victim,std::vector>&otherUnits){ std::vectoremptyMemoryPositions; @@ -72,19 +72,43 @@ std::string MemorySwapper::unitName="Memory Swapper"; std::string MemorySwapper::unitDescription="Flips the orientation of all bits of a target around."; std::vector MemorySwapper::resourceCost={{RANGE,3},{ATKSPD,1},{HEALTH,3},{PROCEDURE,3},{MOVESPD,2}}; MemorySwapper::MemorySwapper(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) - :Unit(pge,UnitType::MemorySwapper,MemorySwapper::resourceCost,pos,12,*IMAGES[MEMORY_SWAPPER],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,moveable,true){ + :Unit(pge,MemorySwapper::resourceCost,pos,12,*IMAGES[MEMORY_SWAPPER],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,moveable,true){ autoAcquireFriendlyTarget=false; } void MemorySwapper::Attack(Unit&victim,std::vector>&otherUnits){ - + std::vectoroldMemory=victim.memory; + for(int i=0;iorder; + for(int i=0;i<5;i++){ + int lowestInd=999999; + Marker*lowest; + if(victim.health.indexindex;} + if(victim.range.indexindex;} + if(victim.atkSpd.indexindex;} + if(victim.moveSpd.indexindex;} + if(victim.procedure.indexindex;} + + order.push_back(lowest); + lowest->index=9999999; + } + std::reverse(order.begin(),order.end()); + int i=0; + int marker=0; + while(markerindex=marker; + marker+=order[i]->size; + i++; + } } std::string Corrupter::unitName="Corrupter"; std::string Corrupter::unitDescription="Chooses a random bit and negates it on a target."; std::vector Corrupter::resourceCost={{ATKSPD,3},{RANGE,1},{PROCEDURE,8},{MOVESPD,4},{HEALTH,4}}; Corrupter::Corrupter(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) - :Unit(pge,UnitType::Corrupter,Corrupter::resourceCost,pos,12,*IMAGES[CORRUPTER],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,moveable){} + :Unit(pge,Corrupter::resourceCost,pos,12,*IMAGES[CORRUPTER],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,moveable){} void Corrupter::Attack(Unit&victim,std::vector>&otherUnits){ //Chooses a bit at random and corrupts it. @@ -96,7 +120,7 @@ std::string MemoryAllocator::unitName="Memory Allocator"; std::string MemoryAllocator::unitDescription="A unit that builds other units."; std::vector MemoryAllocator::resourceCost={{RANGE,1},{ATKSPD,1},{MOVESPD,1},{PROCEDURE,1},{HEALTH,1}}; MemoryAllocator::MemoryAllocator(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) - :Unit(pge,UnitType::MemoryAllocator,MemoryAllocator::resourceCost,pos,12,*IMAGES[UNIT_ALLOCATOR],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,true,false){ + :Unit(pge,MemoryAllocator::resourceCost,pos,12,*IMAGES[UNIT_ALLOCATOR],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,true,false){ isAllocator=true; } @@ -141,7 +165,7 @@ std::string RAMBank::unitName="RAM Bank"; std::string RAMBank::unitDescription="Allows for the construction of Memory Allocators."; std::vector RAMBank::resourceCost={{RANGE,0},{ATKSPD,0},{MOVESPD,0},{PROCEDURE,25},{HEALTH,16}}; RAMBank::RAMBank(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly) - :Unit(pge,UnitType::RAMBank,RAMBank::resourceCost,pos,41,*IMAGES[RAM_BANK],WHITE,WHITE,friendly,false + :Unit(pge,RAMBank::resourceCost,pos,41,*IMAGES[RAM_BANK],WHITE,WHITE,friendly,false ,false,false ),randomOffset({util::random(128),util::random(128)}),matrixImg(*IMAGES[MATRIX]), originalImg(*IMAGES[RAM_BANK]){ @@ -250,8 +274,56 @@ bool RAMBank::ClickHandled(TileTransformedView&game,Resources&player_resources,s return false; } -Unit::Unit(PixelGameEngine*pge,UnitType type,std::vectormemory,vf2d pos,float radius,Renderable&img,Pixel targetLineColor,Pixel attackingLineColor,bool friendly,bool moveable,bool friendlyInteractable,bool enemyInteractable) -:pos(pos),type(type),radius(radius),ghostPos(pos),img(img),targetLineCol(targetLineColor),attackingLineCol(attackingLineColor),friendly(friendly),moveable(moveable),friendlyInteractable(friendlyInteractable),enemyInteractable(enemyInteractable){ +std::string _Platform::unitName="Corrupter"; +std::string _Platform::unitDescription="Chooses a random bit and negates it on a target."; +std::vector _Platform::resourceCost={{ATKSPD,3},{RANGE,1},{PROCEDURE,8},{MOVESPD,4},{HEALTH,4}}; +_Platform::_Platform(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) + :Unit(pge,_Platform::resourceCost,pos,24,*IMAGES[PLATFORM],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,moveable){} + +void _Platform::Attack(Unit&victim,std::vector>&otherUnits){}; + +std::string Refresher::unitName="Refresher"; +std::string Refresher::unitDescription="Repairs missing bits for all surrounding units."; +std::vector Refresher::resourceCost={{ATKSPD,3},{RANGE,1},{PROCEDURE,8},{MOVESPD,4},{HEALTH,4}}; +Refresher::Refresher(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) + :Unit(pge,Refresher::resourceCost,pos,24,*IMAGES[REFRESHER],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,moveable){} + +void Refresher::Attack(Unit&victim,std::vector>&otherUnits){ + //Chooses a bit at random and corrupts it. + int randomBit=rand()%victim.memory.size(); + victim.memory[randomBit]=victim.ghostMemory[randomBit]=false; +} + +std::string Turret::unitName="Turret"; +std::string Turret::unitDescription="Automatically targets attack and movement speed memory ranges before others."; +std::vector Turret::resourceCost={{ATKSPD,4},{RANGE,5},{HEALTH,6},{PROCEDURE,16}}; +Turret::Turret(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) + :Unit(pge,Turret::resourceCost,pos,24,*IMAGES[TURRET],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,moveable){} + +void Turret::Attack(Unit&victim,std::vector>&otherUnits){ + //Chooses a bit at random and corrupts it. + int randomBit=rand()%victim.memory.size(); + victim.memory[randomBit]=victim.ghostMemory[randomBit]=false; +} + +std::string MemoryGuard::unitName="Memory Guard"; +std::string MemoryGuard::unitDescription="Reduces the chance of bit modification for all surrounding units by 30%"; +std::vector MemoryGuard::resourceCost={{HEALTH,10},{ATKSPD,4},{RANGE,4},{PROCEDURE,12}}; +MemoryGuard::MemoryGuard(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly,bool moveable) + :Unit(pge,MemoryGuard::resourceCost,pos,24,*IMAGES[MEMORY_GUARD],CONSTANT::ATTACKER_TARGET_COL,CONSTANT::ATTACKER_ATTACK_COL,friendly,false + ,true,false){} + +void MemoryGuard::Attack(Unit&victim,std::vector>&otherUnits){ + target.reset(); //Doesn't acquire a target. + for(auto&u:otherUnits){ + if(IsFriendly()==u->IsFriendly()&&InRange(u.get())){ + u->SetGuardTime(3); + } + } +} + +Unit::Unit(PixelGameEngine*pge,std::vectormemory,vf2d pos,float radius,Renderable&img,Pixel targetLineColor,Pixel attackingLineColor,bool friendly,bool moveable,bool friendlyInteractable,bool enemyInteractable) +:pos(pos),radius(radius),ghostPos(pos),img(img),targetLineCol(targetLineColor),attackingLineCol(attackingLineColor),friendly(friendly),moveable(moveable),friendlyInteractable(friendlyInteractable),enemyInteractable(enemyInteractable){ int marker=0; for(Memory&mem:memory){ for(int i=0;i>&SO } reloadTimer=std::max(0.f,reloadTimer-pge->GetElapsedTime()); + guardTime=std::max(0.f,guardTime-pge->GetElapsedTime()); lineShift-=pge->GetElapsedTime(); if(lineShift<-25)lineShift+=25; @@ -793,4 +866,16 @@ void Unit::SetBuildUnit(float buildTime,std::unique_ptrfinalUnit){ bool Unit::IsBuilding(){ return buildTime>0; +} + +void Unit::SetGuardTime(float time){ + guardTime=time; +} + +bool Unit::IsGuarded(){ + return guardTime>0; +} + +void Unit::SaveMemory(){ + savedMemory=memory; } \ No newline at end of file diff --git a/olcCodeJam2023Entry/Unit.h b/olcCodeJam2023Entry/Unit.h index 07e571e..40c06f3 100644 --- a/olcCodeJam2023Entry/Unit.h +++ b/olcCodeJam2023Entry/Unit.h @@ -22,6 +22,10 @@ enum class UnitType{ Corrupter, MemoryAllocator, RAMBank, + MemoryGuard, + Refresher, + Turret, + _Platform, }; struct Marker{ @@ -36,7 +40,7 @@ struct Memory{ struct Unit{ public: - Unit(PixelGameEngine*pge,UnitType type,std::vectormemory,vf2d pos,float radius,Renderable&img,Pixel targetLineColor,Pixel attackingLineColor,bool friendly=false,bool moveable=true,bool friendlyInteractable=false,bool enemyInteractable=true); + Unit(PixelGameEngine*pge,std::vectormemory,vf2d pos,float radius,Renderable&img,Pixel targetLineColor,Pixel attackingLineColor,bool friendly=false,bool moveable=true,bool friendlyInteractable=false,bool enemyInteractable=true); int GetHealth(); int GetRange(); int GetAtkSpd(); @@ -45,6 +49,7 @@ public: int GetMemorySize(); std::vectormemory; std::vectorghostMemory; + std::vectorsavedMemory; virtual void Update(PixelGameEngine*pge,std::map>&SOUNDS,std::vector>&queuedUnits); virtual void Attack(Unit&victim,std::vector>&otherUnits)=0; virtual void Draw(TileTransformedView&game,std::map>&IMAGES); @@ -87,6 +92,14 @@ public: bool IsAllocator(); void SetBuildUnit(float buildTime,std::unique_ptrfinalUnit); bool IsBuilding(); + void SetGuardTime(float time); + bool IsGuarded(); + void SaveMemory(); + Marker health={}; + Marker range={}; + Marker atkSpd={}; + Marker moveSpd={}; + Marker procedure={}; std::vector& operator <<=(const int n){ for(int i=0;itarget; std::weak_ptrappliedTarget; vf2d targetLoc=CONSTANT::UNSELECTED; @@ -151,6 +159,7 @@ private: std::weak_ptrself_ptr; float collectionTime=0; UnitType type; + float guardTime=0; }; struct LeftShifter:Unit{ @@ -224,4 +233,36 @@ struct RAMBank:Unit{ static std::vector resourceCost; static std::string unitName; static std::string unitDescription; +}; + +struct _Platform:Unit{ + _Platform(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly=false,bool moveable=true); + void Attack(Unit&victim,std::vector>&otherUnits)override; + static std::vector resourceCost; + static std::string unitName; + static std::string unitDescription; +}; + +struct MemoryGuard:Unit{ + MemoryGuard(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly=false,bool moveable=true); + void Attack(Unit&victim,std::vector>&otherUnits)override; + static std::vector resourceCost; + static std::string unitName; + static std::string unitDescription; +}; + +struct Refresher:Unit{ + Refresher(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly=false,bool moveable=true); + void Attack(Unit&victim,std::vector>&otherUnits)override; + static std::vector resourceCost; + static std::string unitName; + static std::string unitDescription; +}; + +struct Turret:Unit{ + Turret(PixelGameEngine*pge,vf2d pos,std::map>&IMAGES,bool friendly=false,bool moveable=true); + void Attack(Unit&victim,std::vector>&otherUnits)override; + static std::vector resourceCost; + static std::string unitName; + static std::string unitDescription; }; \ No newline at end of file diff --git a/olcCodeJam2023Entry/VirusAttack.cpp b/olcCodeJam2023Entry/VirusAttack.cpp index bc10581..45114b4 100644 --- a/olcCodeJam2023Entry/VirusAttack.cpp +++ b/olcCodeJam2023Entry/VirusAttack.cpp @@ -55,6 +55,11 @@ void VirusAttack::InitializeImages(){ LoadImage(SPD_ICON,"assets/spd_icon.png"); LoadImage(RESOURCE,"assets/material.png"); LoadImage(MEMORY_COLLECTION_POINT_HIGHLIGHT,"assets/memory_collection_point_highlight.png"); + LoadImage(MEMORY_GUARD,"assets/memoryguard.png"); + LoadImage(REFRESHER,"assets/refresher.png"); + LoadImage(TURRET,"assets/turret.png"); + LoadImage(PLATFORM,"assets/platform.png"); + LoadImage(GUARD_ICON,"assets/shieldIcon.png"); } void VirusAttack::InitializeLevelData(){ @@ -76,6 +81,7 @@ void VirusAttack::InitializeLevelData(){ units.push_back({UnitType::Corrupter,vf2d{132,132},true}); units.push_back({UnitType::MemoryAllocator,vf2d{133,133},true}); units.push_back({UnitType::RAMBank,vf2d{134,134},true}); + units.push_back({UnitType::MemoryGuard,vf2d{200,134},true}); for(int i=0;i<5;i++){ @@ -173,6 +179,14 @@ void VirusAttack::LoadLevel(LevelName level){ TranslateUnit(Corrupter) TranslateUnit(MemoryAllocator) TranslateUnit(RAMBank) + TranslateUnit(_Platform) + TranslateUnit(MemoryGuard) + TranslateUnit(Refresher) + TranslateUnit(Turret) + default:{ + std::cout<<"Could not load unit type "< key){return key.second<=0;}); for(auto&u:units){ + u->SaveMemory(); std::weak_ptrclosestUnit; float closestDist=999999; for(auto&u2:units){ @@ -604,6 +619,9 @@ bool VirusAttack::OnUserUpdate(float fElapsedTime){ for(auto&u:units){ u->Draw(game,IMAGES); + if(u->IsGuarded()){ + game.DrawDecal(u->GetPos()+vf2d{float(u->GetUnitSize().x/2),-float(u->GetUnitSize().y/2)}-vf2d{float(IMAGES[GUARD_ICON]->Sprite()->width),0.f}*0.375,IMAGES[GUARD_ICON]->Decal(),{0.375,0.375}); + } } for(auto&deadUnit:deathAnimations){ deadUnit->Update(fElapsedTime); @@ -650,6 +668,22 @@ bool VirusAttack::OnUserUpdate(float fElapsedTime){ float dist2=geom2d::line(u2->GetGhostPos(),GetWorldMousePos()).length(); return dist1>dist2;}); + for(auto&u:units){ + if(u->IsGuarded()){ + bool changeOccured=false; + int changedBit=-1; + for(int i=0;imemory.size();i++){ + if(u->memory[i]!=u->savedMemory[i]){ + changeOccured=true; + changedBit=i; + break; + } + } + if(changeOccured&&util::random(1)<=0.3){ + u->memory[changedBit]=u->ghostMemory[changedBit]=u->savedMemory[changedBit]; + } + } + } return true; } diff --git a/olcCodeJam2023Entry/assets/memoryguard.png b/olcCodeJam2023Entry/assets/memoryguard.png new file mode 100644 index 0000000000000000000000000000000000000000..b1db5d2e29d6ca84069c259fabd728c8dcfbd1d1 GIT binary patch literal 2252 zcmV;-2s8JIP)EX>4Tx04R}tkv&MmKpe$iQ?*4Z4t5X`$xxl_Qbio4ibb$c+6t{Ym|Xe=O&XFE z7e~Rh;NZt%)xpJCR|i)?5c~jfb#YR3krMxx6k5c1aNLh~_a1le0HIlBs@XFKsG4P@ z6LB$@Uljwd2x1I<2p}dgQ%`0Vv+x{W_we!cF3PjK&;2e3JS*_Mt`=0!Tp@O!O;X2JxB(Q`eQV=1djtZ)<5T#Wk#YCF+;~xGI$DbmXOs)zT zITlcZ3d!+<|H1EW&EizdO$x<<-WS{c7zYBoK&xTf-^aGyIsyF8z?IhV*P6iWC+Urj z7C8b2w}Ff6jwbH`mpj1llP(#OBl&3x#Uk*2M&FbNhHioWHMh6+K29HiEOoVf0~{Oz z6D7)C_jq@(ySIPOwEO!3x1e&u@PZ5300006VoOIv00000008+zyMF)x010qNS#tmY zE+YT{E+YYWr9XB6000McNliru=LjDc6(e&buK@r602y>eSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{00yKAfTB{YxO1b1 zYHEy$#y`LXu#`^up|W>JTkH&jYvY22ab>Cz2u?&3HpC#cpil%#WIF9wgJPo*`;Loy z-@W(!e$!5Cbdt$*+V}4J&bjA&-#O=&(ApPgypCG+Kw3f2%YuPg3HsQvW0`I~dh}?^ z@X%7hX9eAaF|=F;v=n%&454PhrvaZYRr{bmfIRv3^9UV?5iohja!W{jXL z;A4TW&HEQ)PJWX5GZXoqp1}}Wi~+IW=L>laCJ36q04uZ<*hBKZn#bD4L>ZE11T_zS z4WK}K;3a79P6mk7cgr{mKgt8Y6eC1djvuKGW2kl+Un>#o$2rS@*T#^%t8%3Z zfZ%p*kp_`~Xw>jdS8r-4IccFYU&sSB*5JuyaOcAS1C{Y}fa?Na6np!PpE-K>O>PrT zjGvJ>L=LQglTIZUV8(nQAIDJa89`~@_Za8>iSyv~n^1gcD~K88*&6`6DxMkQ?vDU7 z26w-lNEPKvp93V|ZrZ90AOHe`>$ii6Q2zNQMB^^r?0H^N?63C|cfm2Bg!#f6tiJbK zEJi1hHtkSw7kpIdfhPtIt=|DKFk1f}?xyW}SA6RT(g|>=^D!-KOblWI!=hhz!Mc}2 z6|dR_20%_0?~~?qMtOD;2RpWF@Y=!5INbSovKnj7XRt~L0!br4D9uhPRx&g#cOfz+4b1QFo&lXzFLSqaS$K?$EUAIR#FrSL0Z6I zDZD3kNiUJ9aQ7{0*E1H|*fGtJMz{->fgx{%cM9C}j6kH9Oy)~*cRxh!W<&uZubDf0 z5qsBNz`pkLm^*bE``bUo{&i!R`{*3@wV%h{br&#q_M(pU;6kEy6UC?cn=-&jYd+%a z`lWD7dUou0;FUIj7ySI~H~{{NT>g#fHXuhRuNp%!_bRwe;M6lyiyGcI+3ci18v@Yj zKfxa0PyPTNJOD%vBd1*8K@M;n44qsBv^jv|VEDrvuu1?9P{zlAXanHj1U>`Y9NN*d zs3DWn1b$Wi%BXwywbvu-dDGk&q0?-ms!xyg|%N>E%e=dXoqg=ADNoq^l+sKxmf_bb))iIN=-Bvg+n z4EGbs65{EXq}Zu@%ntg?YP+O%vPTaY>JzrW2-$$>sziO-*V~FKj4B&rEVcHYMcHO2 zu?E;-#2_jC+L>fZUow1tc*7G`w#Pf-y_p{jc-RJ66+0~NCrtAaJ2G#C5@H(wm2c0& z?b?Ea9o^Cf4mR=}NJOiu(v3V&nw^BGPhntpzb1p=xFs%pQd!9Bgv{K=T3pE3EzM4X z31H#(B3mrP0q{%;d_&d$A{WhS5iMmZjfSSg6lOLiLb3NnQ2mZ6#NYuV!zh6_3$ipp z-Xmu2V4(K};~0MppL(t!(o)5Xzu>kSpaP}F4GByeVvJ#1v~)=glo~exwTnJ|us#!F zpPCwM*@Ik9X>~4)e*xa`h*fPe20OYVdAh7yMhTGW()&>kN}EQc8jv(%33g_c@2W~C z819BG*3>4fsG@#H3)R4reSTGr@qE&_-N{~yDrzm{HLZFSJJ8#wC(@OPs+wZ38dw2T zpVH4gpgi8pa5u@}OCPUWbV-3Gy)yBo90+(LNFeO-lmm~&j@Ppta9D*?hh$(^NTY1E^$U{E(6WRLyZyfUdFOFH4&5)Hm=uU01|11A$ka1qHG8hQ0eXaPv a+x!Dbzq@K6N+!|(0000EX>4Tx04R}tkv&MmKpe$iQ?*4Z4t5X`$xxl_Qbio4ibb$c+6t{Ym|Xe=O&XFE z7e~Rh;NZt%)xpJCR|i)?5c~jfb#YR3krMxx6k5c1aNLh~_a1le0HIlBs@XFKsG4P@ z6LB$@Uljwd2x1I<2p}dgQ%`0Vv+x{W_we!cF3PjK&;2e3JS*_Mt`=0!Tp@O!O;X2JxB(Q`eQV=1djtZ)<5T#Wk#YCF+;~xGI$DbmXOs)zT zITlcZ3d!+<|H1EW&EizdO$x<<-WS{c7zYBoK&xTf-^aGyIsyF8z?IhV*P6iWC+Urj z7C8b2w}Ff6jwbH`mpj1llP(#OBl&3x#Uk*2M&FbNhHioWHMh6+K29HiEOoVf0~{Oz z6D7)C_jq@(ySIPOwEO!3x1e&u@PZ5300006VoOIv00000008+zyMF)x010qNS#tmY zE+YT{E+YYWr9XB6000McNliru=LjDcASF0<$btX>02y>eSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{00Iz6L_t(&-rZW;jl>`f#E1$gB{ghM)R3OGhLn;Pd|yO+ zh{s@?T=p!jv>ya!ustRwab&e1-3WRK2C@X5QgSiI;ln8;`BEX~FmJrYqp;_>G$7^6U1R6w!_`C%CN-Nf2tp~UTyyXGsoZ1T&Z;*rl_jbJ% zE}29&!;qqx5MpV_#2BxiaY!*rfZcPAkr3if*R^&MQJm43GTcB

%qQq*6;jlOwf! z2%6B5f-%Ss&LsRmhoNM(O4!L70T;4In@0-PldP0gzc^NxTdY|`ZS$)6XP2h;v_kGWj%Av>HGK9+ct=0>zhtKo87SS$N+g+>836cc#?A+ZQOP{?_H zW$i#ih@5krQi8h=R>uj87yW>^QF4qxyB1$3qnVTy5&!v)+36ZDAz{%c`ZsT6HHMF~ z8a6-Z5k1wY=x&nek*N{*>rV|JGIwFHKL6bQxy=t^y*2s?(uj%x0000EX>4Tx04R}tkv&MmKpe$iQ?*4Z4t5X`$xxl_Qbio4ibb$c+6t{Ym|Xe=O&XFE z7e~Rh;NZt%)xpJCR|i)?5c~jfb#YR3krMxx6k5c1aNLh~_a1le0HIlBs@XFKsG4P@ z6LB$@Uljwd2x1I<2p}dgQ%`0Vv+x{W_we!cF3PjK&;2e3JS*_Mt`=0!Tp@O!O;X2JxB(Q`eQV=1djtZ)<5T#Wk#YCF+;~xGI$DbmXOs)zT zITlcZ3d!+<|H1EW&EizdO$x<<-WS{c7zYBoK&xTf-^aGyIsyF8z?IhV*P6iWC+Urj z7C8b2w}Ff6jwbH`mpj1llP(#OBl&3x#Uk*2M&FbNhHioWHMh6+K29HiEOoVf0~{Oz z6D7)C_jq@(ySIPOwEO!3x1e&u@PZ5300006VoOIv00000008+zyMF)x010qNS#tmY zE+YT{E+YYWr9XB6000McNliru=LjDc8~^};WjX)=02y>eSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{00JLLL_t(&-tAgTZo?oDWgK5A3m>MR6LgCdDXU14*!Bed z9Hxt$siKQ24kirD41+&vStZCCzc-)900yHwJn=cudLhgRx(No*1nry~f7{F9Horel zp0n1f;elH4A?Oj{aJ>C_{k|hmAOo!k6oHSPf7wk4V3E)u0$lJI@H@}PqYw#%ND*JB z1zu}J@9?z|@EqW|2)M5kn@kW5kPz@vuZKh=z&Rv(3HY2uR)I~}bA=pik0FL*i5=ruW!7i3c9U1&^oW8`E-~aKP#PbBZ0Va!JVv literal 0 HcmV?d00001 diff --git a/olcCodeJam2023Entry/assets/shieldIcon.png b/olcCodeJam2023Entry/assets/shieldIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..563876d5897c69f88ec774e55aeb8d4570870e86 GIT binary patch literal 908 zcmV;719SX|P)EX>4Tx04R}tkv&MmKpe$iQ?*4Z4t5X`$xxl_Qbio4ibb$c+6t{Ym|Xe=O&XFE z7e~Rh;NZt%)xpJCR|i)?5c~jfb#YR3krMxx6k5c1aNLh~_a1le0HIlBs@XFKsG4P@ z6LB$@Uljwd2x1I<2p}dgQ%`0Vv+x{W_we!cF3PjK&;2e3JS*_Mt`=0!Tp@O!O;X2JxB(Q`eQV=1djtZ)<5T#Wk#YCF+;~xGI$DbmXOs)zT zITlcZ3d!+<|H1EW&EizdO$x<<-WS{c7zYBoK&xTf-^aGyIsyF8z?IhV*P6iWC+Urj z7C8b2w}Ff6jwbH`mpj1llP(#OBl&3x#Uk*2M&FbNhHioWHMh6+K29HiEOoVf0~{Oz z6D7)C_jq@(ySIPOwEO!3x1e&u@PZ5300006VoOIv07U>r07V(MmT~|9010qNS#tmY zE+YT{E+YYWr9XB6000McNliru=LrD-94k2TAd>(902y>eSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{00Cr4L_t(o!|hkQ6@xGgJn>vo<}m`3umN*s118A`c`2zO zm5HKAwu~WZq7p3Wbo$sL09a?NU_vbjCy3^U;>T{h008dS$0;C8KkJOO8!uS;0RYh4 zrtRkuKzP)epCA>Men2-)8%l1#3r12MqmItG1kFG^7=cJI77!V&w5Q2i4J`eD<~FHH z@jFkCCRViEE>Cly_60&yh)NnODfXldHTo75JUQj)Q*?SACu@MGp~i5Ioy{gMvRVgT zHhCR2XHLFc{>?Tlq44k;C~;H^^sNSdC8S*zRs>#ZQ~L6<3%n@!K&t5oO_zh>MgQ{@ z`~ieiA<10sode11*m^eA&H_&de5BwTBU$EX>4Tx04R}tkv&MmKpe$iQ?*4Z4t5X`$xxl_Qbio4ibb$c+6t{Ym|Xe=O&XFE z7e~Rh;NZt%)xpJCR|i)?5c~jfb#YR3krMxx6k5c1aNLh~_a1le0HIlBs@XFKsG4P@ z6LB$@Uljwd2x1I<2p}dgQ%`0Vv+x{W_we!cF3PjK&;2e3JS*_Mt`=0!Tp@O!O;X2JxB(Q`eQV=1djtZ)<5T#Wk#YCF+;~xGI$DbmXOs)zT zITlcZ3d!+<|H1EW&EizdO$x<<-WS{c7zYBoK&xTf-^aGyIsyF8z?IhV*P6iWC+Urj z7C8b2w}Ff6jwbH`mpj1llP(#OBl&3x#Uk*2M&FbNhHioWHMh6+K29HiEOoVf0~{Oz z6D7)C_jq@(ySIPOwEO!3x1e&u@PZ5300006VoOIv00000008+zyMF)x010qNS#tmY zE+YT{E+YYWr9XB6000McNliru=LjDc9vN2LuXq3e02y>eSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{00GEJL_t(&-tAgTvVxsPYyKCJZs9E!J?a*E-F z7(Svin$=V(&`ozT1recd1mSzwYe5_c`Vb7*6STGVH7O!E=RTepV<3druz8-l;Zd#N zt+n922k$)~A_*Pu*5pl?$_9dOXf78_mWykt#f8@R#H;A zj`Y5CEee~0FAr5yHqW$CT2`ABXieZAbEpfy>*6v(e8a@k8Jt@DO+iJOu7b z0OP~Lc6hjAPzM{40_h29L`c_cvJiC~96g7M&zM)XQSMy)dsQfRcRw-@a%)l8Vgg7> zb|w2zSgA|XVRu8VcS39qFm0gW!C|2YuvR)U7jnCw!^SC4R90(h`Q8|5kAN$qSrSL6 zP}|^;^vJ|5rkWlZ1-_(DCix@7IGK7Y(c0v@O`EldNRGq?z6bCY0{=+FWB|r~YH-_+ eJzB|hTlWubj2~X3-|5}}0000