{"id":"circle-packing-rectangle-500","name":"Equal circles in a 1 × 0.5 rectangle","family":"combinatorics","description":"Place n circles in the rectangle [0, 1] × [0, 0.5] 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.5 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.5] (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_500`, 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-500. Prints one JSON line: {\"metric\": record_ratio, ...}.\n\nGenerated by tools/packomania_import.py from https://packomania.com/crc_500/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.5]. Source: Packomania (E. Specht),\n# https://packomania.com/crc_500/crc.html, fetched 2026-09-06. only small n are proven.\nRECORDS = {\n    1: 0.250000000000000000000000000000, 2: 0.250000000000000000000000000000, 3: 0.177124344467704704749192123181, 4: 0.151923788646684059708830487741, 5: 0.141101056459326447763018016141,\n    6: 0.135621722338523523745960615902, 7: 0.127166547515124908877372380214, 8: 0.125000000000000000000000000000, 9: 0.110653654474367741340655060442, 10: 0.105783167543767350018062597211,\n    11: 0.100233512361812980711521148405, 12: 0.096427664499301081081613737870, 13: 0.094142364928295586141985453540, 14: 0.093365838666289124470030673945, 15: 0.091090581831205205682456817276,\n    16: 0.085955228382080002217953105914, 17: 0.084652380550897770379015970918, 18: 0.083333333333333333333333333333, 19: 0.078882401662675827253930313354, 20: 0.076558486389562273600443942017,\n    21: 0.075053719656362888139207965053, 22: 0.073151002198728661815716595557, 23: 0.071986654782464227954291509799, 24: 0.071244627914878274325627103835, 25: 0.070266433941895194884915371942,\n    26: 0.069925404472025400649546220148, 27: 0.068211221141434775435384587398, 28: 0.067325459096181718382699377570, 29: 0.065263704794652490405193588681, 30: 0.064000660504103315482893710283,\n    31: 0.063239039575592430245527524692, 32: 0.062513529119464986837398831487, 33: 0.061362641380780810960072632138, 34: 0.059913441660665942403647655027, 35: 0.059073014802394054344042589115,\n    36: 0.058528001390752912998822122969, 37: 0.058005263287499033189237805679, 38: 0.057599687688973850409428335453, 39: 0.056869687311079409555242253989, 40: 0.056663836097005681013780908938,\n    41: 0.056099074285617284286230158416, 42: 0.055753293928454377568280133108, 43: 0.055563768403385707566717104997, 44: 0.053876965144146832689219688582, 45: 0.053278688524590163934426229508,\n    46: 0.052265194045587846294174911870, 47: 0.051680888630939204362972417134, 48: 0.051329154305541199014026688277, 49: 0.050502141969400949816447455479, 50: 0.050142287471139294753868254653,\n    51: 0.050010882998682898954840120671, 52: 0.049246763357710309753212469995, 53: 0.048809537200804487642610287642, 54: 0.048442234418427880520704572183, 55: 0.048179877701987543711209906807,\n    56: 0.047853713201627127034293701652, 57: 0.047653713411493648625646346508, 58: 0.047243389501077936665427108193, 59: 0.047126588165473066409583748155, 60: 0.047069192209893667609523392109,\n    61: 0.046225992794225535501999773532, 62: 0.045895850148690101770761968361, 63: 0.045599739281343847005149976587, 64: 0.045462299986847309645500334989, 65: 0.044443613448354213463611989344,\n    66: 0.044145386394489884647898198349, 67: 0.043622899472312524209825004291, 68: 0.043201265736692864133621358584, 69: 0.042930061617729661001072932760, 70: 0.042635291302461060569843903551,\n    71: 0.042393241618374906130350178069, 72: 0.042157793609315461098708808753, 73: 0.041932470579286307542193317763, 74: 0.041707829184156647021925114669, 75: 0.041462593147343994928020639873,\n    76: 0.041337977640229239254996582794, 77: 0.041153613262605951369219562983, 78: 0.040922389296232648375756860147, 79: 0.040776371214460525536308867001, 80: 0.040726828170627310132321232423,\n    81: 0.040660136398854019834771552820, 82: 0.040351006020421063617939452707, 83: 0.040149313866204279530871168360, 84: 0.040044221033453281484979358806, 85: 0.039356733062302146493957830446,\n    86: 0.039034349725912202594995428228, 87: 0.038822406712210932303739638233, 88: 0.038755956104951631372920614796, 89: 0.038468664389276014689817297669, 90: 0.038194738877783002773296068763,\n    91: 0.037807952290728865782753756802, 92: 0.037473232388110558136722762134, 93: 0.037325032326601734455544405537, 94: 0.037116545755325693903764764827, 95: 0.037041337463301754997468058617,\n    96: 0.036793469284642689364368145591, 97: 0.036608073852591538566964814957, 98: 0.036476955779110724971034101307, 99: 0.036361094919354451148096507900, 100: 0.036212513310819411514713240237,\n    101: 0.036081114685429554291876986105, 102: 0.035941023544174026998796707917, 103: 0.035904565298857659992845146794, 104: 0.035799673236013333428892266926, 105: 0.035617153709178924351362343472,\n    106: 0.035524785154266454123315441872, 107: 0.035490076907234818239428480609, 108: 0.035474189489398044812362246703, 109: 0.035053264279659664521764184611, 110: 0.034836066725984940353270761905,\n    111: 0.034692167026754553375583769515, 112: 0.034586627008555786210295073319, 113: 0.034197885134882832419923765394, 114: 0.033976666163959316737526691031, 115: 0.033812840620867094408324013681,\n    116: 0.033728283609856567083219774278, 117: 0.033559646957911044744006845123, 118: 0.033421036648604225218737857958, 119: 0.033391035230150718043282214709, 120: 0.033099972685625485952927537917,\n    121: 0.032898941383116217301800802759, 122: 0.032769143187758488004306834410, 123: 0.032672589642163857972090138470, 124: 0.032578214153997432801386872080, 125: 0.032467887201004217734645406482,\n    126: 0.032338145197637654872441305476, 127: 0.032221401821155752656064731828, 128: 0.032152738848303439166661472212, 129: 0.032111690007027140829298741067, 130: 0.032043702323317776757149915505,\n    131: 0.031988271722746359424764367637, 132: 0.031836285162943187589544020442, 133: 0.031765249959456289370280153386, 134: 0.031747675676243598892591981865, 135: 0.031707954593793196249505355526,\n    136: 0.031570196507596091110999755836, 137: 0.031499782194109611131325789225, 138: 0.031353448896212707770040941609, 139: 0.031283541947471316585916043173, 140: 0.031263686459127122158144949397,\n    141: 0.030832247684132922728303277942, 142: 0.030648977160549346038431441395, 143: 0.030524298789264589533492081681, 144: 0.030504838873534247385607364780, 145: 0.030253161384122585174416403796,\n    146: 0.030118710794236567075190203235, 147: 0.029996034415041702998703677546, 148: 0.029939498172237215628250668980, 149: 0.029919015690121834039814954783, 150: 0.029755549335495874515855989992,\n    151: 0.029583427716873667128551761728, 152: 0.029531729632610148868772065103, 153: 0.029452878299917718960141566102, 154: 0.029363586774117616058513576296, 155: 0.029249317150331426391025879193,\n    156: 0.029202766669026161242808650602, 157: 0.029119214409784814953283095528, 158: 0.029058237273437755400315142620, 159: 0.029023709820116717074324623872, 160: 0.028924095514503622084926890786,\n    161: 0.028851810426012807835773947769, 162: 0.028767689234845603615444808841, 163: 0.028736775955143162594938170194, 164: 0.028709087374056238416836270953, 165: 0.028668598518972321055370654619,\n    166: 0.028563251083422741014652857837, 167: 0.028521023700264348432896607831, 168: 0.028481894514575358161479073921, 169: 0.028468419676542691635782768725, 170: 0.028462230114497167626611467785,\n    171: 0.028155157990097527246117191432, 172: 0.028055713370242029128209255968, 173: 0.027974980513621630868689035472, 174: 0.027877534651427880692080167858, 175: 0.027854494020919565807362294623,\n    176: 0.027788671525522512066090112544, 177: 0.027469518079713647735583102232, 178: 0.027440138405255882778077978281, 179: 0.027420855016873229220200646629, 180: 0.027320875054589898960751665082,\n    181: 0.027160747740299551798438346006, 182: 0.027070140901292798062709387233, 183: 0.026991401655121140447351188802, 184: 0.026942110285249565751056626824, 185: 0.026894728096383453585744927931,\n    186: 0.026801101672654646396249086073, 187: 0.026729066848563772908624074399, 188: 0.026668676074390265577253248509, 189: 0.026603324440616178478757357325, 190: 0.026549309863213483240776269847,\n    191: 0.026539268843604086931301889821, 192: 0.026432957846190840434234036648, 193: 0.026396682215842580358984795563, 194: 0.026343816719120851538742440017, 195: 0.026268710378111639270662074695,\n    196: 0.026247895915702708712779968149, 197: 0.026202902783482076315423261043, 198: 0.026179488125024927902621827711, 199: 0.026098878874533704510192820051, 200: 0.026064142423986239629381457131,\n    201: 0.026027930375516013092727922674, 202: 0.026009679124707085858275318327, 203: 0.025994436777372496251725088401, 204: 0.025984795945105457435179389557, 205: 0.025888784816969074081007973899,\n    206: 0.025819747808011556669016179442, 207: 0.025727497645450246695495097588, 208: 0.025683654829247473440333872666, 209: 0.025660189630547876283852777491, 210: 0.025430942147710306904662007948,\n    211: 0.025324204178219183871859708381, 212: 0.025263657277136025527715930223, 213: 0.025191584740009428865580669440, 214: 0.025152777696328487642633393911, 215: 0.025121237583400945744594094755,\n    216: 0.025009389414484396042022159896, 217: 0.024957350991830491677875932769, 218: 0.024954417219028271464737577037, 219: 0.024951548307616929837312621404, 220: 0.024756927609435777493786222180,\n    221: 0.024654375527023819224242549709, 222: 0.024583954303142997308698963937, 223: 0.024546145899888458355453388975, 224: 0.024511374327676122114566726924, 225: 0.024456307413175520448382456503,\n    226: 0.024434837930513668593500524012, 227: 0.024382320286205430405171065019, 228: 0.024303644990277716800630557247, 229: 0.024270585218318338859973367772, 230: 0.024218583902030023269277282863,\n    231: 0.024182835029953092954747519875, 232: 0.024168042122966510371217051544, 233: 0.024108474399411274020936580295, 234: 0.024084929815576748642220957374, 235: 0.024034321211533409925537408993,\n    236: 0.023998028408993557240587846661, 237: 0.023959665258176061074171647376, 238: 0.023947748728349824886379776742, 239: 0.023932825228432520546903511811, 240: 0.023906597128458200936964534529,\n    241: 0.023837570897961177375643411182, 242: 0.023816374464428687945713293248, 243: 0.023789483750642631837469824590, 244: 0.023773925474852827831909549391, 245: 0.023766787833391966426231571578,\n    246: 0.023764395432472400734695193056, 247: 0.023552493213875367425720524415, 248: 0.023493272150631340734062439717, 249: 0.023435397799192867521272085097, 250: 0.023355890353995782344336889832,\n    251: 0.023322991809768651564780342356, 252: 0.023302577855523479490307661727, 253: 0.023164683161765541621232760977, 254: 0.023083379387426491015983171478, 255: 0.023021477795255211112176199464,\n    256: 0.022989168271594785595932718181, 257: 0.022949936262126711223912094941, 258: 0.022921626939540217620628036102, 259: 0.022842320989425122366770557694, 260: 0.022749079140619140019153761688,\n    261: 0.022742944515625178490254324584, 262: 0.022742944515625178490254324584, 263: 0.022742944515625178490254324584, 264: 0.022686356854871270942962255755, 265: 0.022619624326634222264045283090,\n    266: 0.022545816626216991389068308962, 267: 0.022505251361713945564281194540, 268: 0.022475576482647568823107159347, 269: 0.022433443041362350209228618065, 270: 0.022404903893470077438210156233,\n    271: 0.022401124925992715560822018887, 272: 0.022330800265160510296636066671, 273: 0.022309942945733705340077142644, 274: 0.022276160952751874110322264175, 275: 0.022241928046184515186987003304,\n    276: 0.022210809994061184149439728019, 277: 0.022195759728175783452382722984, 278: 0.022181481611371754803750404940, 279: 0.022153411110297019040185595947, 280: 0.022143157008859841031584934347,\n    281: 0.022090720123257037265442629563, 282: 0.022060035660516849909989614503, 283: 0.022037939881602512214869180100, 284: 0.022026935871964960496770940892, 285: 0.022019462748245911473512947087,\n    286: 0.022012220400374815776763766029, 287: 0.021953790770444916435502275178, 288: 0.021930049967546014927976525729, 289: 0.021866843179344365245297082582, 290: 0.021804543254270266341907428040,\n    291: 0.021776541570683319599002782964, 292: 0.021758449031095686655696674980, 293: 0.021749636546474226692427229566, 294: 0.021583863206326468391301056427, 295: 0.021507617364507104896785004206,\n    296: 0.021465834659063596848891407390, 297: 0.021414645930970905169837150803, 298: 0.021393555810296541561152482170, 299: 0.021358825842630550654695276806, 300: 0.021293996955586860418567236853,\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.5 - 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_500|{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.5 - 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"}}