Skip to content

Instantly share code, notes, and snippets.

@knowsuchagency
Last active March 23, 2023 13:54
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save knowsuchagency/39f7343096afda3c4149ba569201c517 to your computer and use it in GitHub Desktop.
Save knowsuchagency/39f7343096afda3c4149ba569201c517 to your computer and use it in GitHub Desktop.
Some example code for codingame smash the code contest. Lets you look up board state using (x, y) coordinates and un-fucks the print function.
from functools import partial
from collections import namedtuple, MutableMapping, Counter, deque
from operator import itemgetter, attrgetter
import sys
import random
# Auto-generated code below aims at helping you parse
# the standard input according to the problem statement.
# print function that writes to stderr
# therefore doesn't affect game logic
print = partial(print, file=sys.stderr)
# A coordinate tuple we can use to look up locations later
Coordinate = namedtuple('Coordinate', ['x', 'y'])
class Board(MutableMapping, dict):
"""
Dictionary reprsenting state of game board.
items in at particular coordinates can be accessed
via Board[(x, y)] or Board(Coordinate(x, y)]
"""
color_map = {
-1: 'empty',
0: 'blocked',
1: 'blue',
2: 'green',
3: 'pink',
4: 'red',
5: 'yellow'
}
def __init__(self):
self._empty_coordinates = []
self._red_coordinates = []
self._blue_coordinates = []
self._yellow_coordinates = []
self._green_coordinates = []
self._pink_coordinates = []
self._blocked_coordinates = []
# a flag to set whether we went left last or not
self._left_last = False
for y in range(12):
for x in range(6):
self[Coordinate(x, y)] = '.'
def __setitem__(self, key, value):
# coerse types so that they're all integers
# '.' values are converted to -1
if value == '.':
value = -1
else:
value = int(value)
coordinate = Coordinate._make(key)
x, y = coordinate
coordinate = Coordinate(int(x), int(y))
assert 0 <= coordinate.x <= 5, "x-axis out of range"
assert 0 <= coordinate.y <= 11, "y-axis out of range"
cache_map = {
-1: self._empty_coordinates,
0: self._blocked_coordinates,
1: self._blue_coordinates,
2: self._green_coordinates,
3: self._pink_coordinates,
4: self._red_coordinates,
5: self._yellow_coordinates,
}
# add coordinate to appropriate cache of coordinates
# remove coordinate from its previous list if we have it cached
for l in cache_map.values():
if coordinate in l:
l.remove(coordinate)
break
cache_map.get(value).append(coordinate)
dict.__setitem__(self,coordinate,value)
def __getitem__(self,key):
return dict.__getitem__(self,key)
def __delitem__(self, key):
dict.__delitem__(self,key)
def __iter__(self):
return dict.__iter__(self)
def __len__(self):
return dict.__len__(self)
def __contains__(self, x):
return dict.__contains__(self,x)
def __repr__(self):
"""
Return a string representation of the Board.
Replaces -1 with '.' for clarity
"""
rows = []
for y in range(12):
row = str()
for x in range(6):
value = self.get((x, y))
if value == -1:
value = '.'
else:
value = str(value)
row += value
rows.append(row)
rows = list(reversed(rows))
rows.append('Bottom left: {}'.format(str(self.bottom_left)))
rows.append('Bottom right: {}'.format(str(self.bottom_right)))
rows.append('Bottom six: {}'.format([str((x, y)) for x, y in self.bottom_six]))
return '\n'.join(rows)
@property
def bottom_left(self):
"""Return the leftmost, lowest coordinate that is empty."""
return min(self._empty_coordinates, key=attrgetter('y', 'x'))
@property
def bottom_right(self):
"""Return the leftmost, lowest coordinate that is empty."""
y = min(c.y for c in self.bottom_six)
x = max(c.x for c in self.bottom_six if c.y==y)
return Coordinate(x, y)
@property
def bottom_six(self):
"""Return the bottom 6 coordinates."""
coordinates = [self.lowest_empty_coordinate(c) for c in range(6)]
return sorted(coordinates)
def lowest_empty_coordinate(self, column):
"""Return the bottom-most coordinate for a given column."""
coordinates = [c for c in self._empty_coordinates if c.x==column]
return min(coordinates, key=attrgetter('y'))
def horizontally_adjacent(self, coordinate, value):
"""Return true if there are equal color adjacent to the value horizontally."""
x, y = coordinate
# find horizontal adjacency
horizontal = Counter(self.get((x, y), -1) for x in range(x-1, x+1))
most_common = horizontal.most_common(1)
return most_common[0] == value and most_common[1] > 1
def is_equal_below(self, coordinate, value):
"""Return True if the coordinate below is of the same value."""
x, y = coordinate
return self.get((x, y-1), -1) == value
def bottom_coordinates_with_horizontal_adjacency(self, value):
"""Return the lowest coordinates for which there are equal values horizontally"""
return [c for c in self.bottom_six if self.horizontally_adjacent(c, value)]
def coordinates_with_equal_value_below(self, value):
"""Return all possible coordinates that have the same value directly below for a given value."""
return [c for c in self.bottom_six if self.is_equal_below(c, value)]
def decide(self, bottom_color, verbose=False):
horizontals = self.bottom_coordinates_with_horizontal_adjacency(bottom_color)
verticals = self.coordinates_with_equal_value_below(bottom_color)
if verbose:
print('color is', bottom_color, Board.color_map[bottom_color])
print('horizontals:', horizontals)
print('verticals:', verticals)
if horizontals:
Board.move(horizontals[0], verbose)
elif verticals:
Board.move(verticals[0], verbose)
elif self._left_last:
Board.move(self.bottom_right, verbose)
else:
Board.move(self.bottom_left, verbose)
self._left_last=True
@staticmethod
def move(coordinate, verbose=True):
"""
Move to column.
assert 0 <= integer <=5, coerce it to string and write to stdout.
"""
column = coordinate.x
assert (isinstance(column, int) and 0 <= column <= 5)
if verbose:
print('moving to', coordinate)
print(str(column), file=sys.stdout)
@staticmethod
def color(n):
"""Return the color for a given number."""
return Board.color_map[n]
my_board = Board()
bitch_board = Board()
# game loop
while True:
inputs = deque()
for i in range(8):
# color_a: color of the first block
# color_b: color of the attached block
inputs.append([int(j) for j in input().split()])
bottom, top = inputs.popleft()
# print("my board:")
for row in range(12):
# since we start from the top, and work our way down, we need to
# reverse the number of the row
row = abs(11-row)
row_ = input()
row = [(Coordinate(col, row), i) for col, i in enumerate(row_)]
for coordinate, item in row:
my_board[coordinate] = item
# print(my_board)
my_board.decide(bottom, verbose=False)
# print("\n" + "bitch_board:")
for row in range(12):
# since we start from the top, and work our way down, we need to
# reverse the number of the row
row = abs(11-row)
row_ = input()
# row = [(Coordinate(col, row), i) for col, i in enumerate(row_)]
# for coordinate, item in row:
# bitch_board[coordinate] = item
# print(bitch_board)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment