Ocean of Code - Feedback & Strategies

Iā€™m only bronze. Iā€™m not saying the contest was bad, but the lockdown has a very negative effect on my motivation :frowning:

2 Likes

Thanks @Illedan, @eulerscheZahl and @G-Rom for the wonderful contest. Awesome rules and brilliantly designed. I was late to the contest and only managed to rough out a code to get me into mid wood 1 but will look forward to reading the top player`s post mortems and playing it as a multi.

Thanks again !!

4 Likes

C# ending (hopefully) top 20 after the rerun

First week

Mostly hack around spagetti, trying stuff while also keeping an eye on the contest code, fixing bugs and rewriting the whole contest code for my own sanity. (code done in 2 days without tests :scream_cat:)

Second week

Get that tracker workingā€¦ Made as most top players a tracker following the game state from every possible starting location, expanding on silence and removing invalid states. Did about 3 full rewrites of the trackingā€¦

Third week

Add a big block of InstaKill code which does combinations of torpedo, move, silence and surface. This was enough to get back in the game and into Legend.

Forth week

Feel the lack of motivation rising and trying to rewrite everything as I add more ifs and stuff to the spagetti.

Tracking

Every game state contains all the visited cells up to that point, health of the player, current position and locations of when mines was dropped.
I pruned opponent location based on them being on top of my own potential mines or not. And reduced the pruning if there was no possible locations left.

Also used the same tracking to track myself.

Final algorithm

Move:
Run a depth 4 DFS with a score based on:

  • Visits to cells in potential mine blast areas
  • Distance away from the enemy - further away makes me more safe, as my fighting logic is bad
  • Negative score if Iā€™m in damage range to every possible enemy locations when I have torpedo ready.
  • Small negative score if I was in Torpedo range and was visible enough for a shot that would hit me. Using my own torpedo logic to determine if a potential shot would damage my sub.
  • How many potential positions I could be in at the end of my moves
  • How big Territory I had left. I did a floodfill stopping at my own path, islands and potential mine blast areas.

Torpedo:
Find the target hitting the most enemy locations. Only fire if I can hit all targets or if I donā€™t reveal myself more. Try this before and after the move logic.

Trigger:
Trigger if there a mine can trigger more than enemyLocations/coeff, where coeff is 1.55 at the start and increasing every 50 turns to trigger more later.

Mine:
Only place mines if they can target 4 or more new cells given my other mine blast radiuses.

Silence:
Except for InstaKill, I only silence with a length of 0, but only if there is more than 4 possible cells in both N+S and E+W. To give the most options. Silence is only done after the move logic.

Surface:
Only when there is less than 4 moves left in my FloodFill territory.

The big rewrite

I also started a big rewrite into some MinMax bot, but my motivation stopped me in the end.
Will see if I manage to finish it later :slight_smile:
The idea is to play my bot with about 60 possible sequences of actions (all move directions, silence at 0 or max depth in every dir, torpedo the best position, trigger the best position, surface)
And the enemy with a branching of either:

  • 1: Pick the best move in staying hidden and fire a torpedo if I was close
  • 4: Try all moves with torpedo
  • 8: Try all moves with and without torpedo
  • Maybe with silence too
25 Likes

Golang ~165 ish

First week : 150th

basic ā€œout of bronze to get every rulesā€ bot : spam silence, basic detection, torpedo if in range

Second week : 20th

Rewrite everything, computing my possible positions as well (to be as silent as possible)

Movement decisions using beam search depth 5 size 20, with an evaluation taking into account both accessible positions with floodfill, my possible positions as seen by the opponent, and distance from enemy possible positions (average).
Never use sonar
Use silence if my possible positions < 3
Use torpedo if torpedo can hit at least all enemy possible positions
Mine otherwise, and trigger if enemy might be in range

Order of power : Torpedo > Silence > Mine

Third week : 50th

Didnā€™t change anything, force submit to reset derank from pushers

final week : 165th

Same

30 days is too long for me to get focused for the whole contest ahah

5 Likes

Very good contest:

  • simple rules, rich gameplay and strategies,
  • possibility to perform without simulation, with good heuristics,
  • all powers are useful and well-balanced.

Congratulations.

8 Likes

I finished 28th.

Not much to say about my bot: tracking the opponent actions and using heuristics to determine the next move. Tracking myself as well to hide my location when choosing the next move.
But here is an animation for this game :slight_smile:
replay
Numbers represent the danger to get damaged by a mine, small red dots are my own locations as seen for the opponent while gray circles are the opponent locations.

I also generated some statistics about the gameplay of different users: https://eulerschezahl.github.io/OceanOfCode/ooc_stats.html

42 Likes

So as an author of a gold boss I have a few things to share.

I think most of features that are considered to be basic among legend players aroused in the duration of contest and gave a push for people who implemented them first, even if not in the most optimized way. Here goes a credit to @mchl12 for quite convenient implementation of self-tracking for estimation of all the actions in terms of giving up information about yourself, and, more importantly for implementing the killing blow or, as I call it, FATALITY. These features gave him a solid lead in bronze time, and even without improvements for the second half of the contest he still made it to gold, I believe basically with the same bot.

For me such a feature was mine avoidance. Silver was the time for most people to realize that some kind of mine avoidance is necessary. My first implementation of it was based on estimation of directions by flood-filling sum of the damage with discount. That was only a bit more effective than simple checking adjacent points, although it gave the possibility to estimate if you need to SURFACE not to go to the mine field. Being limited with python speed, I looked for a more precise and in the same time not very consuming algorithm. So the second implementation of mine avoidance aroused in the discussion with BorisZ and stayed this way for gold boss and almost the same in my final bot. The basic idea of it was to generate a bunch of valid random paths, and check the damage on them with discount, choosing an optimal path. I was able to generate only around 50-100 paths of length 15-20 in 5ms, which although was quite enough. Not to underestimate the damage, I greedily choose the maximum length path, and then minimized the damage. This path I did not just follow, but rather used as estimation of a direction and of necessity of SURFACE. Quite important thing here was not to prioritize mine escaping when there are too many candidates, not only because it is require some heavy computations, but also because it could lead to some suboptimal moves. So in the mean time I would rather just minimize the information given. This simple estimation together with other basic features gave me a solid lead in silver which I kept almost to the time gold was open. Around that time other players also come up with own effective mine escaping. With some minor improvements this bot became a gold boss and for a time being did guard legend pretty ok.

I also tried to resubmit the gold boss after 4 days in legend and in the last day of the contest. First time it landed around 12-15/35 and last time 40-50/60 which kind of made sense since late comers could optimize against boss and top players improving their bots quite significantly.

Couple more simple things Iā€™d like to cover. One is handling spam silence in python. Tracking of all the paths possibilities when the opponent uses silence too often is almost impossible without pruning at some point even for more fast languages, so I made merging of the paths that come to the same point by keeping only common parts of them with summing all the mine planting positions for these two paths. The tricky thing is that if the damage was taken in the same turn SILENCE was used you can not tell for sure if the candidate is have to be pruned or not. This imperfect silence handling lead to losing some information, but occasionally it is quite enough, and the results are almost the same as for perfect tracking when it does actually matter (<~15 candidates).

The other thing was targeting SILENCE 0. Zero length is quite easy to use, do not require any estimations and you basically cannot harm yourself jumping to the mine field or in the dead end, so it was used widely by many people including top players. More importantly for me it was used by @kovi and I had 0/32 wins against him, so I decided to do something about it. Basically after opponent used silence once I tracked if the SILENCE 0 candidates will survive and based on that increased the weight of these candidates heavily, if, occasionally, opponent would use another length, the zero length candidates would be pruned and weights normed back to normal. This worked quite well even when opponent did not start to use SILENCE 0 right away, using different length at the start of the battle. The only thing I regret turning it off for gold boss submission, I guess it would be quite fun forcing people to use non-zero silences. In the end I weighted all the length with different weights based on @eulerscheZahl 's stats collection (thx :P), which actually helped a bit.

For my legend bot I basically did not add much, mostly working on mine placement and trying to control territory while in the same time "flattering" the opponent damage map, in a sense of reducing gradient of a damage map to get a better covering without much overlapping of a mine ranges, which also gave a clear strategy when to hold mines without spamming and some space for using sonar due to not overcharging mines. Also I think that important addition was to hold mines to place them after silence. That hits heavily on damage estimation of an opponent and looks quite dirty.

Overall I am quite happy making it to top20 on my first contest and winning a t-shirt. Thanks to all the community of the #world and #ru chat who was quite supportive and made it much more interesting to participate with all the interesting discussions and ideas, and also to @Illedan, @G-rom and @eulerscheZahl for making the contest. I think it is safe to congratulate @pb4 with a win, even though top4 is really close.

27 Likes

Thanks for the contest, guys!

It was fun. There are a lot of possible strategies and no need to write simulation - that my favourite kind of game. I was improving my bot till the last day and still there are thing to work on.

Pretty unhappy about not hiting top-50, but thatā€™s life.

Looking forward for your next contests

:wink:

7 Likes

Grats on your result wlesavo. Funny thing: Last night at 2 am or so, I coded a silence with more than 0 distance and I think that helped me a bit. Good find!

3 Likes

Thanks for the amazing stats and gg on this featured win :smiley:

1 Like

Most of my bot was basic stuff and a lot of if-statements but the best thing I did was modification for floodfill movement where it favoured squares with more previously visited neighbours. Made for a more compact movement and harder tracking by the opponent.

Also I believe trying to take ā€˜controlā€™ of the middle was important in the start but I didnā€™t quite manage to use it as well as I wanted.

Nice challenge, cheers!

4 Likes

Thanks for the contest!

I feel so happy to reach the top 20 for the first time!

I personally used a kind of MCTS to find the best actions.
In UCT, the exploitation term mean (score/visit) is balanced by the exploration term.
I replaced the mean by the best score of the children.
And in each evaluation, I have a (poor) simulation of opponent play.

I loose time to evaluate every single step, but using an UCT, I donā€™t loose time to evaluate not promising nodesā€¦ Not sure it was the best approach, but it worked not so badā€¦

I also used some map of probable damages: one for opponent mines and another one for opponent fire damage.

11 Likes

Hello everyone, I came back on CG for this interesting contest. I really enjoyed it even if I would have loved reaching legend. Thanks @Illedan, @eulerscheZahl and @G-Rom for this contest inspired from the game, updated rules were pretty well balanced. GG

One month was perfect for me because I canā€™t connect a lot, this let the time to come and improve my code from day to day.
It was interesting to find a good strategy to follow and try to implement it. The bad thing on this contest, it is hard for someone who try a contest for the first time to code some ā€˜basic featuresā€™. I spent most of my time in the code to find the opponent according to its/my actions (and debug it BTW ^^).
I was working on a correct way to avoid opponents mines. It started working but didnā€™t had the time to finish it. Canā€™t wait to have this game in multi to finish my last features.
Thanks to this contest, I discovered the game ā€œCaptain Sonarā€ and really want to try it!
See you soon!

7 Likes

I ended 25th. Very happy with the result. Thanks to the creators for coming up with a great contest to spend the lockdown.

For some reason this contest failed to motivate me for 75% of the month. Not because there was anything wrong with it, but because I had other things that drew me away. I liked the information aspect of it, the tracking, eliminating paths etc. I had less fun (and less skill) with the strategic logic. Hereā€™s the general flow of my bot:

Bitboards: I thought it was essential. For tracking I kept a 64 bit (* 15) minemap, a 16 bit map with visited cells and a single position for each possible opponent state. A quarter of my code is just a lot of helper functions for these bitboards. Copying, combining, adding, removing etc.

StartCell: My start is fully random, except that I donā€™t start in closed off sections of the map (you can check this with floodfill). I assume the opponent can start on any cell, meaning I start with 225
(minus islands) possible states for tracking.

OpponentOrders: The most important stage for tracking. For each state, I process all opponent orders and if one of them doesnā€™t match up to reality, the state is removed. There are two ways in which extra states can be created.

  1. Silence
  2. Trigger that happens on a position that has more than 1 neighbouring position from which a mine was laid

I also tracked all damage forms on a damagemap and any cell that got an amount of damage that does not correspond to opponent health lost, has its states removed. Itā€™s also important to make sure you floodfill the cell torpedoed by the opponent to see where he could be.

A major issue in this game is chain-silence. It can time you out easily. I have a limit as to how many states are allowed to exist. If there are too many, i combine the ones with the same position and mines and combine their ā€œvisitedā€ histories to only have cells that all cells share in their history. I also do this for self-tracking. I silence more than most players and if I didnā€™t prune, I would time myself out as well :slight_smile:.

Mine avoidance:: Since I have a bunch of states with mines laid from various cells, I can combine this information into a mine probability map (where are mines likely to be?) and a mine probability damage map (which cells are those mines likely to damage?). I use a beamsearch to navigate the map, avoiding cells with high probability of mine damage. I also combine this with a floodfill-score (to keep room for myself to move and not have to surface) and a self-tracking score (so as not to give my position away).

Self-Tracking: Similar to opponent tracking but with a key difference: I donā€™t track mine-triggers. This was mostly to keep the complexity of my code smaller, but also to conserve calculation time.

Fatality!: I love this part of my bot. It simply brute forces all possible actions and checks if there is a guaranteed kill. It will also surface if necessary, silence-dash to the opponent, combine mine + torpedo damage and even damage different parts of the map if the opponent position is not yet determined. It could theoretically damage 18 cells just to do 1 guaranteed damage to the opponent and kill them if it is possible.

Ability Charging: This is the first area of the game where I didnā€™t really know what to do. In the end I preferred torpedo, then mine, then silence if the amount of cells where my opponent thinks I can be, drops below a certain value. Otherwise sonar.

Overall Action Logic: This is the second area where I tried stuff and did not know what was best. I think I got a reasonable set of heuristics in the end, but it could be much improved.

  1. Make an opponent-probability-map. That is for each cell, calculate the likelyhood the opponent is there. This is necessary for other logic.

  2. Check if moves are even possible (in case you need to surface). If not and you have more than 1 life remaining, then Surface.

  3. If you have moves available (also after surface), do the earlier explained beamsearch to get a movement direction.

  4. Check the best targets for a torpedo before and after the move and determine which is the best ā€œshotā€. If the score is above a certain threshold, launch the torpedo before or after the move (preferring before the move, on equal score). Score is determined by the target cell with the highest expected opponent damage (using the opponent probability map). Donā€™t shoot yourselfā€¦

  5. Check the best targets for a mine-trigger and see if the score is above the mine trigger threshold. I also check if I need to move out of the way (trigger before or after move). Score is determined the same way as torpedo score, but the threshold is a bit lower. This is because torpedoā€™s reveal your position more strongly. I noticed a high torpedo threshold is very important.

  6. If silence is available, check if it is worth using, meaning, does the opponent get more cells where it thinks I am (at least 4 more) and am I even below a certain value on this (below 30 self-tracked cells). So basically: Is it necessary to silence and does it even help me at all?

One of the last things I coded was a non zero distance silence. This to possibly avoid a bad position with mines. I donā€™t think it happens often, but it does happen.

  1. Lay mines when if I can, but not when there is too much overlap with other mines. Try to lay mines that cover more available ocean.

  2. If sonar is available (almost never). Use it only if the opponent could be in more than 1 sector and pick the sector with the most states.

  3. If there are no orders recorded yet (because I canā€™t move and I canā€™t surface or I would die), I start blowing up mines.

Thatā€™s most of it I think. Works quite well, but I think in the end I wrote a heuristic bot and the trick to being in the top 10 is probably a more flexible search-based bot. People talked about battle simulations on the chat. That is probably a necessary component. Other than that I could have watched more games and added more heuristics. One example of this that dawned on me while writing this, is that I did not consider laying a mine before moving. Maybe that would sometimes be good.

24 Likes

Thanks to @Illedan, @eulerscheZahl and @G-rom for saving our lockdown month and one of the best MULTI CG game (simple but full of possibilities)
I finished #8 and 1st in java. Really happy about this result.

One of the hardest thing in java CG MULTI is dealing with garbage collector timeouts.
This time i used mainly primitives and byte arrays rather than objects.
For example :

  • to store a position : a number between 0 and 225 rather than an object with x and y fields
  • to store a possible opponent way : a byte array [life, position, mine dropping positionsā€¦, map with visited positionsā€¦]

I learned this by making UTTT legend which is the best MULTI to improve in coding java CG MULTI.

The heavy work was done during the first two weeks :

  • a good detection of opponent moves (which could be used both ways)
  • calculate all possible combinations of actions that i could do : TORPEDO->MOVE->SILENCE->TRIGGER or MOVE->TRIGGERā€¦ with some pruning.

I spent the last two weeks on the ā€œevaluationā€ (it became a bit boring but i tried my best to keep my ranking)

I struggled a lot with the size of my code.
I tried to code cleanly, but after two weeks i had to remove all spaces, ā€œuseless codeā€ (like public, finalā€¦), even reduce the class and variable names when bundling my classes in one file.
At the end it was a bit blocking, i would think twice before starting a big improvement.

18 Likes

Hi again,
Just few questions.
Previously we were waiting around a month between the end of a contest and the opening of the game as multi. Is it still around a month?
Second, does anyone already tried to use the referee java code to perform local tests (Me against myself)? I really would like to finish and validate my last features now because in a month it will be hard to go back into it.
And if someone still have the link to the referee I am interested ^^.

2 Likes

The game should be available as a multiplayer later today :slight_smile:

If you canā€™t wait, you can play some on this contribution:


Just select the 3rd league top right and there is some other players (3 weeks old) that submitted :slight_smile:

4 Likes

Hi there,

Many thanks to @Illedan, @eulerscheZahl @G-Rom and Coding Game. You helped us go through these complicated weeks, with a game was really interesting and well balanced.
I ended 50th with a randomized MCTS, which proved to be rather weak.

It was nice to try a longer duration. 4 weeks were cool, maybe a bit too long : we had enough time to code all that we wanted,
but the last week I felt quite exhausted. Maybe a 2 weeks duration would be ideal for next contests.

5 Likes

I finished #15 in legend. My strategy was to focus on parts of the bot one after the other, not caring until my rank until it would be all done. The upside of this approach was that, in the end, every single ā€œpartā€ of my bot worked extraordinarily well. The downside was that when I had to put them all together, I failed.

Tracking

The most boring part; the bot just remembers all the possibilities, and when there were more than 10000, I would remove half of them: I would find pairs of possible ā€œhistoriesā€ that ended with the sub in the same cell, and I would merge them into one - the visited squares in the new history were intersection of visited squares of the two old histories; mines were union of the old mines (I remembered the square from which the mine was placed, not the squares where it could be). I used 2 bitboards to remember the visited squares and mines; apart from that there was only playerā€™s HP (to be able to prune after torpedoes and triggers) and his position.

Starting position and early game movement

I used the first turn to precalculate the first 33 squares I would visit (unless a mine or a fight happens). I used a genetic algorithm to do this. Every individual in the population consisted of up to 32 directions, stored in a 64-bit variable (2 bits per direction). Evaluation was simply walking from every square on the map, following the directions, and for every step that was valid I added 1 point to the evaluation - this ensured that I couldnā€™t be found easily at the start of the game. Mutation was simply changing one direction, crossover was taking two subpaths and concatenating them into one. After the GA finished, I chose an individual from the final population and a starting position according to pathā€™s evaluation, number of squares I could reach from the final position (so that I donā€™t need to surface right after those 33 squares) and number of squares that I could mine when walking along the path.

Movement / Pathfinding

I used a genetic algorithm again, but a different one. This time, the individuals consisted of 225 directions (450 bits); each direction corresponded to a cell of the map, and it was the direction in which the submarine would move next from that square. The evaluation was simply following the directions, starting at my submarineā€™s current position, and adding bonuses and maluses for each square I visited, with decreasing weights further down the path (decay). These bonuses and maluses were:

  • a constant (1), to make sure that I would surface as late as possible
  • a small bonus for being close to the center - thereā€™s usually fewer options for your sub when itā€™s stuck in the corner
  • a small bonus for being out of range of any of my mines - to try to claim more space
  • a large bonus if the path didnā€™t give my position away - every turn, I precalculated how many cells I could be in (according to my opponentā€™s tracking) after every path of length <= 6, and used only this information.
  • a large malus for going to a square that could be in range of opponentā€™s mine (I calculated expected mine damage for every square, based on my tracking)

To mutate, I walked randomly from a cell on the subā€™s path, until I either had no available squares, or merged back to the path. Crossover was following both paths at the start until they diverged, then picking one of them randomly, following it until the paths merged, then repeating the same process until I ran out of squares. Implementing these operations efficiently was the reason why I needed entire maps as individuals. On its own, this pathfinding, along with torpedoing whenever expected damage was above 0.75 and silencing afterwards, was enough to reach legend.

Surfacing, sonar, stuffā€¦

I used sonar whenever the opponent could be in more than 1 sector and I had it charged, and used it on the sector with the most possible opponent positions. Surfacing was based simply on the expected mine damage I mentioned earlier, with the threshold needed for surfacing depending on my HP. I charged actions in order Torpedo > Silence > Mine > Sonar, with giving Mine some additional priority on the early turns, and also preferring Sonar over Mine when the number of possible opponentā€™s positions was above a threshold. I placed mines whenever I came close to a square that my bot considered good enough (based on number of water cells next to it, and how many of them were already in range of one of my mines), becoming less picky over time. I triggered mines whenever the average damage caused by the explosion would exceed 0.65; having this value too low or high had very bad effects on my bot.

Fighting

I wrote a simple sim that tried every possible combination of my actions (surface, move, torpedo, silence) that made at least some sense - f. e. never torpedoing a cell if the opponent couldnā€™t be next to it; usually ~2000 combinations. For each one of this combinations, I would find the cells the opponent could think I am in - this would be too time-consuming, so instead of working with all the combinations of cells I could have visited before coming to each cell where my opponent thought I could be, I used an estimation - the ā€œrealā€ visited squares, but I would move the squares I visited since I last used silence by the difference between my actual and ā€œpretendedā€ position - for example, if Iā€™m at [1,1], I visited squares [1,2], [1,3], [2,3], [3,3] since I last used silence from [4,3], and Iā€™m calculating squares I could reach by a combination of actions starting at [2,1], I would add [1,0] to those coordinates, and get [2,2], [2,3], [3,3] (and stop there, because [4,3] was visited before using silence), and the rest of the map would be the same. Then, I made an eval (HPs, numbers of possible positions after all the actions) for every combination of possible opponent position and torpedo that made some sense, and averaged them with some weights (opponentā€™s torpedos that hit more squares had higher weights), added some additional bonuses and maluses based on cooldowns after the turn and distance, how useful silence was in the part of the map where the fighting took place, how many cells I could still reach after my actions, and on expected mine damage on that cell. Going deeper than 2 turns wasnā€™t very useful, because once the abilities were used, players only charged torpedo and eval was simple at that point and it was easy to estimate the result from just the HPs and how much information the players had about each otherā€™s positions.

And indeed, this worked great - whenever I tested this against my final version, it won a large majority of games where the two submarines met and fought to death.

ā€¦ ā€œwhenever I tested this against my final versionā€?

Where it went wrong

I think you can already tell that this bot had a lot of things in it. So many, that the most difficult part became deciding which of these algorithms should I believe in this specific turn. I had a precalculated path from the first turn. I had a genetic algorithm that suggested a different path - this GA had less time to calculate it, but more information, and different priorities. I had an evaluation of how good each one of my possible actions was when it came to fighting the opponent with torpedoes and silence. I also had some heuristicsā€¦ and it became a mess. The fighting algorithm couldnā€™t tell whether the sub should try to silence and torpedo towards a possible enemy position, or keep playing calmly, and somehow trying to use differences in evaluations was futile; pathfinding algorithm kept walking into torpedo range at 2 HP, ā€¦ A few days before the end I realized that by adding more stuff (assumptions about enemy positions, using mines offensively, and more things I had prototypes for), I would probably just make it worse (and I was dangerously close to 100k characters), so I just thoroughly tested what I had already made, and it turned out that a bot that used the old, bugged fighting algo (a predecessor of what I described) worked best against the other players (except kovi, who kept losing to the new bot for some reason, and winning all the games against the submitted one). Maybe I could have somehow made it work, but with all the variance on the leaderboard and even in the benchmarks, I was lost and gave up.

Congratulations to everyone who managed to make sense of this game, and thanks to creators for giving us a game that we didnā€™t even come close to solving despite playing it for a month.

17 Likes

I joined the fun 3 days before the contest ended, yet reached mid Silver!
Update: I reached gold in the multi :slight_smile:

Wood2: Random shooting Just throwing Torpedos at random spot + handling SURFACE got me out off wood2.

Wood1: The SONAR strat. I started storing last known enemy grid through my sonar results and opponentsā€™ SURFACE commands. I used SONAR restricted to grids where I can use TORPEDO. This drastically improved my rank. (I only use SONAR after my move command so that the result is more accurate as I always use Move before Torpedos). I restricted myself never to enter into choke points where there is less room to breathe. I prefer to finish my current grid before moving to the next grid. This gave me enough time to spam SONARS only in grids around me instead of jumping into enemy and get surprised. All these logic and I was still stuck on top 10. So I added some random firing chance even when I donā€™t know enemy grid and that promoted me.

Bronze: The enemy tracking strat and stay out off his firing range: I started tracking enemy movements. Whenever enemy uses a silence, I cleared the enemy history. Every turn I recalculate all the possible end points of enemy (from enemyā€™s turn 1 movement). I removed all the SONAR code and started charging SILENCES. As I removed it, I also removed the logic where I prefer to stay in the same grid. It was okay to surprise enemy and fire at a random enemy spot I predicted. I replaced my move command with SILENCE with distance 1 whenever I had cooldown. I finally fixed my spawning inside the pond. Used Torpedos before Move commands. Easiest league so far.

Silver: The combo finder strat: I decided to implement a search algorithm to shuffle my command orders in order to generate nice combos. I was able to run it with an average of 15000 simulations easily. Did optimisations in tracking code and fixed a lot of bugs here. I removed all manhattan calculations and replaced it with reachable distance (because of islands).

Here is my final eval during the contest:

int GameState::getScore(int moveDir) {
	Point currPos = players[myId].pos;
	int score = 0;
	score += (10000 - players[1 - myId].life) * lifeMultiplier;
	score += spacesMultiplier * players[myId].getSpacesFromPosition();
	score += distanceFromEnemyPoints[currPos.x][currPos.y] * stayAwayFromEnemyMultiplier;
	score += 4 - moveDir;
	return score;
}

What I did great: In a short span I wrote a very optimized sim which runs sooooo fast. And a looot of debugging. Bugs Bugs everywhere.

What I could have done Better I forgot to fire torpedos at random positions in my final sim version (which explains my rank drop after switching to sim). Also I forgot to add FINISHER blow scoring in my eval.

What was amazing in this contest: I felt this is a very balanced game with no real meta at least until Silver. Lot of strategies can beat each other and itā€™s nice to see Miners kill Silencers and Silencers use nice combos for sneak attack. I didnā€™t sleep on the last day (similar to many CG last days) trying to get into Gold fixing bugs ignoring the scream of my body.

What could have been better: This was one of the games which takes lot of time to code for wood2. Because the input was large (plus the confusing spawn turn where you donā€™t read any inputs) and 3 possible outcomes: MOVE, SURFACE and TORPEDO as well as combination of those (MOVE+TORPEDO on the same turn). It would have been nice to have been a wood3 league with 3 lives with only MOVE and SURFACE commands with boss using SURFACE command often to kill himself.

7 Likes