Skip to content

Commit bee5a77

Browse files
committed
first commit
0 parents  commit bee5a77

File tree

12 files changed

+546
-0
lines changed

12 files changed

+546
-0
lines changed

.gitignore

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
.DS_Store
2+
readme_assets
3+
4+
# Byte-compiled / optimized / DLL files
5+
__pycache__/
6+
*.py[cod]
7+
*$py.class
8+
9+
# C extensions
10+
*.so
11+
12+
# Distribution / packaging
13+
.Python
14+
env/
15+
build/
16+
develop-eggs/
17+
dist/
18+
downloads/
19+
eggs/
20+
.eggs/
21+
lib/
22+
lib64/
23+
parts/
24+
sdist/
25+
var/
26+
*.egg-info/
27+
.installed.cfg
28+
*.egg
29+
30+
# PyInstaller
31+
# Usually these files are written by a python script from a template
32+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
33+
*.manifest
34+
*.spec
35+
36+
# Installer logs
37+
pip-log.txt
38+
pip-delete-this-directory.txt
39+
40+
# Unit test / coverage reports
41+
htmlcov/
42+
.tox/
43+
.coverage
44+
.coverage.*
45+
.cache
46+
nosetests.xml
47+
coverage.xml
48+
*,cover
49+
.hypothesis/
50+
51+
# Translations
52+
*.mo
53+
*.pot
54+
55+
# Django stuff:
56+
*.log
57+
local_settings.py
58+
59+
# Flask stuff:
60+
instance/
61+
.webassets-cache
62+
63+
# Scrapy stuff:
64+
.scrapy
65+
66+
# Sphinx documentation
67+
docs/_build/
68+
69+
# PyBuilder
70+
target/
71+
72+
# IPython Notebook
73+
.ipynb_checkpoints
74+
75+
# pyenv
76+
.python-version
77+
78+
# celery beat schedule file
79+
celerybeat-schedule
80+
81+
# dotenv
82+
.env
83+
84+
# virtualenv
85+
venv/
86+
ENV/
87+
88+
# Spyder project settings
89+
.spyderproject
90+
91+
# Rope project settings
92+
.ropeproject

Procfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
web: gunicorn app:app --log-file=-

README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Squill
2+
3+
Squill is a game where you write a program to control troops and battle your friend!
4+
5+
Status: Works locally and looks less ugly than it did before but still lots of work to do before actually playable....
6+
7+
## Docs
8+
9+
You will code a JavaScript strategy file with one function called 'turn'. It will have the following signature:
10+
11+
**turn(color, matrix, strength, x, y)**
12+
13+
14+
Your function should return **heal()**, **attack(DIRECTION, NUMBER_OF_TROOPS)**, or **move(DIRECTION, NUMBER_OF_TROOPS)**
15+
16+
17+
DIRECTION must be "U" "D" "L" or "R", for up/down/left/right.
18+
NUMBER_OF_TROOPS should be an integer, indicating the number of troops you would like to move. You cannot move all your troops. It costs one troop to attack and you must have at least one troop protecting your territory. Therefore, you must have at least three troops to attack succesfully.
19+
20+
21+
Below is the template of a strategy file.
22+
23+
**function turn(color, matrix, strength, x, y){ < YOUR CODE HERE >}**
24+
25+
Here is a very simple example of a valid file.
26+
27+
**function turn(color, matrix, strength, x, y){ return heal(); }**
28+
29+
All that should be in your file should be your function definition (and comments if desired).
30+
31+
32+
Save your JS file and upload it when needed. When both you and your opponent have uploaded your files, you can hit 'Battle!' which will show you your results.
33+
34+
## An Important Note
35+
**There are also some more rules, but I haven't gotten around to writing them.**

