code-battles 1.6.4 → 1.7.1

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.
Files changed (55) hide show
  1. package/dist/cjs/index.js +2234 -2004
  2. package/dist/cjs/styles.css +2 -1
  3. package/dist/cjs/types/components/DataTable.d.ts +21 -0
  4. package/dist/cjs/types/components/ResultStaticsTable.d.ts +3 -0
  5. package/dist/cjs/types/configuration.d.ts +2 -2
  6. package/dist/cjs/types/utilities.d.ts +2 -2
  7. package/dist/code_battles/__init__.py +1 -1
  8. package/dist/code_battles/battles.py +69 -28
  9. package/dist/code_battles/utilities.py +12 -3
  10. package/dist/esm/index.js +2235 -2005
  11. package/dist/esm/styles.css +2 -1
  12. package/dist/esm/types/components/DataTable.d.ts +21 -0
  13. package/dist/esm/types/components/ResultStaticsTable.d.ts +3 -0
  14. package/dist/esm/types/configuration.d.ts +2 -2
  15. package/dist/esm/types/utilities.d.ts +2 -2
  16. package/dist/index.d.ts +2 -2
  17. package/dist/pyscript/codemirror-eKulCBrd.js +2 -0
  18. package/dist/pyscript/codemirror-eKulCBrd.js.map +1 -0
  19. package/dist/pyscript/codemirror_commands-BVu_0Pnj.js +2 -0
  20. package/dist/pyscript/codemirror_commands-BVu_0Pnj.js.map +1 -0
  21. package/dist/pyscript/codemirror_lang-python-a2LxSo5G.js +2 -0
  22. package/dist/pyscript/codemirror_lang-python-a2LxSo5G.js.map +1 -0
  23. package/dist/pyscript/codemirror_language-_2pXlKJ9.js +2 -0
  24. package/dist/pyscript/codemirror_language-_2pXlKJ9.js.map +1 -0
  25. package/dist/pyscript/codemirror_view-DMW9kQlJ.js +2 -0
  26. package/dist/pyscript/codemirror_view-DMW9kQlJ.js.map +1 -0
  27. package/dist/pyscript/core-DezwbZpG.js +4 -0
  28. package/dist/pyscript/core-DezwbZpG.js.map +1 -0
  29. package/dist/pyscript/core.js +1 -1
  30. package/dist/pyscript/deprecations-manager-B1bDno27.js +2 -0
  31. package/dist/pyscript/deprecations-manager-B1bDno27.js.map +1 -0
  32. package/dist/pyscript/donkey-DNl0ASkM.js +2 -0
  33. package/dist/pyscript/donkey-DNl0ASkM.js.map +1 -0
  34. package/dist/pyscript/error-DmRE4Y-7.js +2 -0
  35. package/dist/pyscript/error-DmRE4Y-7.js.map +1 -0
  36. package/dist/pyscript/index-DkgvWIf-.js +2 -0
  37. package/dist/pyscript/index-DkgvWIf-.js.map +1 -0
  38. package/dist/pyscript/mpy-BoY0tVRD.js +2 -0
  39. package/dist/pyscript/mpy-BoY0tVRD.js.map +1 -0
  40. package/dist/pyscript/py-DsQqgZuM.js +2 -0
  41. package/dist/pyscript/py-DsQqgZuM.js.map +1 -0
  42. package/dist/pyscript/py-editor-DZkG_or6.js +2 -0
  43. package/dist/pyscript/py-editor-DZkG_or6.js.map +1 -0
  44. package/dist/pyscript/py-game-D0Z4YnzZ.js +2 -0
  45. package/dist/pyscript/py-game-D0Z4YnzZ.js.map +1 -0
  46. package/dist/pyscript/py-terminal-DYHK7LJ0.js +2 -0
  47. package/dist/pyscript/py-terminal-DYHK7LJ0.js.map +1 -0
  48. package/dist/pyscript/service-worker.js +1 -0
  49. package/dist/pyscript/storage.js +1 -1
  50. package/dist/pyscript/storage.js.map +1 -1
  51. package/dist/pyscript/xterm-CVv2fC4I.js +2 -0
  52. package/dist/pyscript/xterm-CVv2fC4I.js.map +1 -0
  53. package/dist/pyscript/zip-D13-hp9W.js +2 -0
  54. package/dist/pyscript/zip-D13-hp9W.js.map +1 -0
  55. package/package.json +14 -14
