gr-tradinggame 0.1.13__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
1
+ def hello() -> str:
2
+ return "Hello from uvrestructure!"
File without changes
@@ -0,0 +1,50 @@
1
+ from contextlib import redirect_stderr, redirect_stdout
2
+ import cloudpickle as pickle
3
+ import base64
4
+ from IPython.terminal.interactiveshell import TerminalInteractiveShell
5
+ import io
6
+
7
+
8
+ class Blackbox:
9
+ def __init__(self, source, name='play'):
10
+ self.name = name
11
+ self.stdout = io.StringIO()
12
+ self.stderr = io.StringIO()
13
+ with redirect_stderr(self.stderr), redirect_stdout(self.stdout):
14
+ self.shell = TerminalInteractiveShell()
15
+ out = self.shell.run_cell(source)
16
+ if out.error_before_exec is not None:
17
+ raise out.error_before_exec
18
+ if out.error_in_exec is not None:
19
+ raise out.error_in_exec
20
+ if not isinstance(name, str) or name not in self.shell.user_ns:
21
+ raise Exception(f"Your source code must define a function called `{self.name}`, but only has `{self.shell.user_ns.keys()}`")
22
+
23
+ def __call__(self, *args, **kwargs):
24
+ input_variable_name = '__magic_input__'
25
+ with redirect_stderr(self.stderr), redirect_stdout(self.stdout):
26
+ self.shell.user_ns[input_variable_name] = args, kwargs
27
+ out = self.shell.run_cell(f'{self.name}(*{input_variable_name}[0], **{input_variable_name}[1])')
28
+ if out.error_before_exec is not None:
29
+ raise out.error_before_exec
30
+ if out.error_in_exec is not None:
31
+ raise out.error_in_exec
32
+ return out.result
33
+
34
+
35
+ class Plackbox:
36
+ def __init__(self, source):
37
+ self.foo = pickle.loads(source)
38
+ self.stdout = io.StringIO()
39
+ self.stderr = io.StringIO()
40
+
41
+ def __call__(self, *args, **kwargs):
42
+ with redirect_stderr(self.stderr), redirect_stdout(self.stdout):
43
+ return self.foo(*args, **kwargs)
44
+
45
+
46
+ def generate_function(data):
47
+ if data[0] == 'p':
48
+ return pickle.loads(base64.b64decode(data[1:]))
49
+ else:
50
+ return Blackbox(base64.b64decode(data[1:]).decode('utf-8'))
@@ -0,0 +1,115 @@
1
+ import base64
2
+ import datetime
3
+ import random
4
+ import traceback
5
+ import requests
6
+ from requests.auth import HTTPBasicAuth
7
+ import cloudpickle as pickle
8
+ import timeit
9
+
10
+ from .blackbox import Plackbox, Blackbox
11
+
12
+
13
+ class Client:
14
+ def __init__(self, team_name, server=None, timeout=0.1):
15
+ self.team_name = team_name
16
+ if server:
17
+ self.url = "https://" + server + ".ngrok-free.app"
18
+ else:
19
+ self.url = None
20
+ self.timeout = timeout
21
+
22
+ def test(self, source_or_function, verbose=False, strict=False, allow_state=True):
23
+ return self._submit(source_or_function, strict=strict, submit=False, allow_state=allow_state, verbose=verbose)
24
+
25
+ def submit(self, source_or_function, allow_state=True):
26
+ return self._submit(source_or_function, strict=False, submit=True, allow_state=allow_state, verbose=False)
27
+
28
+ def _submit(self, source_or_function, strict, submit, allow_state, verbose):
29
+ if submit and not self.url:
30
+ print('Automatic submission not enabled. Please send an email with your snippet to the organizers.')
31
+ return
32
+ test_cases = [
33
+ ((1.5, 5, 1, 10, 1.3, [1.1, 2.3]), "generic inputs", None),
34
+ ((-1.5, 5, 1, 10, 1.3, [1.1, 2.3]), "negative reward", (False, 'It never makes sense to take a negative reward')),
35
+ ((0, 5, 1, 10, 1.3, [1.1, 2.3]), "zero rewards", (False, "It doesn't make sense to accept a lockout in return for no reward")),
36
+ ((1.5, 5, 1, 10, 1.3, []), "playing by yourself", None),
37
+ ((1.5, 5, 1, 10, -1, [-1.1, 2.3]), "negative score", None),
38
+ ((0.0001, 5, 10, 10, 1.3, [1.1, 2.3]), "no time left after this round", (True, 'There is no time left after this round, you should accept any reward you can get')),
39
+ ((0.0001, 0, 1, 10, 1.3, [1.1, 2.3]), "no lockout", (True, 'There is no lockout, you should accept any reward you can get')),
40
+ ]
41
+ if isinstance(source_or_function, str):
42
+ output = source_or_function
43
+ foo = Blackbox(output)
44
+ else:
45
+ output = pickle.dumps(source_or_function)
46
+ foo = Plackbox(output)
47
+ outputs = dict()
48
+ for j in range(3):
49
+ for i, (args, err, hint) in enumerate(test_cases):
50
+ test_str = f'Test {i} ("{err}"): f{args}'
51
+ if j == 0 and verbose:
52
+ print(test_str)
53
+ test_str = ''
54
+ try:
55
+ a = foo(*args)
56
+ if j == 0:
57
+ outputs[i] = a
58
+ else:
59
+ if a != outputs[i] and not allow_state:
60
+ print(test_str)
61
+ raise Exception(f"""You previously returned `{outputs[i]}` and are now returning `{a}`. If this is intentional, set `allow_state=True`""")
62
+ elif not isinstance(a, bool):
63
+ print(test_str)
64
+ raise Exception(f"""You should return `False` or `True` but you returned `{a}` of type {type(a)}""")
65
+ elif strict and hint is not None and a != hint[0]:
66
+ print(test_str)
67
+ raise Exception(hint[1])
68
+ except Exception:
69
+ print(test_str)
70
+ raise
71
+ if j == 0 and verbose:
72
+ print(f'\tSuccess -- returned {a}')
73
+ tic = timeit.default_timer()
74
+ for j in range(1_000):
75
+ T = int(1_000_000 * random.random())
76
+ t = int(random.random() * T)
77
+ lockout = int(10 * random.random())
78
+ reward = 100 * random.random()
79
+ score = reward * T * random.random()
80
+ scores = [reward * T * random.random() for _ in range(10)]
81
+ args = (reward, lockout, t, T, score, scores)
82
+ try:
83
+ a = foo(*args)
84
+ except Exception:
85
+ print(f'Random input {args}')
86
+ raise
87
+ else:
88
+ if not isinstance(a, bool):
89
+ print(f'Random input {args}')
90
+ raise Exception(f"""You should return `False` or `True` but returned `{a}` of type {type(a)}""")
91
+ toc = timeit.default_timer()
92
+ if toc - tic > max(1, (j + 1) * self.timeout):
93
+ raise Exception(f"""Your code is too slow. Should take {self.timeout}s per round but took {(toc - tic) / (j + 1):.3f}s""")
94
+ if submit:
95
+ self.fancy_submit(source_or_function)
96
+ else:
97
+ print("All tests passed. You're ready to call `submit`\n")
98
+
99
+ def fancy_submit(self, output):
100
+ if isinstance(output, str):
101
+ submission = 's' + base64.b64encode(output.encode('utf-8')).decode('utf-8')
102
+ else:
103
+ submission = 'p' + base64.b64encode(pickle.dumps(output)).decode('utf-8')
104
+ j = {"team": self.team_name, 'time': str(datetime.datetime.now()), 'submission': submission}
105
+ response = requests.post(
106
+ self.url + '/receive',
107
+ json=j,
108
+ auth=HTTPBasicAuth("colabuser", "secretcolab"),
109
+ )
110
+ try:
111
+ response.raise_for_status()
112
+ except Exception:
113
+ raise Exception("Couldn't connect to server. Please notify an organizer.")
114
+ else:
115
+ print('Submission successful: ', j['team'], j['time'])
@@ -0,0 +1,165 @@
1
+ import timeit
2
+ import numpy as np
3
+ import ipywidgets as widgets
4
+ import plotly.graph_objects as go
5
+ import pandas as pd
6
+ from IPython.display import clear_output, display
7
+ import time
8
+ import json
9
+
10
+ from .blackbox import generate_function
11
+
12
+
13
+ class CodingGame:
14
+ def __init__(
15
+ self, rounds=2000, lockout=5, plot_frequency=0.3, plot_width=1000, length_in_seconds=30, eliminate_slow_teams=False,
16
+ functions=None, submissions=None, additional_functions=None, random_draw_function='a', must_be_only_team=False
17
+ ):
18
+ if functions is None and submissions is None:
19
+ with open("submissions.json", "r") as f:
20
+ submissions = json.load(f)
21
+ if additional_functions is None:
22
+ additional_functions = {}
23
+ self.candidates = functions if functions is not None else CodingGame.clean(submissions)
24
+ self.candidates = {**self.candidates, **{x: generate_function(y) if isinstance(y, str) else y for (x, y) in additional_functions.items()}}
25
+ self.plot_frequency = plot_frequency
26
+ self.eliminate = eliminate_slow_teams
27
+ self.length = length_in_seconds
28
+ self.plot_width = plot_width
29
+ self.last_lockout = lockout
30
+ self.max_rounds = rounds
31
+ self.random_draw_function = random_draw_function
32
+ self.must_be_only_team = must_be_only_team
33
+ if isinstance(self.random_draw_function, str):
34
+ if self.random_draw_function.lower().strip() == 'a':
35
+ self.random_draw_function = lambda: np.random.exponential(10)
36
+ elif self.random_draw_function.lower().strip() == 'b':
37
+ self.random_draw_function = lambda: np.random.normal(-0.2, 1)
38
+ self.init_play()
39
+ self.initialize_ui()
40
+
41
+ @staticmethod
42
+ def clean(candidates):
43
+ return {
44
+ outer_key: generate_function(max(inner_dict.items(), key=lambda item: item[0])[1])
45
+ for outer_key, inner_dict in candidates.items()
46
+ }
47
+
48
+ def initialize_ui(self):
49
+ self.output = widgets.Output()
50
+ self.plot_output = widgets.Output(layout=dict(width='100%'))
51
+ self.game_ui = widgets.HBox(
52
+ [self.output, self.plot_output],
53
+ layout=widgets.Layout(
54
+ align_items='center',
55
+ justify_content='center',
56
+ width='100%'
57
+ )
58
+ )
59
+ top_spacer = widgets.Box(layout=widgets.Layout(flex='1 1 auto'))
60
+ bottom_spacer = widgets.Box(layout=widgets.Layout(flex='1 1 auto'))
61
+ self.vertical_box = widgets.VBox(
62
+ [top_spacer, self.game_ui, bottom_spacer],
63
+ layout=widgets.Layout(
64
+ height='100vh',
65
+ display='flex',
66
+ flex_flow='column',
67
+ align_items='center',
68
+ justify_content='center',
69
+ )
70
+ )
71
+
72
+ self.update_plot()
73
+
74
+ def update_plot(self):
75
+ fig = go.Figure()
76
+ for team in self.candidates:
77
+ n = self.current_round
78
+ step = int(n / 100 + 1)
79
+ fig.add_trace(go.Scatter(
80
+ x=list(range(self.current_round + 1))[::step],
81
+ y=self.team_scores[team][::step],
82
+ mode='lines',
83
+ name=team,
84
+ ))
85
+ fig.update_layout(showlegend=True, xaxis_title='Round', yaxis_title='Score', xaxis_range=[0, self.max_rounds], width=self.plot_width)
86
+ with self.plot_output:
87
+ clear_output(wait=True)
88
+ display(fig)
89
+
90
+ def start_new_round(self):
91
+ self.current_round += 1
92
+ self.last_number = self.random_draw_function()
93
+
94
+ def loop(self):
95
+ with self.output:
96
+ while self.current_round < self.max_rounds:
97
+ self.start_new_round()
98
+ eliminate = []
99
+ last_team_to_score = None
100
+ for team, btn in self.candidates.items():
101
+ args = (self.last_number, self.last_lockout, self.current_round, self.max_rounds, self.team_scores[team][-1], [y[-1] for (x, y) in self.team_scores.items() if x != team])
102
+ tic_team = timeit.default_timer()
103
+ took_action = btn(*args) and self.current_round > self.team_blocked_until[team]
104
+ toc_team = timeit.default_timer()
105
+ if self.eliminate and toc_team - tic_team > self.length / self.max_rounds / len(self.candidates):
106
+ eliminate.append(team)
107
+ score = self.last_number if took_action else 0
108
+ self.team_scores[team].append(self.team_scores[team][-1] + score)
109
+ if self.must_be_only_team and took_action and last_team_to_score is not None:
110
+ self.team_scores[team][-1] = self.team_scores[team][-2]
111
+ self.team_scores[last_team_to_score][-1] = self.team_scores[last_team_to_score][-2]
112
+ if took_action:
113
+ self.team_blocked_until[team] = self.current_round + self.last_lockout
114
+ last_team_to_score = team
115
+ for x in eliminate:
116
+ del self.candidates[x]
117
+ toc = timeit.default_timer()
118
+ target = self.start + self.current_round / self.max_rounds * self.length
119
+ if toc < target:
120
+ time.sleep(target - toc)
121
+ if toc > self.last_update + self.plot_frequency:
122
+ self.last_update = toc
123
+ self.update_plot()
124
+
125
+ self.update_plot()
126
+ df = (
127
+ pd.DataFrame(
128
+ {x: self.team_scores[x][-1] for x in self.team_scores}.items(),
129
+ columns=['Name', 'Score']
130
+ )
131
+ .sort_values('Score', ascending=False)
132
+ .reset_index(drop=True)
133
+ .rename(index=lambda x: x + 1)
134
+ .round(2)
135
+ )
136
+ display(df)
137
+
138
+ def init_play(self):
139
+ if self.random_draw_function is None:
140
+ random = np.random.default_rng(seed=None)
141
+ self.random_draw_function= lambda: random.pareto(3)
142
+ self.last_update = -2 ** 31
143
+ self.team_scores = {team: [0] for team in self.candidates}
144
+ self.team_blocked_until = {team: -1 for team in self.candidates}
145
+ self.last_number = None
146
+ self.current_round = 0
147
+
148
+ def play(self, countdown=0):
149
+
150
+ with self.output:
151
+ clear_output()
152
+ with self.plot_output:
153
+ clear_output()
154
+
155
+ display(self.vertical_box)
156
+ with self.output:
157
+ for i in range(countdown, 0, -1):
158
+ print(i)
159
+ time.sleep(1)
160
+ clear_output()
161
+ self.start = timeit.default_timer()
162
+ self.loop()
163
+
164
+ def _ipython_display_(self):
165
+ display(self.vertical_box)
@@ -0,0 +1,74 @@
1
+ import uuid
2
+ from flask import Flask, request, jsonify
3
+ from functools import wraps
4
+ import json
5
+ import base64
6
+ from collections import defaultdict
7
+ import threading
8
+
9
+ from .blackbox import generate_function
10
+ from .util import get_url
11
+
12
+
13
+ class GameServer:
14
+ def __init__(self):
15
+ self.name = str(uuid.uuid4())
16
+ self.submission_lock = threading.Lock()
17
+ self.USERNAME = "colabuser"
18
+ self.PASSWORD = "secretcolab"
19
+
20
+ self.submissions = defaultdict(lambda: defaultdict(dict))
21
+ try:
22
+ with open("submissions.json", 'r') as f:
23
+ submissions_loaded = json.load(f)
24
+ for team, team_submissions in submissions_loaded.items():
25
+ for time, team_submission in team_submissions.items():
26
+ self.submissions[team][time] = team_submission
27
+ except FileNotFoundError:
28
+ pass
29
+ else:
30
+ print("Loaded existing submissions:")
31
+ print(json.dumps(self.submissions, indent=4))
32
+
33
+ self.app = Flask(self.name)
34
+
35
+ def require_auth(f):
36
+ @wraps(f)
37
+ def decorated(*args, **kwargs):
38
+ auth = request.headers.get("Authorization")
39
+ error = None
40
+ if auth and auth.startswith("Basic "):
41
+ try:
42
+ decoded = base64.b64decode(auth.split(" ")[1]).decode("utf-8")
43
+ user, pw = decoded.split(":")
44
+ if user == self.USERNAME and pw == self.PASSWORD:
45
+ return f(*args, **kwargs)
46
+ except Exception as e:
47
+ print(e)
48
+ error = e
49
+ return jsonify({"error": "Unauthorized"}), 401 if error is None else jsonify({'error': str(error)}), 500
50
+ return decorated
51
+
52
+ @self.app.route("/receive", methods=["POST"])
53
+ @require_auth
54
+ def receive():
55
+ data = request.get_json()
56
+ print("Submission received:", data)
57
+ generate_function(data['submission'])
58
+ with self.submission_lock:
59
+ self.submissions[data['team']][data['time']] = data['submission']
60
+ with open("submissions.json", "w") as f:
61
+ json.dump(dict(self.submissions), f, indent=4)
62
+ print(json.dumps(
63
+ {
64
+ team_name: max(team_submissions.items(), key=lambda x: x[0])[0]
65
+ for (team_name, team_submissions) in self.submissions.items()
66
+ },
67
+ indent=4
68
+ ))
69
+ return jsonify({"status": "success"})
70
+
71
+ def run(self, force_restart=False):
72
+ server_id = get_url(force_restart)
73
+ print('Serving', server_id)
74
+ self.app.run(port=5000)
@@ -0,0 +1,43 @@
1
+ import time
2
+ import subprocess
3
+ import requests
4
+ from pyngrok import ngrok, conf
5
+
6
+ NGROK_API = "http://localhost:4040/api/tunnels"
7
+
8
+ def _cleanup_local_tunnels():
9
+ try:
10
+ r = requests.get(NGROK_API, timeout=1)
11
+ for t in r.json().get("tunnels", []):
12
+ old_url = t["public_url"]
13
+ print(f"NOTE: disconnecting and cleaning up {old_url} before serving new session.")
14
+ ngrok.disconnect(old_url)
15
+ except Exception:
16
+ pass
17
+
18
+ def _ensure_ngrok_running():
19
+ try:
20
+ requests.get(NGROK_API, timeout=1)
21
+ except Exception:
22
+ ngrok.install_ngrok()
23
+ subprocess.Popen(
24
+ [conf.get_default().ngrok_path, "http", "5000"],
25
+ stdout=subprocess.DEVNULL,
26
+ stderr=subprocess.DEVNULL,
27
+ start_new_session=True,
28
+ )
29
+ time.sleep(5)
30
+
31
+ def get_url(force_restart=False):
32
+ if force_restart:
33
+ _cleanup_local_tunnels()
34
+
35
+ _ensure_ngrok_running()
36
+
37
+ try:
38
+ r = requests.get(NGROK_API)
39
+ tunnels = r.json()["tunnels"]
40
+ public_url = tunnels[0]["public_url"]
41
+ return public_url.split('//')[1].split('.ngrok-free.app')[0]
42
+ except Exception as e:
43
+ raise RuntimeError("ngrok tunnel not available") from e
@@ -0,0 +1,136 @@
1
+ import numpy
2
+ import ipywidgets as widgets
3
+ from IPython.display import display, clear_output
4
+ import plotly.graph_objs as go
5
+ import pandas as pd
6
+
7
+
8
+ class ManualGame:
9
+ def __init__(self, team_names, max_rounds=30, lockout=3, width=1000, random_draw_function='a'):
10
+ self.team_names = team_names
11
+ self.max_rounds = max_rounds
12
+ self.lockout = lockout
13
+ self.random_draw_function = random_draw_function
14
+ if isinstance(self.random_draw_function, str):
15
+ if self.random_draw_function.lower().strip() == 'a':
16
+ self.random_draw_function = lambda: numpy.random.exponential(10)
17
+ elif self.random_draw_function.lower().strip() == 'b':
18
+ self.random_draw_function = lambda: numpy.random.normal(-0.2, 1)
19
+ self.width = width
20
+ self.initialize_ui()
21
+
22
+ def initialize_ui(self):
23
+ self.current_round = 0
24
+ self.team_scores = {team: [0] for team in self.team_names}
25
+ self.team_blocked_until = {team: -1 for team in self.team_names}
26
+ self.last_number = None
27
+ self.last_lockout = self.lockout
28
+ self.number_display = widgets.HTML(layout=dict(width='80%'))
29
+ self.team_buttons = {
30
+ team: widgets.ToggleButton(description=team, value=False, tooltip=team, layout=dict(width='50%'))
31
+ for team in self.team_names
32
+ }
33
+ self.submit_button = widgets.Button(description="Submit Selections", button_style='success', layout=dict(width='50%'))
34
+ self.output = widgets.Output()
35
+ self.controls = widgets.VBox([
36
+ self.number_display,
37
+ *self.team_buttons.values(),
38
+ self.submit_button,
39
+ self.output,
40
+ ],
41
+ layout=dict(width='40%', align_items='center')
42
+ )
43
+ self.plot_output = widgets.Output(layout=dict(width='100%'))
44
+
45
+ def update_plot():
46
+ fig = go.Figure()
47
+ for team in self.team_names:
48
+ fig.add_trace(go.Scatter(
49
+ x=list(range(self.current_round + 1)),
50
+ y=self.team_scores[team],
51
+ mode='lines+markers',
52
+ name=team
53
+ ))
54
+ fig.update_layout(xaxis_title='Round', yaxis_title='Score', xaxis_range=[0, self.max_rounds], width=self.width)
55
+ with self.plot_output:
56
+ clear_output(wait=True)
57
+ display(fig)
58
+
59
+ def start_new_round():
60
+ self.current_round += 1
61
+ self.last_number = self.random_draw_function()
62
+
63
+ self.number_display.value = f"""
64
+ <div style='text-align:center; padding: 10px;'>
65
+ <h1 style='margin-bottom: 0;'>Round {self.current_round} / {self.max_rounds} <br> Lockout: {self.last_lockout}</h1>
66
+ <h2 style='color:darkred; font-size: 48px; margin-top: 10px;'>Reward: {self.last_number:.2f}</h2>
67
+ </div>
68
+ """
69
+
70
+ for team, btn in self.team_buttons.items():
71
+ blocked = self.team_blocked_until[team] - self.current_round
72
+ is_blocked = blocked >= 0
73
+ btn.disabled = is_blocked
74
+ btn.value = False
75
+ btn.description = f'❌ {team} ({blocked + 1})' if is_blocked else team
76
+
77
+ def on_submit(_):
78
+ with self.output:
79
+ clear_output()
80
+ for team, btn in self.team_buttons.items():
81
+ took_action = btn.value and not btn.disabled
82
+ score = self.last_number if took_action else 0
83
+ self.team_scores[team].append(self.team_scores[team][-1] + score)
84
+ if took_action:
85
+ self.team_blocked_until[team] = self.current_round + self.last_lockout
86
+ update_plot()
87
+ if self.current_round < self.max_rounds:
88
+ start_new_round()
89
+ else:
90
+ df = (
91
+ pd.DataFrame(
92
+ {x: self.team_scores[x][-1] for x in self.team_scores}.items(),
93
+ columns=['Name', 'Score']
94
+ )
95
+ .sort_values('Score', ascending=False)
96
+ .reset_index(drop=True)
97
+ .rename(index=lambda x: x + 1)
98
+ .round(2)
99
+ )
100
+ self.number_display.value = ''
101
+ self.submit_button.layout.display = 'none'
102
+ for x in self.team_buttons.values():
103
+ x.layout.display = 'none'
104
+ with self.output:
105
+ display(df)
106
+
107
+ self.submit_button.on_click(on_submit)
108
+ self.game_ui = widgets.HBox(
109
+ [self.controls, self.plot_output],
110
+ layout=widgets.Layout(
111
+ align_items='center',
112
+ justify_content='center',
113
+ border='solid 1px gray',
114
+ width='100%'
115
+ )
116
+ )
117
+
118
+ top_spacer = widgets.Box(layout=widgets.Layout(flex='1 1 auto'))
119
+ bottom_spacer = widgets.Box(layout=widgets.Layout(flex='1 1 auto'))
120
+ self.vertical_box = widgets.VBox(
121
+ [top_spacer, self.game_ui, bottom_spacer],
122
+ layout=widgets.Layout(
123
+ height='100vh',
124
+ display='flex',
125
+ flex_flow='column',
126
+ align_items='center',
127
+ justify_content='center',
128
+ )
129
+ )
130
+
131
+ update_plot()
132
+ start_new_round()
133
+
134
+ def _ipython_display_(self):
135
+ display(self.vertical_box)
136
+
File without changes
@@ -0,0 +1,43 @@
1
+ Metadata-Version: 2.4
2
+ Name: gr_tradinggame
3
+ Version: 0.1.13
4
+ Summary: Add your description here
5
+ Author-email: Soeren Wolfers <soeren.wolfers@gresearch.com>, Ajay Mittal <ajaymittal2001@gmail.com>
6
+ Requires-Python: >=3.11
7
+ Requires-Dist: cloudpickle==3.1.1
8
+ Requires-Dist: flask-ngrok==0.0.25
9
+ Requires-Dist: flask==3.1.1
10
+ Requires-Dist: ipython==7.34.0
11
+ Requires-Dist: ipywidgets==7.7.1
12
+ Requires-Dist: numpy>=2.0.2
13
+ Requires-Dist: pandas>=2.2.2
14
+ Requires-Dist: plotly==5.10.0
15
+ Requires-Dist: pyngrok==7.2.8
16
+ Requires-Dist: requests>=2.32.3
17
+ Description-Content-Type: text/markdown
18
+
19
+ # Trading game for recruitment events.
20
+
21
+ ## Installation
22
+
23
+ `pip install gr-tradinggame`
24
+
25
+ ### Manual game
26
+
27
+ 1. Run the code in `notebooks/example_manual.ipynb` in a notebook (looks best on Colab, with fullscreen cell display). [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/soerenwolfers/gr_tradinggame/blob/main/notebooks/example_manual.ipynb)
28
+
29
+ 2. Have teams shout / show their decisions and enter them by clicking buttons.
30
+
31
+ ### Coding game
32
+
33
+ 1. Run the code in `notebooks/example_server.ipynb`. [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/soerenwolfers/gr_tradinggame/blob/main/notebooks/example_server.ipynb)
34
+
35
+
36
+
37
+ 2. The output will contain `Serving <id>`. Give that `id` to the teams and have them test and submit their solutions with that `id` as in `notebooks/example_client.ipynb`. [![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/soerenwolfers/gr_tradinggame/blob/main/notebooks/example_client.ipynb)
38
+
39
+ 3. Run the remaining cells in your server notebook to see who wins.
40
+
41
+
42
+
43
+
@@ -0,0 +1,12 @@
1
+ gr_tradinggame/__init__.py,sha256=f_XkRXIp0URwPWFmsMMKwN12zySh3mCtr55hiM3ZrYI,59
2
+ gr_tradinggame/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ gr_tradinggame/coding/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
4
+ gr_tradinggame/coding/blackbox.py,sha256=tOcgtQB9lgT6ZG0S_IT8wszZlLL6gZx4UT8TBk5g5r0,1959
5
+ gr_tradinggame/coding/client.py,sha256=h1QlRC1jmFim-IdCclMA9fJa3i-mG7LA7AdEIUd1BvI,5427
6
+ gr_tradinggame/coding/gui.py,sha256=lXgMj3qz5BNVhpYapPLAsHWBimoidgrP5S_LxDnsKsg,6841
7
+ gr_tradinggame/coding/server.py,sha256=s3Z4QaPAC6-w4rLhZFHaASJzp-SvjxB3HjRm164PTOs,2791
8
+ gr_tradinggame/coding/util.py,sha256=Z4lGVhhMOPGZJwjZ3Wu5a8LAfG0vIyHd7KEFaOE6b2o,1243
9
+ gr_tradinggame/manual/__init__.py,sha256=ml818maV8iA2J9S8VWrIGyiKRbRFuGcFoXB7LIkME2A,5551
10
+ gr_tradinggame-0.1.13.dist-info/METADATA,sha256=Vm-9lmOyI8aycdH9wINx4gWGU-dXqY4Sl700VYrdtiA,1760
11
+ gr_tradinggame-0.1.13.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
12
+ gr_tradinggame-0.1.13.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.28.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any