Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rip #47

Open
wants to merge 66 commits into
base: main
Choose a base branch
from
Open

Rip #47

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
230fba1
Add or update the Azure App Service build and deployment workflow config
Diluent67 Oct 4, 2023
711fb67
New
Oct 4, 2023
d993a08
Remove the Azure App Service build and deployment workflow config
Diluent67 Oct 5, 2023
525fb7d
Transferred over progress
Oct 7, 2023
c7e6fff
Merge branch 'main' of https://github.com/Diluent67/battlesnake-g
Oct 7, 2023
35fec40
New changes
Oct 11, 2023
3cadee8
Changed main.py
Oct 16, 2023
5b2ae59
New changes pt 2
Oct 16, 2023
1342f46
New changes pt 3
Oct 16, 2023
e235abb
New changes pt 3
Oct 16, 2023
9828217
New changes pt 4
Oct 16, 2023
51326ff
New changes pt 5
Oct 17, 2023
b59e505
New changes pt 6
Oct 17, 2023
243a79c
New changes pt 7
Oct 17, 2023
32f5e1a
New changes pt 8
Oct 17, 2023
331d42b
New changes pt 9
Oct 17, 2023
d738f0e
Changes pt 10
Oct 18, 2023
1368c06
Changes pt 11 where we attempt to reduce runtime
Oct 18, 2023
b069eb3
Changes pt 11 remove pandas
Oct 18, 2023
293cead
Changes pt 11 where we attempt to reduce runtime 2
Oct 18, 2023
a58c8cb
Changes pt 11 where we attempt to reduce runtime 3
Oct 18, 2023
ce557d1
NO PRINT
Oct 18, 2023
d7a6d28
PUlled back
Oct 18, 2023
42d49c0
PUlled back 2
Oct 18, 2023
1538cf0
Pen
Oct 18, 2023
ad77d0f
Snake engine
Oct 19, 2023
a5ac837
Trying out mult
Oct 19, 2023
b1d2ab2
Reverted lol
Oct 19, 2023
7529f0f
Networkx
Oct 19, 2023
3fec865
Merge branch 'main' of https://github.com/Diluent67/battlesnake-g
Oct 19, 2023
95374ed
chanes12
Oct 19, 2023
730a41f
chanes12
Oct 19, 2023
475b7b6
main
Oct 19, 2023
058c948
HM pt 12
Oct 19, 2023
55fd6c1
No edge kill
Oct 19, 2023
721a1ea
Don't get trapped
Oct 19, 2023
c19d162
Don't get trapped edge
Oct 19, 2023
c8abc55
Final changes here
Oct 20, 2023
64aca08
Initial draft of repo
Oct 23, 2023
6562a45
Hm new revamp
Oct 24, 2023
e331ae6
New
Oct 24, 2023
7c1f42b
New 2
Oct 24, 2023
eb4436e
A*
Oct 25, 2023
0b30871
A*
Oct 25, 2023
f08930f
Reverted to previous version yesterday
Oct 25, 2023
454acf3
Reverted to previous version yesterday New
Oct 25, 2023
16b3eea
Reverted back to New
Oct 25, 2023
f422e6c
Reverted back to my OG changes
Oct 25, 2023
ffeda8a
Fixed bug with Dijkstra
Oct 25, 2023
7595321
Bug with Dijkstra vs Manhattan
Oct 26, 2023
f914259
Edge kill corner cases
Oct 30, 2023
1f3ac83
fixed bug where our snake would die
Oct 30, 2023
9fb6176
Fixed another bug
Oct 30, 2023
eeca73a
Fixed another bug with edge control
Oct 30, 2023
7333d73
Fixed another bug with simulate move
Oct 30, 2023
7b4dfe5
Fixed another bug with simulate move
Oct 30, 2023
02906c1
Can stall to not die
Oct 31, 2023
e1cfd06
Added a bug fix for networkx
Oct 31, 2023
c00f74c
More time-efficient
Oct 31, 2023
e7cf666
Incr depth in the beginning
Oct 31, 2023
1fb120e
Another edge kill going down bug
Oct 31, 2023
6086031
Integrated Rick's
Oct 31, 2023
ef3809b
Fixing depth = 6
Oct 31, 2023
92fd19a
test
Oct 31, 2023
b8e2c64
FORK
Oct 31, 2023
51333b0
MEH
Oct 31, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added .gitmodules
Empty file.
135 changes: 135 additions & 0 deletions a_star_search_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
game = {
"game": {
"id": "totally-unique-game-id",
"ruleset": {
"name": "standard",
"version": "v1.1.15",
"settings": {
"foodSpawnChance": 15,
"minimumFood": 1,
"hazardDamagePerTurn": 14
}
},
"map": "standard",
"source": "league",
"timeout": 500
},
"turn": 14,
"board": {
"height": 11,
"width": 11,
"food": [
{"x": 2, "y": 0},
{"x": 1, "y": 9},
{"x": 4, "y": 6}
],
"hazards": [
{"x": 3, "y": 2}
],
"snakes": [
{
"id": "snake-508e96ac-94ad-11ea-bb37",
"name": "My Snake",
"health": 54,
"body": [
{"x": 5, "y": 4},
{"x": 5, "y": 5},
{"x": 5, "y": 6},
{"x": 5, "y": 7},
{"x": 5, "y": 8},
{"x": 5, "y": 9},
{"x": 5, "y": 10},
# {"x": 5, "y": 7},
# {"x": 5, "y": 8},
# {"x": 4, "y": 9}
],
"latency": "111",
"head": {"x": 0, "y": 0},
"length": 3,
"shout": "why are we shouting??",
"customizations":{
"color":"#FF0000",
"head":"pixel",
"tail":"pixel"
}
},
# {
# "id": "snake-b67f4906-94ae-11ea-bb37",
# "name": "Another Snake",
# "health": 16,
# "body": [
# {"x": 5, "y": 4},
# {"x": 5, "y": 3},
# {"x": 6, "y": 3},
# {"x": 6, "y": 2}
# ],
# "latency": "222",
# "head": {"x": 5, "y": 4},
# "length": 4,
# "shout": "I'm not really sure...",
# "customizations":{
# "color":"#26CF04",
# "head":"silly",
# "tail":"curled"
# }
# }
]
},
"you": {
"id": "snake-508e96ac-94ad-11ea-bb37",
"name": "My Snake",
"health": 54,
"body": [
{"x": 1, "y": 0},
{"x": 1, "y": 1},
{"x": 1, "y": 2},
{"x": 1, "y": 3},
{"x": 1, "y": 4},
{"x": 2, "y": 4},
{"x": 3, "y": 4},
{"x": 4, "y": 4},
{"x": 4, "y": 3},
{"x": 4, "y": 2},
{"x": 4, "y": 1},
{"x": 5, "y": 1},
{"x": 5, "y": 0},
{"x": 6, "y": 0},
],
"latency": "111",
"head": {"x": 1, "y": 0},
"length": 3,
"shout": "why are we shouting??",
"customizations": {
"color":"#FF0000",
"head":"pixel",
"tail":"pixel"
}
}
}