@@ -2,4 +2,5 @@
2
2
  pre[class*="language-"].line-numbers{position:relative;padding-left:3.8em;counter-reset:linenumber;}pre[class*="language-"].line-numbers>code{position:relative;white-space:inherit;}.line-numbers .line-numbers-rows{position:absolute;pointer-events:none;top:0;font-size:100%;left:-3.8em;width:3em;letter-spacing:-1px;border-right:1px solid #999;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;}.line-numbers-rows>span{display:block;counter-increment:linenumber;}.line-numbers-rows>span:before{content:counter(linenumber);color:#999;display:block;padding-right:0.8em;text-align:right;}
3
3
  code[class*="language-"],pre[class*="language-"]{color:black;background:none;text-shadow:0 1px white;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none;}pre[class*="language-"]::-moz-selection,pre[class*="language-"] ::-moz-selection,code[class*="language-"]::-moz-selection,code[class*="language-"] ::-moz-selection{text-shadow:none;background:#b3d4fc;}pre[class*="language-"]::selection,pre[class*="language-"] ::selection,code[class*="language-"]::selection,code[class*="language-"] ::selection{text-shadow:none;background:#b3d4fc;}@media print{code[class*="language-"],pre[class*="language-"]{text-shadow:none;}}pre[class*="language-"]{padding:1em;margin:.5em 0;overflow:auto;}:not(pre)>code[class*="language-"],pre[class*="language-"]{background:#f5f2f0;}:not(pre)>code[class*="language-"]{padding:.1em;border-radius:.3em;white-space:normal;}.token.comment,.token.prolog,.token.doctype,.token.cdata{color:slategray;}.token.punctuation{color:#999;}.token.namespace{opacity:.7;}.token.property,.token.tag,.token.boolean,.token.number,.token.constant,.token.symbol,.token.deleted{color:#905;}.token.selector,.token.attr-name,.token.string,.token.char,.token.builtin,.token.inserted{color:#690;}.token.operator,.token.entity,.token.url,.language-css .token.string,.style .token.string{color:#9a6e3a;background:hsla(0,0%,100%,.5);}.token.atrule,.token.attr-value,.token.keyword{color:#07a;}.token.function,.token.class-name{color:#DD4A68;}.token.regex,.token.important,.token.variable{color:#e90;}.token.important,.token.bold{font-weight:bold;}.token.italic{font-style:italic;}.token.entity{cursor:help;}
4
4
  py-config,py-script,py-splashscreen,.py-error{display:none;}h1,h2,h3,h4,h5,h6,p{margin:0;}
5
- .token.operator{background:inherit !important;}pre[class*="language-"],code[class*="language-"]{color:#d4d4d4;font-size:13px;text-shadow:none;font-family:Menlo,Monaco,Consolas,"Andale Mono","Ubuntu Mono","Courier New",monospace;direction:ltr;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none;}pre[class*="language-"]::selection,code[class*="language-"]::selection,pre[class*="language-"] *::selection,code[class*="language-"] *::selection{text-shadow:none;background:#264f78;}@media print{pre[class*="language-"],code[class*="language-"]{text-shadow:none;}}pre[class*="language-"]{padding:1em;margin:0.5em 0;overflow:auto;background:#1e1e1e;}:not(pre)>code[class*="language-"]{padding:0.1em 0.3em;border-radius:0.3em;color:#db4c69;background:#1e1e1e;}.namespace{opacity:0.7;}.token.doctype .token.doctype-tag{color:#569cd6;}.token.doctype .token.name{color:#9cdcfe;}.token.comment,.token.prolog{color:#6a9955;}.token.punctuation,.language-html .language-css .token.punctuation,.language-html .language-javascript .token.punctuation{color:#d4d4d4;}.token.property,.token.tag,.token.boolean,.token.number,.token.constant,.token.symbol,.token.inserted,.token.unit{color:#b5cea8;}.token.selector,.token.attr-name,.token.string,.token.char,.token.builtin,.token.deleted{color:#ce9178;}.language-css .token.string.url{text-decoration:underline;}.token.operator,.token.entity{color:#d4d4d4;}.token.operator.arrow{color:#569cd6;}.token.atrule{color:#ce9178;}.token.atrule .token.rule{color:#c586c0;}.token.atrule .token.url{color:#9cdcfe;}.token.atrule .token.url .token.function{color:#dcdcaa;}.token.atrule .token.url .token.punctuation{color:#d4d4d4;}.token.keyword{color:#569cd6;}.token.keyword.module,.token.keyword.control-flow{color:#c586c0;}.token.function,.token.function .token.maybe-class-name{color:#dcdcaa;}.token.regex{color:#d16969;}.token.important{color:#569cd6;}.token.italic{font-style:italic;}.token.constant{color:#9cdcfe;}.token.class-name,.token.maybe-class-name{color:#4ec9b0;}.token.console{color:#9cdcfe;}.token.parameter{color:#9cdcfe;}.token.interpolation{color:#9cdcfe;}.token.punctuation.interpolation-punctuation{color:#569cd6;}.token.boolean{color:#569cd6;}.token.property,.token.variable,.token.imports .token.maybe-class-name,.token.exports .token.maybe-class-name{color:#9cdcfe;}.token.selector{color:#d7ba7d;}.token.escape{color:#d7ba7d;}.token.tag{color:#569cd6;}.token.tag .token.punctuation{color:#808080;}.token.cdata{color:#808080;}.token.attr-name{color:#9cdcfe;}.token.attr-value,.token.attr-value .token.punctuation{color:#ce9178;}.token.attr-value .token.punctuation.attr-equals{color:#d4d4d4;}.token.entity{color:#569cd6;}.token.namespace{color:#4ec9b0;}pre[class*="language-javascript"],code[class*="language-javascript"],pre[class*="language-jsx"],code[class*="language-jsx"],pre[class*="language-typescript"],code[class*="language-typescript"],pre[class*="language-tsx"],code[class*="language-tsx"]{color:#9cdcfe;}pre[class*="language-css"],code[class*="language-css"]{color:#ce9178;}pre[class*="language-html"],code[class*="language-html"]{color:#d4d4d4;}.language-regex .token.anchor{color:#dcdcaa;}.language-html .token.punctuation{color:#808080;}pre[class*="language-"]>code[class*="language-"]{position:relative;z-index:1;}.line-highlight.line-highlight{background:#f7ebc6;box-shadow:inset 5px 0 0 #f7d87c;z-index:0;}
5
+ .token.operator{background:inherit !important;}pre[class*="language-"],code[class*="language-"]{color:#d4d4d4;font-size:13px;text-shadow:none;font-family:Menlo,Monaco,Consolas,"Andale Mono","Ubuntu Mono","Courier New",monospace;direction:ltr;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none;}pre[class*="language-"]::selection,code[class*="language-"]::selection,pre[class*="language-"] *::selection,code[class*="language-"] *::selection{text-shadow:none;background:#264f78;}@media print{pre[class*="language-"],code[class*="language-"]{text-shadow:none;}}pre[class*="language-"]{padding:1em;margin:0.5em 0;overflow:auto;background:#1e1e1e;}:not(pre)>code[class*="language-"]{padding:0.1em 0.3em;border-radius:0.3em;color:#db4c69;background:#1e1e1e;}.namespace{opacity:0.7;}.token.doctype .token.doctype-tag{color:#569cd6;}.token.doctype .token.name{color:#9cdcfe;}.token.comment,.token.prolog{color:#6a9955;}.token.punctuation,.language-html .language-css .token.punctuation,.language-html .language-javascript .token.punctuation{color:#d4d4d4;}.token.property,.token.tag,.token.boolean,.token.number,.token.constant,.token.symbol,.token.inserted,.token.unit{color:#b5cea8;}.token.selector,.token.attr-name,.token.string,.token.char,.token.builtin,.token.deleted{color:#ce9178;}.language-css .token.string.url{text-decoration:underline;}.token.operator,.token.entity{color:#d4d4d4;}.token.operator.arrow{color:#569cd6;}.token.atrule{color:#ce9178;}.token.atrule .token.rule{color:#c586c0;}.token.atrule .token.url{color:#9cdcfe;}.token.atrule .token.url .token.function{color:#dcdcaa;}.token.atrule .token.url .token.punctuation{color:#d4d4d4;}.token.keyword{color:#569cd6;}.token.keyword.module,.token.keyword.control-flow{color:#c586c0;}.token.function,.token.function .token.maybe-class-name{color:#dcdcaa;}.token.regex{color:#d16969;}.token.important{color:#569cd6;}.token.italic{font-style:italic;}.token.constant{color:#9cdcfe;}.token.class-name,.token.maybe-class-name{color:#4ec9b0;}.token.console{color:#9cdcfe;}.token.parameter{color:#9cdcfe;}.token.interpolation{color:#9cdcfe;}.token.punctuation.interpolation-punctuation{color:#569cd6;}.token.boolean{color:#569cd6;}.token.property,.token.variable,.token.imports .token.maybe-class-name,.token.exports .token.maybe-class-name{color:#9cdcfe;}.token.selector{color:#d7ba7d;}.token.escape{color:#d7ba7d;}.token.tag{color:#569cd6;}.token.tag .token.punctuation{color:#808080;}.token.cdata{color:#808080;}.token.attr-name{color:#9cdcfe;}.token.attr-value,.token.attr-value .token.punctuation{color:#ce9178;}.token.attr-value .token.punctuation.attr-equals{color:#d4d4d4;}.token.entity{color:#569cd6;}.token.namespace{color:#4ec9b0;}pre[class*="language-javascript"],code[class*="language-javascript"],pre[class*="language-jsx"],code[class*="language-jsx"],pre[class*="language-typescript"],code[class*="language-typescript"],pre[class*="language-tsx"],code[class*="language-tsx"]{color:#9cdcfe;}pre[class*="language-css"],code[class*="language-css"]{color:#ce9178;}pre[class*="language-html"],code[class*="language-html"]{color:#d4d4d4;}.language-regex .token.anchor{color:#dcdcaa;}.language-html .token.punctuation{color:#808080;}pre[class*="language-"]>code[class*="language-"]{position:relative;z-index:1;}.line-highlight.line-highlight{background:#f7ebc6;box-shadow:inset 5px 0 0 #f7d87c;z-index:0;}
6
+ .control{width:100%;padding:10px;cursor:pointer;}.control:hover{background-color:light-dark(var(--mantine-color-gray-0),var(--mantine-color-dark-6));}
@@ -0,0 +1,21 @@
1
+ import React from "react";
2
+ import "./DataTable.css";
3
+ export interface DataTableData {
4
+ head: string[];
5
+ body: string[][];
6
+ }
7
+ declare const DataTable: ({ tableName, data, renderValue, renderHead, disableSort, hideIfEmpty, selectable, selectedRows, setSelectedRows, defaultSort, defaultReversed, stickyFirstColumn, }: {
8
+ tableName: string;
9
+ data: DataTableData;
10
+ renderValue?: (rowIndex: number, columnName: string, value: string) => React.ReactNode;
11
+ renderHead?: (columnName: string, columnIndex: number) => React.ReactNode;
12
+ disableSort?: boolean;
13
+ hideIfEmpty?: boolean;
14
+ selectable?: boolean;
15
+ selectedRows?: number[];
16
+ setSelectedRows?: React.Dispatch<React.SetStateAction<number[]>>;
17
+ defaultSort?: number;
18
+ defaultReversed?: boolean;
19
+ stickyFirstColumn?: boolean;
20
+ }) => React.JSX.Element;
21
+ export default DataTable;
@@ -0,0 +1,3 @@
1
+ import React from "react";
2
+ declare const ResultStatisticsTable: () => React.JSX.Element;
3
+ export default ResultStatisticsTable;
@@ -3,13 +3,12 @@ import type { Auth } from "firebase/auth";
3
3
  import type { Firestore } from "firebase/firestore";
4
4
  interface CodeBattlesRequiredConfiguration {
5
5
  firebase: any;
6
- maps: string[];
6
+ parameters: Record<string, string[]>;
7
7
  }
8
8
  interface CodeBattlesDatesConfiguration {
9
9
  locale?: string;
10
10
  firstDayOfWeek?: DayOfWeek;
11
11
  weekendDays?: DayOfWeek[];
12
- timezone?: string;
13
12
  }
14
13
  interface CodeBattlesOptionalConfiguration {
15
14
  primaryColor: string;
@@ -19,6 +18,7 @@ interface CodeBattlesOptionalConfiguration {
19
18
  authentication: Auth;
20
19
  runningCountOptions?: number[];
21
20
  dates?: CodeBattlesDatesConfiguration;
21
+ parameterIcons?: Record<string, string>;
22
22
  }
23
23
  export interface CodeBattlesConfiguration extends CodeBattlesRequiredConfiguration, Partial<CodeBattlesOptionalConfiguration> {
24
24
  }
@@ -1,6 +1,6 @@
1
1
  export interface RoundInfo {
2
2
  players: string[];
3
- map: string;
3
+ parameters: Record<string, string>;
4
4
  }
5
5
  export declare const getLocalStorage: (key: string, defaultValue?: {}) => any;
6
6
  export declare const setLocalStorage: (key: string, value?: {}) => void;
@@ -10,6 +10,6 @@ export declare const getRank: (tournamentInfo: any, team: string, pointModifier:
10
10
  export declare const updatePointModifier: () => void;
11
11
  export declare const toPlacing: (n: number) => string;
12
12
  export declare const zeroPad: (s: string, l: number) => string;
13
- export declare const runNoUI: (map: string, apis: Record<string, any>, playerBots: string[], seed: string, verbose: boolean) => void;
13
+ export declare const runNoUI: (parameters: Record<string, string>, apis: Record<string, any>, playerBots: string[], seed: string, verbose: boolean) => void;
14
14
  export declare const tryUntilSuccess: (f: () => void, timeout?: number) => void;
15
15
  export declare const downloadFile: (filename: string, mimeType: string, contents: string) => void;
@@ -1,7 +1,7 @@
1
1
  import sys
2
2
 
3
- from code_battles.utilities import GameCanvas, Alignment, is_web, is_worker
4
3
  from code_battles.battles import CodeBattles
4
+ from code_battles.utilities import Alignment, GameCanvas, is_web, is_worker
5
5
 
6
6
 
7
7
  def run_game(battles: CodeBattles):
@@ -1,29 +1,29 @@
1
1
  import asyncio
2
2
  import base64
3
- from dataclasses import dataclass
4
3
  import datetime
4
+ import gzip
5
5
  import json
6
6
  import math
7
- import time
8
- from random import Random
9
7
  import sys
8
+ import time
10
9
  import traceback
11
- import gzip
10
+ import typing
11
+ from dataclasses import dataclass
12
+ from random import Random
13
+ from typing import Any, Dict, Generic, List, Optional, Set, Tuple, TypeVar, Union
12
14
  from urllib.parse import quote
13
15
 
14
- from typing import Any, Dict, Generic, List, Optional, Set, Tuple, TypeVar
15
- import typing
16
16
  from code_battles.utilities import (
17
17
  GameCanvas,
18
18
  console_log,
19
19
  download_image,
20
+ is_web,
20
21
  is_worker,
21
22
  navigate,
22
23
  set_results,
23
24
  show_alert,
24
25
  show_download,
25
26
  web_only,
26
- is_web,
27
27
  )
28
28
 
29
29
  try:
@@ -39,7 +39,7 @@ PlayerRequestsType = TypeVar("PlayerRequestsType")
39
39
 
40
40
  @dataclass
41
41
  class Simulation:
42
- map: str
42
+ parameters: Dict[str, str]
43
43
  player_names: str
44
44
  game: str
45
45
  version: str
@@ -53,7 +53,7 @@ class Simulation:
53
53
  gzip.compress(
54
54
  json.dumps(
55
55
  {
56
- "map": self.map,
56
+ "parameters": self.parameters,
57
57
  "playerNames": self.player_names,
58
58
  "game": self.game,
59
59
  "version": self.version,
@@ -73,7 +73,9 @@ class Simulation:
73
73
  def load(file: str):
74
74
  contents: Dict[str, Any] = json.loads(gzip.decompress(base64.b64decode(file)))
75
75
  return Simulation(
76
- contents["map"],
76
+ contents["parameters"]
77
+ if "parameters" in contents
78
+ else {"map": contents["map"]},
77
79
  contents["playerNames"],
78
80
  contents["game"],
79
81
  contents["version"],
@@ -105,6 +107,8 @@ class CodeBattles(
105
107
 
106
108
  player_names: List[str]
107
109
  """The name of the players. This is populated before any of the overridable methods run."""
110
+ parameters: Dict[str, str]
111
+ """The parameters of the simulation. This is populated before any of the overridable methods run."""
108
112
  map: str
109
113
  """The name of the map. This is populated before any of the overridable methods run."""
110
114
  map_image: "js.Image"
@@ -231,6 +235,15 @@ class CodeBattles(
231
235
 
232
236
  pass
233
237
 
238
+ def get_statistics(self) -> Dict[str, Union[int, float]]:
239
+ """
240
+ Optional method to return statistics, called after the game ends.
241
+
242
+ When running multiple no UI simulations, you can use this to view the simulations in a table.
243
+ """
244
+
245
+ return {}
246
+
234
247
  def configure_extra_width(self) -> int:
235
248
  """Optionally add extra height to the right of the boards. 0 by default."""
236
249
 
@@ -358,12 +371,13 @@ class CodeBattles(
358
371
  await ff.load()
359
372
  document.fonts.add(ff)
360
373
 
361
- def run_bot_method(self, player_index: int, method_name: str):
374
+ def run_bot_method(self, player_index: int, method_name: str) -> float:
362
375
  """
363
- Runs the specifid method of the given player.
376
+ Runs the specified method of the given player and returns the time it took (in seconds).
364
377
 
365
378
  Upon exception, shows an alert (does not terminate the bot).
366
379
  """
380
+ start = time.time()
367
381
 
368
382
  assert player_index in self.active_players
369
383
 
@@ -392,6 +406,9 @@ class CodeBattles(
392
406
  "fa-solid fa-exclamation",
393
407
  )
394
408
 
409
+ end = time.time()
410
+ return end - start
411
+
395
412
  def eliminate_player(self, player_index: int, reason=""):
396
413
  """Eliminate the specified player for the specified reason from the simulation."""
397
414
 
@@ -468,7 +485,7 @@ class CodeBattles(
468
485
 
469
486
  If ``force`` is set, will play the sound even if the simulation is not :attr:`verbose`.
470
487
  """
471
- from js import window, Audio
488
+ from js import Audio, window
472
489
 
473
490
  if not force and not self.verbose:
474
491
  return
@@ -521,7 +538,7 @@ class CodeBattles(
521
538
 
522
539
  @web_only
523
540
  def _initialize(self):
524
- from js import window, document
541
+ from js import document, window
525
542
  from pyscript.ffi import create_proxy
526
543
 
527
544
  window.addEventListener("resize", create_proxy(lambda _: self._resize_canvas()))
@@ -565,7 +582,7 @@ class CodeBattles(
565
582
 
566
583
  def _run_webworker_simulation(
567
584
  self,
568
- map: str,
585
+ parameters: Dict[str, str],
569
586
  player_names_str: str,
570
587
  player_codes_str: str,
571
588
  seed: Optional[int] = None,
@@ -573,10 +590,12 @@ class CodeBattles(
573
590
  from pyscript import sync
574
591
 
575
592
  # JS to Python
593
+ parameters = json.loads(parameters)
576
594
  player_names = json.loads(player_names_str)
577
595
  player_codes = json.loads(player_codes_str)
578
596
 
579
- self.map = map
597
+ self.parameters = parameters
598
+ self.map = parameters.get("map")
580
599
  self.player_names = player_names
581
600
  self.background = True
582
601
  self.console_visible = False
@@ -589,7 +608,10 @@ class CodeBattles(
589
608
  decisions = self._make_decisions()
590
609
  logs = self._logs
591
610
  alerts = self._alerts
611
+ log = self.log
612
+ self.log = lambda *args, **kwargs: None
592
613
  self.apply_decisions(decisions)
614
+ self.log = log
593
615
 
594
616
  sync.update_step(
595
617
  base64.b64encode(decisions).decode(),
@@ -620,7 +642,8 @@ class CodeBattles(
620
642
  contents = f.read()
621
643
  simulation = Simulation.load(contents)
622
644
  seed = simulation.seed
623
- self.map = simulation.map
645
+ self.parameters = simulation.parameters
646
+ self.map = simulation.parameters.get("map")
624
647
  self.player_names = simulation.player_names
625
648
  decisions = simulation.decisions
626
649
  player_codes = ["" for _ in simulation.player_names]
@@ -684,12 +707,15 @@ class CodeBattles(
684
707
 
685
708
  try:
686
709
  simulation = Simulation.load(str(contents))
710
+ parameters = "&".join(
711
+ [f"{p}={quote(v)}" for p, v in simulation.parameters.items()]
712
+ )
687
713
  navigate(
688
- f"/simulation/{simulation.map}/{','.join([quote(player_name) for player_name in simulation.player_names])}?seed={simulation.seed}"
714
+ f"/simulation/{','.join([quote(player_name) for player_name in simulation.player_names])}?seed={simulation.seed}&{parameters}"
689
715
  )
690
716
  self.alert(
691
717
  "Loaded simulation file!",
692
- f"{', '.join(simulation.player_names)} competed in {simulation.map} at {simulation.timestamp}",
718
+ f"{', '.join(simulation.player_names)} competed with {simulation.parameters} at {simulation.timestamp}",
693
719
  "blue",
694
720
  "fa-solid fa-file-code",
695
721
  0,
@@ -713,9 +739,10 @@ class CodeBattles(
713
739
  while document.getElementById("loader") is None:
714
740
  await asyncio.sleep(0.01)
715
741
  self._initialize()
716
- self.map = simulation.map
742
+ self.parameters = simulation.parameters
743
+ self.map = self.parameters.get("map")
717
744
  self.map_image = await download_image(
718
- self.configure_map_image_url(simulation.map)
745
+ self.configure_map_image_url(self.map)
719
746
  )
720
747
  self.player_names = simulation.player_names
721
748
  self.background = False
@@ -744,7 +771,7 @@ class CodeBattles(
744
771
  @web_only
745
772
  async def _start_simulation_async(
746
773
  self,
747
- map: str,
774
+ parameters: Dict[str, str],
748
775
  player_codes: List[str],
749
776
  player_names: List[str],
750
777
  background: bool,
@@ -758,15 +785,19 @@ class CodeBattles(
758
785
  # JS to Python
759
786
  player_names = [str(x) for x in player_names]
760
787
  player_codes = [str(x) for x in player_codes]
788
+ parameters = parameters.to_py()
761
789
 
762
790
  try:
763
791
  render_status = document.getElementById("render-status")
764
792
  if render_status is not None:
765
793
  render_status.textContent = "Rendering: Initializing..."
766
794
 
767
- self.map = map
795
+ self.parameters = parameters
796
+ self.map = parameters.get("map")
768
797
  self.player_names = player_names
769
- self.map_image = await download_image(self.configure_map_image_url(map))
798
+ self.map_image = await download_image(
799
+ self.configure_map_image_url(self.map)
800
+ )
770
801
  self.background = background
771
802
  self.console_visible = console_visible
772
803
  self.verbose = verbose
@@ -794,7 +825,10 @@ class CodeBattles(
794
825
  self._worker = await workers["worker"]
795
826
  self._worker.update_step = self._update_step
796
827
  self._worker._run_webworker_simulation(
797
- map, json.dumps(player_names), json.dumps(player_codes), self._seed
828
+ json.dumps(parameters),
829
+ json.dumps(player_names),
830
+ json.dumps(player_codes),
831
+ self._seed,
798
832
  )
799
833
 
800
834
  if self.background:
@@ -824,7 +858,7 @@ class CodeBattles(
824
858
 
825
859
  def _get_simulation(self):
826
860
  return Simulation(
827
- self.map,
861
+ self.parameters,
828
862
  self.player_names,
829
863
  self.__class__.__name__,
830
864
  self.configure_version(),
@@ -842,7 +876,7 @@ class CodeBattles(
842
876
  is_over_str: str,
843
877
  should_pause_str: str,
844
878
  ):
845
- from js import window, document
879
+ from js import document, window
846
880
 
847
881
  now = time.time()
848
882
  decisions = base64.b64decode(str(decisions_str))
@@ -1020,7 +1054,12 @@ class CodeBattles(
1020
1054
  if len(self.active_players) == 1:
1021
1055
  self._eliminated.append(self.active_players[0])
1022
1056
  set_results(
1023
- self.player_names, self._eliminated[::-1], self.map, self.verbose
1057
+ self.player_names,
1058
+ self._seed,
1059
+ self._eliminated[::-1],
1060
+ self.get_statistics(),
1061
+ self.parameters,
1062
+ self.verbose,
1024
1063
  )
1025
1064
  if not self.background:
1026
1065
  self.render()
@@ -1111,3 +1150,5 @@ class CodeBattles(
1111
1150
  0,
1112
1151
  )
1113
1152
  )
1153
+ else:
1154
+ await asyncio.sleep(0.0005)
@@ -3,9 +3,9 @@
3
3
  import asyncio
4
4
  import math
5
5
  import sys
6
- from typing import Callable, List, Union
7
6
  from enum import Enum
8
7
  from functools import wraps
8
+ from typing import Callable, Dict, List, Union
9
9
 
10
10
  try:
11
11
  import js
@@ -73,12 +73,21 @@ def show_alert(
73
73
 
74
74
 
75
75
  @web_only
76
- def set_results(player_names: List[str], places: List[int], map: str, verbose: bool):
76
+ def set_results(
77
+ player_names: List[str],
78
+ seed: int,
79
+ places: List[int],
80
+ statistics: Dict[str, Union[float, int]],
81
+ parameters: Dict[str, str],
82
+ verbose: bool,
83
+ ):
77
84
  from js import window
78
85
 
79
86
  if hasattr(window, "setResults"):
80
87
  try:
81
- window.setResults(player_names, places, map, verbose)
88
+ window.setResults(
89
+ player_names, str(seed), places, statistics, parameters, verbose
90
+ )
82
91
  except Exception as e:
83
92
  print(e)
84
93