{"id":"circle-packing-rectangle-300","name":"Equal circles in a 1 × 0.3 rectangle","family":"combinatorics","description":"Place n circles in the rectangle [0, 1] × [0, 0.3] as large as possible (equal). Scored against the best-known Packomania records; anything above 1.0 on an n is a new record candidate.","metric":"record_ratio","direction":"maximize","tolerance":0.05,"eval_timeout_seconds":600,"agent_timeout_seconds":1800,"mutable":["pack.py"],"runtime":"python>=3.11, standard library only (math, random, itertools, functools, collections, heapq, time)","decomposable":true,"status":"active","captain":null,"parent_problem":null,"program_md":"# Equal circles in a 1 × 0.3 rectangle\n\n## Goal\n\n`pack.py` exposes `pack(n: int, time_budget: float, seed: int) -> list[tuple[float, ...]]`: the\ncentres of `n` circles inside the rectangle [0, 1] × [0, 0.3] (2 coordinates each). All objects share one radius, which the eval derives as\n\n    r = min( distance of every centre to the boundary, half the smallest pairwise distance )\n\nYou do not return a radius; the eval derives the largest feasible one from your centres, so there\nis nothing to fudge. Make it as large as possible for every `n` you are handed.\n\n## Metric\n\nThe eval runs your `pack` on a fixed set of values, `n = 8, 13, 19, 26, 31, 37, 44, 52, 68, 85, 101, 120, 150, 200`, each with the given time\nbudget (12 s by default), validates the result, and reports\n\n    metric = mean over n of  value(n) / record(n)\n\nwhere `record(n)` is the best-known value on Packomania (Eckard Specht's table, maintained since\n2011; table `crc_300`, fetched 2026-09-06). `1.0` matches the record; above `1.0` is a new record\ncandidate, listed under `records_beaten`. A hub-verified one is worth reporting to Packomania\nwith your ledger entry as provenance.\n\nThe hub verifies with a different `seed`, so your method must be robust to its starting point.\nThe full records table (n up to 300) is in `eval.py`.\n\n## Constraints\n\n- Standard library only. No numpy, no scipy, no subprocess. The eval rejects other imports.\n- Respect `time_budget` (seconds, per call). The eval kills the run if the whole set overruns.\n- Deterministic given `seed`: use `random.Random(seed)`, not the global RNG.\n- Every centre must lie inside the container. Objects may touch; they may not overlap.\n\n## Where the frontier is\n\nonly small n are proven. Above that every entry is \"best known\", found by numerical search, and Packomania's\nhistory shows improvements landing mostly at larger `n`. Budget your time per `n` deliberately;\nthe O(n²) checks and the number of local optima both grow.\n\n## Ideas that are known to matter (check the journal before repeating one)\n\n- Energy minimisation: treat objects as repelling points, minimise a soft overlap penalty with\n  gradient descent, then polish by maximising the minimum scaled distance directly.\n- Basin hopping / perturb-and-repolish from the current best; keep a small population.\n- Start from structured arrangements (lattices, rings, shells) as well as random.\n- Identify the binding contacts and solve the equal-distance conditions exactly for the last digits.\n- Spend more of the budget on the `n` values whose ratio is lowest.\n\nWrite one honest line in `NOTES.md`: the idea, and which `n` it helped.\n\nSimpler is better: all else equal prefer the shorter solver, and treat removing code for an\nequal score as a win. Log every experiment, including discards, in your results.tsv.\n","eval_py":"\"\"\"Eval for circle-packing-rectangle-300. Prints one JSON line: {\"metric\": record_ratio, ...}.\n\nGenerated by tools/packomania_import.py from https://packomania.com/crc_300/crc.html on 2026-09-06.\n\nEnv:\n  ZT_EVAL_SEED             seed handed to pack() (the n set is fixed so scores are comparable)\n  ZT_EVAL_NS               comma-separated n values (default \"8,13,19,26,31,37,44,52,68,85,101,120,150,200\")\n  ZT_EVAL_PER_N_SECONDS    time budget handed to pack() per n (default 12)\n\"\"\"\n\nfrom __future__ import annotations\n\nimport ast\nimport itertools\nimport json\nimport math\nimport os\nimport random\nimport sys\nimport time\nfrom pathlib import Path\n\nSEED = os.environ.get(\"ZT_EVAL_SEED\", \"dev-seed\")\nNS = [int(x) for x in os.environ.get(\"ZT_EVAL_NS\", \"8,13,19,26,31,37,44,52,68,85,101,120,150,200\").split(\",\")]\nBUDGET = float(os.environ.get(\"ZT_EVAL_PER_N_SECONDS\", \"12\"))\nSTDLIB_ALLOW = {\"math\", \"random\", \"itertools\", \"functools\", \"collections\", \"heapq\", \"time\", \"sys\", \"typing\", \"operator\"}\nEPS = 1e-9\nDIM = 2\n\n# Best-known values: equal objects in the rectangle [0, 1] × [0, 0.3]. Source: Packomania (E. Specht),\n# https://packomania.com/crc_300/crc.html, fetched 2026-09-06. only small n are proven.\nRECORDS = {\n    1: 0.150000000000000000000000000000, 2: 0.150000000000000000000000000000, 3: 0.150000000000000000000000000000, 4: 0.126631206038591402044816559535, 5: 0.107151991246211766023215091783,\n    6: 0.096688068540962573707868627546, 7: 0.090524980688874672231101900327, 8: 0.086624445513407986563879928173, 9: 0.084012779560868469248747528918, 10: 0.082183960607952947104467913022,\n    11: 0.080856054890725549128789228176, 12: 0.078183050093750876264961776380, 13: 0.074383118578882528398855021422, 14: 0.071690963196452521131547349910, 15: 0.067052525214119914224462306330,\n    16: 0.065161636802461890269909506198, 17: 0.062488544823889879508873858776, 18: 0.061300900367034192835166155455, 19: 0.059550656751250132811711587320, 20: 0.058578634153027236565466859064,\n    21: 0.057556164173945465572147860585, 22: 0.056829196367008116655910085286, 23: 0.056480789058860864653297028022, 24: 0.055687549391540451928672059783, 25: 0.055133307173835925009539287161,\n    26: 0.055029721700425140817596972087, 27: 0.053129454470372796800891154001, 28: 0.051263389719084686712968074972, 29: 0.050574671762540061910281662280, 30: 0.050000000000000000000000000000,\n    31: 0.048237334081921615156521944228, 32: 0.047506172350128100070079679517, 33: 0.046528041427494177311067302354, 34: 0.045842255778321503803911267635, 35: 0.045326929298257786901628748190,\n    36: 0.044696399788238293082900053513, 37: 0.044189570871487661105934798261, 38: 0.043924639199845338127647393716, 39: 0.043492666398085474449307216485, 40: 0.043101962030921619401738162276,\n    41: 0.042734400222033722159271602277, 42: 0.042538652292561095623883942424, 43: 0.042216386991065198825363988063, 44: 0.042084159922576466823992128235, 45: 0.041738765654977466112815057130,\n    46: 0.041666698686612742275306743112, 47: 0.040705379222986533781442836620, 48: 0.040264246406544206363518328956, 49: 0.039445405839191235339383348207, 50: 0.038949256048498339628656535561,\n    51: 0.038658295201252175494057881338, 52: 0.037963722246073354949049414283, 53: 0.037538613523303451425815861700, 54: 0.037377672840456481195489451151, 55: 0.036821146016561448902344535603,\n    56: 0.036489585424092138070358922411, 57: 0.036134102581187336287994831898, 58: 0.035946228253989012564529538442, 59: 0.035623233954159996204811152461, 60: 0.035410163893910687467572142897,\n    61: 0.035194861912490522255389203742, 62: 0.034979567404528373120441297937, 63: 0.034784473616478034030693163406, 64: 0.034577764524454160060602771758, 65: 0.034416597359089708480898899210,\n    66: 0.034249166970938659383062853915, 67: 0.034148410253936484471474255671, 68: 0.034081602735789718686733126686, 69: 0.033847639555750483296400771786, 70: 0.033796001733098026542546115369,\n    71: 0.033606813648998757248906552800, 72: 0.033409172025378879884142596682, 73: 0.033338463053847396170619977166, 74: 0.032616987204617423820257206424, 75: 0.032421427171979613680023527331,\n    76: 0.031955171771317619131510424843, 77: 0.031714333544939433857008311529, 78: 0.031637269812226431326163115735, 79: 0.031278191336827302451429038418, 80: 0.031009454065161705448802783935,\n    81: 0.030740788187739453010506263583, 82: 0.030529136629875429149799646930, 83: 0.030441831476039112921251952482, 84: 0.030195297504174257180073645041, 85: 0.030038382028080899980426001461,\n    86: 0.030002462118380845680673398462, 87: 0.029751438200420344250648227372, 88: 0.029583740266262674826277857186, 89: 0.029461270081064462565428471088, 90: 0.029322141118449119925149337381,\n    91: 0.029174331835118965340937691174, 92: 0.029046029161450878611969158788, 93: 0.029003588941959269180908743440, 94: 0.028836696680915642828031246174, 95: 0.028757878783588562214959261885,\n    96: 0.028665307614145275329611862981, 97: 0.028545553751987484012836369512, 98: 0.028484248696577589182156016260, 99: 0.028435554212868030849212417760, 100: 0.028302338820544108590585131176,\n    101: 0.028257754633513118549048815243, 102: 0.028238375042450805414717962642, 103: 0.028011659857520984298839134413, 104: 0.027852988007340577203932745090, 105: 0.027794892978654206271859994434,\n    106: 0.027535211845764605436590231747, 107: 0.027251205775747549592704313366, 108: 0.027164475846542418237686506455, 109: 0.026889123500713840534251190570, 110: 0.026707061442037960273116045794,\n    111: 0.026642297475135009163974702072, 112: 0.026484179830352499698437282841, 113: 0.026284900321440956351333974035, 114: 0.026202601459959226245404598275, 115: 0.026025255837879467477427504126,\n    116: 0.025906232973915120234114437482, 117: 0.025830027267520138953571387912, 118: 0.025704786885211698621329765502, 119: 0.025618955161162966842588054692, 120: 0.025527181881409762752561895220,\n    121: 0.025446335088338135215489550163, 122: 0.025314649299144289656061160803, 123: 0.025276716365927278477504335494, 124: 0.025162433941115291176539359240, 125: 0.025055482306722672207139970751,\n    126: 0.025021618168217231919147180378, 127: 0.024952538805520807957127023933, 128: 0.024860119793920455816095854460, 129: 0.024797971801845074130131553691, 130: 0.024740658660292697545650788795,\n    131: 0.024652676016254139593923331381, 132: 0.024603396159233857947114469542, 133: 0.024554836403489723605882524555, 134: 0.024484059315114268721657102388, 135: 0.024438434008531799027103622513,\n    136: 0.024411983584887020764007097872, 137: 0.024392030974825139716361666048, 138: 0.024286083557267434973110196064, 139: 0.024260736169346817115476302966, 140: 0.024250222592084895513672836264,\n    141: 0.024055693968047485002728752397, 142: 0.023917579859034299820297531778, 143: 0.023860432934142405927444215640, 144: 0.023836177376652268312348184510, 145: 0.023527842859509929931423663374,\n    146: 0.023439272147164687103438091540, 147: 0.023387326231241615567710009893, 148: 0.023197925843733818012236957644, 149: 0.023111358338870302025465730213, 150: 0.023031811667282605665088499992,\n    151: 0.023008212452899929908236177263, 152: 0.022845271225367154267575094099, 153: 0.022744328498670303560889129833, 154: 0.022689929813762288713944462093, 155: 0.022585703188380117457185978700,\n    156: 0.022519276625005400512160286568, 157: 0.022450485218343579577801146770, 158: 0.022399180453602167357489775683, 159: 0.022322526572162188183335143443, 160: 0.022236605155245734363454499411,\n    161: 0.022195241503142934091486221746, 162: 0.022138825679181292012936802160, 163: 0.022057534485747992067785992091, 164: 0.022012011722208454531322906809, 165: 0.021953232441395218922879379691,\n    166: 0.021919196366725976291293745088, 167: 0.021847344188620696784677802114, 168: 0.021822114627356266392353242947, 169: 0.021740714454396355184249906722, 170: 0.021714608001888489617404023583,\n    171: 0.021661944101783982369466249808, 172: 0.021652716787448795641599519579, 173: 0.021572500768173462740468674647, 174: 0.021542730874590353010192055895, 175: 0.021506825884399701152512433354,\n    176: 0.021476115671020062801148544228, 177: 0.021420830922335435789739600070, 178: 0.021386841293496729230857021100, 179: 0.021368200223267016265340673629, 180: 0.021356758797489283990082632323,\n    181: 0.021294993588757111963669041327, 182: 0.021263660408506836619556344668, 183: 0.021251100537255848210337091455, 184: 0.021248354647111596958733862781, 185: 0.021034189475167234123246972303,\n    186: 0.020952955510455286890730800503, 187: 0.020889615161608347310171550524, 188: 0.020863762078964588910948579313, 189: 0.020833336504546043314224626978, 190: 0.020604812058503279199651048260,\n    191: 0.020550396026447764135805203359, 192: 0.020534453108759521975362133542, 193: 0.020398931256691510228441583960, 194: 0.020331497912402453801726961469, 195: 0.020276405863125816593166186704,\n    196: 0.020251090442360699413106779915, 197: 0.020161358858121598469750250388, 198: 0.020098442656505992132203061217, 199: 0.020039435159174057548347758279, 200: 0.020007069522155599587332237742,\n    201: 0.019954131883546143640269441505, 202: 0.019888285798398333242741473123, 203: 0.019856349107300332611533406892, 204: 0.019804766816154518146242166213, 205: 0.019762889545228807542797712731,\n    206: 0.019688898702476348347445282187, 207: 0.019662659852342355184624185044, 208: 0.019633591321802884442999369906, 209: 0.019591538769658112320079703081, 210: 0.019540177338054208277917480759,\n    211: 0.019503326429638379164692444298, 212: 0.019494474900433714266676001218, 213: 0.019429293599372067114977873119, 214: 0.019385118125542864011836227915, 215: 0.019356710664150633606080228473,\n    216: 0.019348777444811387848225816681, 217: 0.019285143024535893584682774187, 218: 0.019266443057456919230007847814, 219: 0.019236676138689796107666312173, 220: 0.019218484810961357051760911895,\n    221: 0.019194556746831074088226310290, 222: 0.019148752016887496347095982100, 223: 0.019120011442930023958521344950, 224: 0.019103978363503050041694149861, 225: 0.019082228180616973521254866431,\n    226: 0.019041482924556621560768112188, 227: 0.019012622149080135815716661885, 228: 0.019007944266026229828397072151, 229: 0.018998476866658860649465136708, 230: 0.018992636235028447239356648685,\n    231: 0.018941674301956734952649174897, 232: 0.018917635800221082323361472115, 233: 0.018881260456856313852782953756, 234: 0.018871097795434779603613850674, 235: 0.018690146448886759794973801223,\n    236: 0.018651467507972670854240146411, 237: 0.018593417836167609975917060731, 238: 0.018563258704491663599537226474, 239: 0.018548136128114502340017864755, 240: 0.018400613071091657390995033202,\n    241: 0.018340767394383699665099809782, 242: 0.018308294828037158678521982124, 243: 0.018287021381275354977772415091, 244: 0.018181222889849160271945578991, 245: 0.018121276149507780967258170537,\n    246: 0.018094173743590557376203832034, 247: 0.018079577120380947479151198738, 248: 0.018052826710841577114919824089, 249: 0.017997652459641453750325198427, 250: 0.017934911982584917540027456500,\n    251: 0.017880989086930553245980109505, 252: 0.017856702153156979319258898016, 253: 0.017812992909714341766611110036, 254: 0.017788000615541420293169492346, 255: 0.017766154316057960756556987525,\n    256: 0.017749850428086829422587613843, 257: 0.017707196232021022807787038872, 258: 0.017667937533763620840842808547, 259: 0.017633452227936349496511522263, 260: 0.017623120720183158312107847585,\n    261: 0.017590096166757424338415409385, 262: 0.017567976467131918041550268218, 263: 0.017524718795973125883236287003, 264: 0.017501472748097644370182207932, 265: 0.017494495315676387443501257034,\n    266: 0.017440456641027116071967435172, 267: 0.017421656365926577036667805966, 268: 0.017411393667920991959737017903, 269: 0.017385839074669731429633045405, 270: 0.017379574569687861635170443895,\n    271: 0.017329092345035972342519929249, 272: 0.017316458379007036270031979304, 273: 0.017291132336699880575790612900, 274: 0.017277038661260597486759669366, 275: 0.017276609879897040626830646857,\n    276: 0.017226711453348248053111263364, 277: 0.017213963674412495362206992207, 278: 0.017190780220025260011396635453, 279: 0.017184637967863744656274991147, 280: 0.017172160025333764672180090362,\n    281: 0.017136123591566622880118014729, 282: 0.017124783505404532643677187107, 283: 0.017107960978559855519303738335, 284: 0.017102129898623975918721890234, 285: 0.017100199840642701273524918382,\n    286: 0.017031414619010597125512696486, 287: 0.016990810269244136558701808282, 288: 0.016987959237621046876470267675, 289: 0.016965931488915096455065875988, 290: 0.016955060749344193153665826076,\n    291: 0.016817977394151830153392833785, 292: 0.016784313654409689203826348014, 293: 0.016736263660124224534974423093, 294: 0.016713233394864897815163425572, 295: 0.016701578334441598116319080439,\n    296: 0.016670946905219811520356849343, 297: 0.016548318307044348044457018319, 298: 0.016524083016780614879194909260, 299: 0.016498917570028840864565116502, 300: 0.016458728976061140249536135425,\n}\n\n\ndef fail(msg: str, kind: str = \"error\") -> None:\n    print(json.dumps({\"metric\": 0.0, \"error\": msg, \"kind\": kind}))\n    sys.exit(1)\n\n\ndef check_imports(path: Path) -> None:\n    try:\n        tree = ast.parse(path.read_text(encoding=\"utf-8\"))\n    except SyntaxError as e:\n        fail(f\"syntax error in pack.py: {e}\", \"compile_error\")\n    for node in ast.walk(tree):\n        names = []\n        if isinstance(node, ast.Import):\n            names = [a.name.split(\".\")[0] for a in node.names]\n        elif isinstance(node, ast.ImportFrom) and node.module:\n            names = [node.module.split(\".\")[0]]\n        for nm in names:\n            if nm not in STDLIB_ALLOW:\n                fail(f\"import of '{nm}' is not allowed (stdlib subset only: {sorted(STDLIB_ALLOW)})\", \"compile_error\")\n\n\ndef boundary(c) -> float:\n    \"\"\"Distance from centre c to the container boundary; negative outside.\"\"\"\n    return min(c[0], 1 - c[0], c[1], 0.3 - c[1])\n\n\ndef weight(i: int) -> float:\n    \"\"\"Radius weight of object i (1-based); the eval derives the common scale s, r_i = weight(i) * s.\"\"\"\n    return 1.0\n\n\ndef value_of(centres: list, n: int) -> float:\n    if not isinstance(centres, (list, tuple)) or len(centres) != n:\n        fail(f\"pack({n}) must return {n} centres\", \"wrong_answer\")\n    pts = []\n    for c in centres:\n        try:\n            p = tuple(float(v) for v in c)\n        except Exception:\n            fail(f\"pack({n}) returned a non-point {c!r}\", \"wrong_answer\")\n        if len(p) != DIM or not all(math.isfinite(v) for v in p):\n            fail(f\"pack({n}) returned a point that is not {DIM}-D and finite: {c!r}\", \"wrong_answer\")\n        if boundary(p) < -EPS:\n            fail(f\"pack({n}) placed a centre outside the container: {p}\", \"wrong_answer\")\n        pts.append(p)\n    w = [weight(i + 1) for i in range(n)]\n    s = min(max(boundary(p), 0.0) / w[i] for i, p in enumerate(pts))   # upper bound from the walls\n    if s <= EPS:\n        fail(f\"pack({n}) has a centre on the boundary (scale={s})\", \"wrong_answer\")\n    # Any pair that limits the scale below s has distance < (w_i + w_j) s <= 2 wmax s, so it lies\n    # in the same or an adjacent cell of a grid with that spacing. Expected O(n) instead of O(n^2).\n    cell = 2.0 * max(w) * s\n    grid = {}\n    for idx, p in enumerate(pts):\n        key = tuple(int(math.floor(v / cell)) for v in p)\n        grid.setdefault(key, []).append(idx)\n    offsets = list(itertools.product((-1, 0, 1), repeat=DIM))\n    for key, members in grid.items():\n        for off in offsets:\n            nb = tuple(k + o for k, o in zip(key, off))\n            if nb < key or nb not in grid:\n                continue\n            others = grid[nb]\n            for i in members:\n                pi = pts[i]\n                for j in others:\n                    if nb == key and j <= i:\n                        continue\n                    pj = pts[j]\n                    d = math.sqrt(sum((a - b) * (a - b) for a, b in zip(pi, pj))) / (w[i] + w[j])\n                    if d < s:\n                        s = d\n    if s <= EPS:\n        fail(f\"pack({n}) has coincident centres (scale={s})\", \"wrong_answer\")\n    return w[n - 1] * s   # the largest object's radius (equal case: the common radius)\n\n\ndef main() -> None:\n    here = Path(__file__).parent\n    check_imports(here / \"pack.py\")\n    sys.path.insert(0, str(here))\n    try:\n        import pack as cand  # noqa: E402\n    except SystemExit:\n        raise\n    except Exception as e:\n        fail(f\"import pack.py failed: {e!r}\", \"compile_error\")\n    if not hasattr(cand, \"pack\"):\n        fail(\"pack.py must define pack(n, time_budget, seed)\", \"compile_error\")\n\n    ns = sorted(set(NS))\n    for n in ns:\n        if n not in RECORDS:\n            fail(f\"no Packomania record for n={n}\", \"error\")\n    seed_int = random.Random(f\"crc_300|{SEED}\").getrandbits(32)\n    per_n, beaten = {}, []\n    t_all = time.perf_counter()\n    for n in ns:\n        t0 = time.perf_counter()\n        try:\n            centres = cand.pack(n, BUDGET, seed_int)\n        except SystemExit:\n            raise\n        except Exception as e:\n            fail(f\"pack({n}) raised {e!r}\", \"runtime_error\")\n        elapsed = time.perf_counter() - t0\n        if elapsed > 1.25 * BUDGET + 3:\n            fail(f\"pack({n}) took {elapsed:.1f}s against a {BUDGET:.0f}s budget\", \"timeout\")\n        v = value_of(centres, n)\n        ratio = v / RECORDS[n]\n        per_n[n] = {\"value\": round(v, 12), \"record\": RECORDS[n], \"ratio\": round(ratio, 6), \"seconds\": round(elapsed, 2)}\n        if v > RECORDS[n] + 1e-9:\n            beaten.append(n)\n    metric = sum(x[\"ratio\"] for x in per_n.values()) / len(per_n)\n    print(json.dumps({\"metric\": round(metric, 6), \"ns\": ns, \"per_n\": per_n, \"records_beaten\": beaten,\n                      \"total_seconds\": round(time.perf_counter() - t_all, 1)}))\n\n\nif __name__ == \"__main__\":\n    main()\n","baseline":{"pack.py":"\"\"\"Baseline: a lattice of candidate points inside the container, spacing found by bisection so\nthat at least n fit. Deliberately naive; scores well below the records. Beat it.\"\"\"\n\nimport itertools\nimport math\n\nDIM = 2\n\n\ndef _boundary(c):\n    return min(c[0], 1 - c[0], c[1], 0.3 - c[1])\n\n\ndef _weight(i):\n    return 1.0\n\n\ndef _lattice(n, r):\n    \"\"\"Cubic lattice points at spacing 2r whose distance to the boundary is at least r.\"\"\"\n    lo, hi = ((0.0,) * DIM, (1.0,) * DIM)\n    step = 2.0 * r\n    axes = []\n    for d in range(DIM):\n        k = int((hi[d] - lo[d]) / step) + 1\n        axes.append([lo[d] + r + i * step for i in range(k)])\n    pts = [p for p in itertools.product(*axes) if _boundary(p) >= r]\n    return pts\n\n\ndef pack(n, time_budget, seed):\n    # treat every object as the largest one when choosing the lattice spacing\n    wmax = max(_weight(i + 1) for i in range(n))\n    # find a feasible spacing by halving, then bisect between it and the last infeasible one\n    a = 1.0\n    while len(_lattice(n, a * wmax)) < n and a > 1e-9:\n        a /= 2\n    b = 2 * a\n    for _ in range(40):\n        m = (a + b) / 2\n        if len(_lattice(n, m * wmax)) >= n:\n            a = m\n        else:\n            b = m\n    pts = _lattice(n, a * wmax)\n    pts.sort(key=lambda p: -_boundary(p))   # keep the most interior points\n    return [tuple(p) for p in pts[:n]]\n"}}