from helper_battlesnake import *

my_head = {"x": 1, "y": 0}
safe_moves = obvious_moves(game, my_head)
for safe in safe_moves:
f = flood_fill(game, look_ahead(my_head, safe))
print(safe, f)
print("=" * 50)

food = game['board']['food']
food_dist = []
food_moves = []
# Big idea: loop through all food and find the shortest path using A* search
for food_loc in food:
best_path, best_dist = a_star_search(game, my_head.copy(), food_loc)
print(f"Food: {food_loc}")
print(f"Shortest dist: {best_dist}")
if best_path is not None:
food_dist.append(best_dist)
lesgo = snake_compass(my_head, best_path[-2])
food_moves.append(lesgo)

f = flood_fill(game, look_ahead(my_head, lesgo))
print(f"Direction {lesgo} at {f}")
print(best_dist * 11 * 11 / f ** 2.25)
Binary file added battlesnake.exe
Binary file not shown.
49 changes: 49 additions & 0 deletions battlesnake_test.py

Large diffs are not rendered by default.

85 changes: 21 additions & 64 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,91 +5,48 @@
# | | \ / __ \| | | | | |_\ ___/ \___ \| | \/ __ \| <\ ___/
# |________/(______/__| |__| |____/\_____>______>___|__(______/__|__\\_____>
#
# This file can be a nice home for your Battlesnake logic and helper functions.
#
# To get you started we've included code to prevent your Battlesnake from moving backwards.
# For more info see docs.battlesnake.com