app.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
from flask import Flask, request, render_template
2+
import random
3+
import json
4+
from gamelogic import core_game
5+
app = Flask(__name__)
6+
7+
# Super Global
8+
index_to_col = {0: "red", 1: "blue"}
9+
file_states = dict()
10+
user_col_states = dict()
11+
full_game_state = dict()
12+
reset_state = dict()
13+
14+
@app.route("/reset/<num>")
15+
def reset(num):
16+
del file_states[num]
17+
del user_col_states[num]
18+
del full_game_state[num]
19+
return "reset button clicked"
20+
21+
@app.route("/online/<num>")
22+
def online(num):
23+
return render_template("test.html")
24+
25+
@app.route("/docs/<num>")
26+
def docs(num):
27+
return render_template("docs.html")
28+
29+
@app.route("/upload/<num>", methods=['POST'])
30+
def upload(num):
31+
if num not in file_states:
32+
file_states[num] = dict()
33+
if num not in user_col_states:
34+
user_col_states[num] = []
35+
username, code_text = request.form["username"], request.form["code_text"]
36+
if username not in file_states[num] and len(file_states[num]) == 2:
37+
return "Too many users: code was not submitted"
38+
file_states[num][username] = code_text
39+
if username not in [uname for color, uname in user_col_states[num]]:
40+
color = index_to_col[len(file_states[num]) - 1]
41+
user_col_states[num].append((color, username))
42+
return json.dumps(user_col_states[num])
43+
44+
@app.route("/info/<num>")
45+
def info(num):
46+
if num in user_col_states:
47+
return json.dumps(user_col_states[num])
48+
return json.dumps([])
49+
50+
@app.route("/init/<num>")
51+
def game(num):
52+
if num not in full_game_state:
53+
full_game_state[num] = []
54+
red_code = list(file_states[num].items())[0][1]
55+
blue_code = list(file_states[num].items())[1][1]
56+
boards = core_game(red_code, blue_code, full_game_state[num])
57+
return json.dumps(boards)
58+
59+
if __name__ == '__main__':
60+
app.run(debug=True, use_reloader=True)
61+