import random
import typing
from snake_engine import Battlesnake


# info is called when you create your Battlesnake on play.battlesnake.com
# and controls your Battlesnake's appearance
# TIP: If you open your Battlesnake URL in a browser you should see this data
def info() -> typing.Dict:
"""
info is called when you create your Battlesnake on play.battlesnake.com
and controls your Battlesnake's appearance
TIP: If you open your Battlesnake URL in a browser you should see this data
"""
print("INFO")

return {
"apiversion": "1",
"author": "", # TODO: Your Battlesnake Username
"color": "#888888", # TODO: Choose color
"head": "default", # TODO: Choose head
"tail": "default", # TODO: Choose tail
"author": "G",
"color": "#3333ff",
"head": "ski",
"tail": "mystic-moon",
}


# start is called when your Battlesnake begins a game
def start(game_state: typing.Dict):
"""start is called when your Battlesnake begins a game"""
print("GAME START")


# end is called when your Battlesnake finishes a game
def end(game_state: typing.Dict):
"""end is called when your Battlesnake finishes a game"""
print("GAME OVER\n")


# move is called on every turn and returns your next move
# Valid moves are "up", "down", "left", or "right"
# See https://docs.battlesnake.com/api/example-move for available data
def move(game_state: typing.Dict) -> typing.Dict:

is_move_safe = {"up": True, "down": True, "left": True, "right": True}

# We've included code to prevent your Battlesnake from moving backwards
my_head = game_state["you"]["body"][0] # Coordinates of your head
my_neck = game_state["you"]["body"][1] # Coordinates of your "neck"

if my_neck["x"] < my_head["x"]: # Neck is left of head, don't move left
is_move_safe["left"] = False

elif my_neck["x"] > my_head["x"]: # Neck is right of head, don't move right
is_move_safe["right"] = False

elif my_neck["y"] < my_head["y"]: # Neck is below head, don't move down
is_move_safe["down"] = False

elif my_neck["y"] > my_head["y"]: # Neck is above head, don't move up
is_move_safe["up"] = False

# TODO: Step 1 - Prevent your Battlesnake from moving out of bounds
# board_width = game_state['board']['width']
# board_height = game_state['board']['height']

# TODO: Step 2 - Prevent your Battlesnake from colliding with itself
# my_body = game_state['you']['body']

# TODO: Step 3 - Prevent your Battlesnake from colliding with other Battlesnakes
# opponents = game_state['board']['snakes']

# Are there any safe moves left?
safe_moves = []
for move, isSafe in is_move_safe.items():
if isSafe:
safe_moves.append(move)

if len(safe_moves) == 0:
print(f"MOVE {game_state['turn']}: No safe moves detected! Moving down")
return {"move": "down"}

# Choose a random move from the safe ones
next_move = random.choice(safe_moves)

# TODO: Step 4 - Move towards food instead of random, to regain health and survive longer
# food = game_state['board']['food']

print(f"MOVE {game_state['turn']}: {next_move}")
return {"move": next_move}
"""
move is called on every turn and returns your next move
Valid moves are "up", "down", "left", or "right"
See https://docs.battlesnake.com/api/example-move for available data
"""
game = Battlesnake(game_state)
optimal_move = game.optimal_move()
print(f"MOVE {game_state['turn']}: {optimal_move}")
return {"move": optimal_move}


# Start server when `python main.py` is run
Expand Down
125 changes: 125 additions & 0 deletions networkx_tree.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import networkx as nx
import random