gamelogic.py

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
def core_game(red_code, blue_code, state=None):
2+
# Imports & Init
3+
import random
4+
import json
5+
#from pygame import draw, display, Rect, event, QUIT, Color, time, Surface, font
6+
from node_vm2 import VM
7+
#pygame.init()
8+
#pygame.font.init()
9+
10+
# URL Specific Setup
11+
turn_code = dict()
12+
turn_code["red"]= red_code
13+
turn_code["blue"] = blue_code
14+
15+
# Globals
16+
#FONT = font.SysFont("Arial", 24)
17+
SQUARE_WID = 75
18+
BOARD_WID = 10
19+
#WHITE = Color(255, 255, 255)
20+
#BLACK = Color(0, 0, 0)
21+
#RED = Color(200, 0, 0)
22+
#BLUE = Color(0, 0, 200)
23+
player_dict = dict()
24+
#col_dict = {"blue": BLUE, "red": RED, "white": WHITE}
25+
dir_to_delta = { "U":(0, -1), "D":(0, 1), "L":(-1,0), "R": (1,0)}
26+
preload_code = open("preload.js").read()
27+
28+
# Utils
29+
def valid_sq(x, y):
30+
return x > -1 and x < BOARD_WID and y > -1 and y < BOARD_WID
31+
32+
def copy_2D(mat):
33+
return [[i for i in row] for row in mat]
34+
35+
def copy_3D(mat):
36+
return[copy_2D(i) for i in mat]
37+
38+
def r_ind():
39+
return random.randint(0,BOARD_WID-1)
40+
41+
42+
# Player Class
43+
class Player:
44+
def __init__(self, color):
45+
self.color = color
46+
player_dict[color] = self
47+
48+
def turn(self, mat, strength, x, y):
49+
ref = {"mat":copy_2D(mat), "x":x, "y":y}
50+
try:
51+
with VM() as vm:
52+
turn_call = "turn({}, {}, {}, {}, {})".format(" '{}' ".format(self.color), json.dumps(mat), strength, x, y)
53+
call_str = "{} {} {}".format(preload_code, turn_code[self.color], turn_call)
54+
action = vm.run(call_str)
55+
if type(action) == list:
56+
return tuple(action)
57+
except:
58+
print("Error: {}".format(self.color))
59+
60+
# Core Functions
61+
def execute(move, mat, x, y, col):
62+
move_id = move[0]
63+
move_info = move[1:]
64+
65+
if move_id == "move":
66+
direction = move_info[0]
67+
dx, dy = dir_to_delta[direction]
68+
num = int(move_info[1])
69+
if valid_sq(x+dx, y+dy):
70+
sq, to_sq = mat[x][y], mat[x+dx][y+dy]
71+
to_col = to_sq[0]
72+
units = min(sq[1], num)
73+
if to_col in (col, "white"):
74+
sq[1] -= units
75+
to_sq[0] = col
76+
to_sq[1] += units
77+
78+
elif move_id == "attack":
79+
direction = move_info[0]
80+
dx, dy = dir_to_delta[direction]
81+
num = int(move_info[1])
82+
if valid_sq(x+dx, y+dy):
83+
sq, to_sq = mat[x][y], mat[x+dx][y+dy]
84+
to_col = to_sq[0]
85+
units = min(sq[1], num)
86+
if to_col not in (col, "white"):
87+
if sq[1] - units < 2:
88+
return
89+
enemy_units = to_sq[1]
90+
del_units = units - enemy_units
91+
sq[1] -= units + 1
92+
if del_units == 0:
93+
to_sq[0], to_sq[1] = "white", 0
94+
elif del_units > 0:
95+
to_sq[0], to_sq[1] = col, del_units
96+
else:
97+
to_sq[1] -= units
98+
99+
elif move_id == "heal":
100+
mat[x][y][1] += 1
101+
102+
def setup():
103+
Player("blue")
104+
Player("red")
105+
col_mat = [[["white", 0] for i in range(BOARD_WID)] for j in range(BOARD_WID)]
106+
col_mat[r_ind()][r_ind()] = ["blue", 299]
107+
col_mat[r_ind()][r_ind()] = ["red", 299]
108+
return col_mat
109+
110+
def main():
111+
col_mat = setup()
112+
#screen = display.set_mode((750, 750))
113+
#clock = pygame.time.Clock()
114+
counter = 0
115+
while counter < 10:
116+
#for ev in event.get():
117+
# if ev.type == QUIT:
118+
# break
119+
#screen.fill((0, 0, 0))
120+
next_mat = copy_2D(col_mat)
121+
for i, row in enumerate(col_mat):
122+
for j, tup in enumerate(row):
123+
if "white" not in tup:
124+
col, strength = tup
125+
move = player_dict[col].turn(copy_2D(next_mat), strength, i, j)
126+
if move:
127+
execute(move, next_mat, i, j, col)
128+
129+
col_mat = next_mat
130+
if state != None:
131+
state.append(copy_3D(col_mat))
132+
counter += 1
133+
print(counter)
134+
#clock.tick(500)
135+
136+
main()
137+
print("finished")
138+
return state
139+
140+
141+
def local_test():
142+
red_code = open("turn_red.js", "r").read()
143+
blue_code = open("turn_red.js", "r").read()
144+
core_game(red_code, blue_code)
145+
146+
#local_test()
147+
148+
149+
150+
151+
152+
153+
154+

preload.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//Utils
2+
function max(n1, n2){
3+
if(n1>n2){
4+
return n1;
5+
}
6+
return n2;
7+
}
8+
//Moves
9+
function move(dir, num) {
10+
return["move", dir, max(0, num)]
11+
}
12+
function heal(){
13+
return ["heal"];
14+
}
15+
function attack(dir, num){
16+
return ["attack", dir, max(0, num)]
17+
}

requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Flask
2+
gunicorn

runtime.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
python-3.5.1

0 commit comments

Comments
 (0)