def hierarchy_pos(G, root=None, width=25., vert_gap=0.025, vert_loc=0, leaf_vs_root_factor=1):
'''
If the graph is a tree this will return the positions to plot this in a
hierarchical layout.

Based on Joel's answer at https://stackoverflow.com/a/29597209/2966723,
but with some modifications.

We include this because it may be useful for plotting transmission trees,
and there is currently no networkx equivalent (though it may be coming soon).

There are two basic approaches we think of to allocate the horizontal
location of a node.

- Top down: we allocate horizontal space to a node. Then its ``k``
descendants split up that horizontal space equally. This tends to result
in overlapping nodes when some have many descendants.
- Bottom up: we allocate horizontal space to each leaf node. A node at a
higher level gets the entire space allocated to its descendant leaves.
Based on this, leaf nodes at higher levels get the same space as leaf
nodes very deep in the tree.

We use both of these approaches simultaneously with ``leaf_vs_root_factor``
determining how much of the horizontal space is based on the bottom up
or top down approaches. ``0`` gives pure bottom up, while 1 gives pure top
down.


:Arguments:

**G** the graph (must be a tree)

**root** the root node of the tree
- if the tree is directed and this is not given, the root will be found and used
- if the tree is directed and this is given, then the positions will be
just for the descendants of this node.
- if the tree is undirected and not given, then a random choice will be used.

**width** horizontal space allocated for this branch - avoids overlap with other branches

**vert_gap** gap between levels of hierarchy

**vert_loc** vertical location of root

**leaf_vs_root_factor**

xcenter: horizontal location of root
'''
if not nx.is_tree(G):
raise TypeError('cannot use hierarchy_pos on a graph that is not a tree')

if root is None:
if isinstance(G, nx.DiGraph):
root = next(iter(nx.topological_sort(G))) # allows back compatibility with nx version 1.11
else:
root = random.choice(list(G.nodes))

def _hierarchy_pos(G, root, leftmost, width, leafdx=2, vert_gap=0.2, vert_loc=0,
xcenter=0.5, rootpos=None,
leafpos=None, parent=None):
'''
see hierarchy_pos docstring for most arguments

pos: a dict saying where all nodes go if they have been assigned
parent: parent of this branch. - only affects it if non-directed

'''

if rootpos is None:
rootpos = {root: (xcenter, vert_loc)}
else:
rootpos[root] = (xcenter, vert_loc)
if leafpos is None:
leafpos = {}
children = list(G.neighbors(root))
leaf_count = 0
if not isinstance(G, nx.DiGraph) and parent is not None:
children.remove(parent)
if len(children) != 0:
node_size = width / 50

rootdx = width / len(children)
nextx = xcenter - width / 2 - rootdx / 2
for child in children:
nextx += rootdx
rootpos, leafpos, newleaves = _hierarchy_pos(G, child, leftmost + leaf_count * leafdx,
width=rootdx, leafdx=leafdx,
vert_gap=vert_gap, vert_loc=vert_loc - vert_gap,
xcenter=nextx, rootpos=rootpos, leafpos=leafpos,
parent=root)
leaf_count += newleaves

leftmostchild = min((x for x, y in [leafpos[child] for child in children]))
rightmostchild = max((x for x, y in [leafpos[child] for child in children]))
leafpos[root] = ((leftmostchild + rightmostchild) / 2, vert_loc)
else:
leaf_count = 1
leafpos[root] = (leftmost, vert_loc)
# pos[root] = (leftmost + (leaf_count-1)*dx/2., vert_loc)
# print(leaf_count)
return rootpos, leafpos, leaf_count

xcenter = width / 2.
if isinstance(G, nx.DiGraph):
leafcount = len([node for node in nx.descendants(G, root) if G.out_degree(node) == 0])
elif isinstance(G, nx.Graph):
leafcount = len([node for node in nx.node_connected_component(G, root) if G.degree(node) == 1 and node != root])
rootpos, leafpos, leaf_count = _hierarchy_pos(G, root, 0, width,
leafdx=width * 1. / leafcount,
vert_gap=vert_gap,
vert_loc=vert_loc,
xcenter=xcenter)
pos = {}
for node in rootpos:
pos[node] = (
leaf_vs_root_factor * leafpos[node][0] + (1 - leaf_vs_root_factor) * rootpos[node][0], leafpos[node][1])
# pos = {node:(leaf_vs_root_factor*x1+(1-leaf_vs_root_factor)*x2, y1) for ((x1,y1), (x2,y2)) in (leafpos[node], rootpos[node]) for node in rootpos}
xmax = max(x for x, y in pos.values())
for node in pos:
pos[node] = (pos[node][0] * width / xmax, pos[node][1])
return pos
5 changes: 5 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
Flask==2.3.2

numpy~=1.26.0
pandas~=2.1.1
matplotlib~=3.8.0
networkx~=3.1
Loading