{"id":"circle-packing-right-triangle","name":"Equal circles in a right triangle","family":"combinatorics","description":"Place n circles in the isosceles right triangle with vertices (0,0), (1,0), (0,1) 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 right triangle\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 isosceles right triangle with vertices (0,0), (1,0), (0,1) (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 `crt`, 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 299) 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-right-triangle. Prints one JSON line: {\"metric\": record_ratio, ...}.\n\nGenerated by tools/packomania_import.py from https://packomania.com/crt/crt.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 isosceles right triangle with vertices (0,0), (1,0), (0,1). Source: Packomania (E. Specht),\n# https://packomania.com/crt/crt.html, fetched 2026-09-06. only small n are proven.\nRECORDS = {\n    1: 0.292893218813452475599155637895, 2: 0.207106781186547524400844362105, 3: 0.184699031259064639371307948271, 4: 0.160188620508520367600361869474, 5: 0.139933250189584016010699682098,\n    6: 0.134876071694908969152891508111, 7: 0.122229728867651532414543849327, 8: 0.115046593935109792351790738066, 9: 0.110240604605771200956705296110, 10: 0.106222361897208144374166310900,\n    11: 0.099412103976005362507947914479, 12: 0.095943368477780190279390254976, 13: 0.092604027573949621290924338290, 14: 0.089753553298429679513887679701, 15: 0.087610065690070458685697053835,\n    16: 0.084090268325901633878526670883, 17: 0.082264484182688609747379051363, 18: 0.079727525625494859159593067446, 19: 0.078133140566947791272420642865, 20: 0.076378991823013947793545532583,\n    21: 0.074547791814273978529565572365, 22: 0.072895080875273247425094690768, 23: 0.071581718995599529585444225012, 24: 0.069914330471767597225541240229, 25: 0.068552444544352860098178160187,\n    26: 0.067573656554549286526642415752, 27: 0.066273724817239233486769019447, 28: 0.065186454246851524853291386212, 29: 0.064012298551316766854566681766, 30: 0.063062012996332493125050814958,\n    31: 0.062206905110929787982554697853, 32: 0.061271965726474658527691524658, 33: 0.060341937748463158170313421166, 34: 0.059529215264914758075537012723, 35: 0.058702760457182031530456481064,\n    36: 0.057977885816087168807523351764, 37: 0.057201813503630322194646488397, 38: 0.056524599580478030236429337372, 39: 0.055775498265939385768159921378, 40: 0.055284785872367966120432533474,\n    41: 0.054567981671521314734928568992, 42: 0.053878035839236931707317523765, 43: 0.053337740416613861875143736503, 44: 0.052739546815925135884153722541, 45: 0.052151704852573534064757542009,\n    46: 0.051730124673871185786780817652, 47: 0.051230682535404290746659075563, 48: 0.050659107957245864162268168619, 49: 0.050148758538649490901737888561, 50: 0.049782889215332344842427198878,\n    51: 0.049210643899436240853141091882, 52: 0.048843851530028133627914182530, 53: 0.048400723345548409963977099342, 54: 0.047987323959451553136362699298, 55: 0.047519033968221680040031495221,\n    56: 0.047111702421810535957614208254, 57: 0.046745895733448388429067091576, 58: 0.046421284638022819702349500743, 59: 0.045950456511985541273636177626, 60: 0.045601392571645883160832003974,\n    61: 0.045294150990393085251273677778, 62: 0.044918749375195635798626985710, 63: 0.044570982561404562440413676600, 64: 0.044224566623236258846364834541, 65: 0.043931051031698020223651763542,\n    66: 0.043635317229970822854502642176, 67: 0.043311925364952404881383052691, 68: 0.043008487573184573962470605529, 69: 0.042717378651785596354539992142, 70: 0.042484939929021566211469037742,\n    71: 0.042115911651114051392641615673, 72: 0.041828699597051416701987863185, 73: 0.041597294201379434344754464127, 74: 0.041327719538519885419563026930, 75: 0.041032850590849648929006267366,\n    76: 0.040804704927251857119396324645, 77: 0.040558779096203082107171923521, 78: 0.040294467192844828258033240885, 79: 0.040035822097006118702450300740, 80: 0.039844578067413915145714662697,\n    81: 0.039598896812237962565791616340, 82: 0.039393416735785588980126316269, 83: 0.039171058445401154434968508937, 84: 0.038906886690802678971918807096, 85: 0.038664292457572917885535785240,\n    86: 0.038483258924123575320205308525, 87: 0.038291635579757780019559443384, 88: 0.038087925226711666783978530630, 89: 0.037863497233666749164449824658, 90: 0.037692475487242589573876187843,\n    91: 0.037471662651535436206963530619, 92: 0.037264690039514402311535477755, 93: 0.037087301465658458898371786150, 94: 0.036894699782078599751850736775, 95: 0.036698643855145706404699424636,\n    96: 0.036528541360465405736724439656, 97: 0.036370285227438766405826136730, 98: 0.036188454424976049430221322261, 99: 0.036005719267126801921579945796, 100: 0.035803503873716013690544482287,\n    101: 0.035658964130103636934822646848, 102: 0.035495740294867397500361418047, 103: 0.035321486940073031617824515957, 104: 0.035161727350453294736088134374, 105: 0.035002899389078017195423633237,\n    106: 0.034864593631030463076200801255, 107: 0.034698078329801354932758582117, 108: 0.034542778791871884710963290664, 109: 0.034372259323998769332424170875, 110: 0.034233576903981078701085691481,\n    111: 0.034086416480706564837550946824, 112: 0.033944935518406306598892913973, 113: 0.033819343156400040225641468055, 114: 0.033660242844082393623260671437, 115: 0.033503476565283971284621798573,\n    116: 0.033371154078948269725729584124, 117: 0.033249266587035668080302537397, 118: 0.033111287134123391101432611243, 119: 0.032983340877363024121774323941, 120: 0.032858295047313347828441353756,\n    121: 0.032705202761546005561661149031, 122: 0.032587842769609785077857068355, 123: 0.032451839658662134589202623999, 124: 0.032344586691074128980986665313, 125: 0.032204794945647505784912539896,\n    126: 0.032071871107568746657518681597, 127: 0.031967455761978173639296780188, 128: 0.031873082744451182800100833904, 129: 0.031748588074885912844381012437, 130: 0.031627383835886681617513654732,\n    131: 0.031501740843591538924101090765, 132: 0.031389690640053192374514597279, 133: 0.031277485056317788800295672669, 134: 0.031168201564862235001909016517, 135: 0.031057451010877154721001283731,\n    136: 0.030946675741193782795936930366, 137: 0.030837828293904458860223362185, 138: 0.030713728156171506852076258106, 139: 0.030612919211019990644170423905, 140: 0.030518479587971284998313691091,\n    141: 0.030420510118446136012223096961, 142: 0.030291487963601186021018925747, 143: 0.030197942233097538205010985220, 144: 0.030106171472638760385730897717, 145: 0.030011366235184777662973908377,\n    146: 0.029908281494832940136653838799, 147: 0.029823952104959626805553384797, 148: 0.029727997293061660219278513419, 149: 0.029621734496298883654906953399, 150: 0.029530381065308387968980869493,\n    151: 0.029413401175019320735528194413, 152: 0.029338442722510542275338696825, 153: 0.029247865957036616278373446912, 154: 0.029156764689660024684099845073, 155: 0.029064617490148708558908923936,\n    156: 0.028967184576205253173264083725, 157: 0.028889885197087781625774447440, 158: 0.028793913471833378385355499061, 159: 0.028710647070022065001055218290, 160: 0.028618496176438051560296324347,\n    161: 0.028537060264452933213104300060, 162: 0.028444629621139262688412661838, 163: 0.028366712077674286884078417771, 164: 0.028269845632706349832815641416, 165: 0.028201114710445537644179364546,\n    166: 0.028137504800034490934242006718, 167: 0.028036762342152449836615330714, 168: 0.027949002512393007392624684339, 169: 0.027872953511646182612187016770, 170: 0.027809716330362713189545809259,\n    171: 0.027741977877903544399353351938, 172: 0.027649540664406753995109501759, 173: 0.027580060413830474336749681138, 174: 0.027483945803823845515227119638, 175: 0.027422149242311425793481810104,\n    176: 0.027355356960997968341854371066, 177: 0.027276864383351250850988316104, 178: 0.027187822226450272796270786089, 179: 0.027122097847526280413462207605, 180: 0.027048549027364226261720129816,\n    181: 0.026984742335465257846162405779, 182: 0.026891797613505531407468863940, 183: 0.026830965024212462316455525522, 184: 0.026759618890909262255904959937, 185: 0.026694402397772307494142902682,\n    186: 0.026628562480806788083419395933, 187: 0.026559941263661300415645214219, 188: 0.026481836582034051936486752627, 189: 0.026418244679312700122420563622, 190: 0.026356945834531737625798215145,\n    191: 0.026301706718658208003205227681, 192: 0.026217277472550386664091907177, 193: 0.026143153872289608320343518084, 194: 0.026090009644656685537127805711, 195: 0.026031575692805857916084558277,\n    196: 0.025979393498155145526485083124, 197: 0.025897762266875827827293625866, 198: 0.025839106920297322758487792545, 199: 0.025779262519934221294384208306, 200: 0.025723048767509291047570635402,\n    201: 0.025653933362478751978855219461, 202: 0.025589600144422698213793905466, 203: 0.025519926593477311758998864688, 204: 0.025457740774352259486593906413, 205: 0.025406659007510064745367639302,\n    206: 0.025362283181242228576113944153, 207: 0.025302051136799496814026538263, 208: 0.025222004336150521928974970167, 209: 0.025175336841918742608446819842, 210: 0.025117491728966094908613964622,\n    211: 0.025053583413564635206227266747, 212: 0.024997342920455157872331172621, 213: 0.024938559239068401501841698218, 214: 0.024894039188596702510818019333, 215: 0.024832199755073649527129579499,\n    216: 0.024776189239358497881503578295, 217: 0.024716995098687883659283173566, 218: 0.024660255999680444257989072772, 219: 0.024610786519706540202334921455, 220: 0.024553790242187925846914301087,\n    221: 0.024507150869603175041801699663, 222: 0.024454280555957871615986199862, 223: 0.024392870678124406746824084702, 224: 0.024336068923688238964020316432, 225: 0.024285842720377864942836582015,\n    226: 0.024237005896011575333122316744, 227: 0.024200644133549477487370497739, 228: 0.024132388434212972399450034989, 229: 0.024084500459467290103007722168, 230: 0.024036148148198053021410571416,\n    231: 0.023986316043926012758399259040, 232: 0.023935164074611907684427262278, 233: 0.023893526215715307133559732738, 234: 0.023843951158961837355723027786, 235: 0.023789163431004572040761513113,\n    236: 0.023743899908977693673052675853, 237: 0.023695255577671141004767540353, 238: 0.023646080813452248897244692365, 239: 0.023588960994927703479526497723, 240: 0.023540144212784773869791745828,\n    241: 0.023489510803114194681394161845, 242: 0.023449691072916169631910709134, 243: 0.023402793568819185372229773591, 244: 0.023361701426167729351469291911, 245: 0.023309894997663702713759402136,\n    246: 0.023260295185694073822574375711, 247: 0.023220619522626652354396589463, 248: 0.023168220061789816647317582681, 249: 0.023128949875853259864392333018, 250: 0.023079967224267566546971350123,\n    251: 0.023035567155365513321671194263, 252: 0.022990008318987469857239762320, 253: 0.022944466813648199355759296254, 254: 0.022895468700979210923055041016, 255: 0.022858649079053652195678937719,\n    256: 0.022823354557619637628769097697, 257: 0.022778605996431135977367687870, 258: 0.022734369655630379315260803513, 259: 0.022695320701969673119656578088, 260: 0.022647631758477380235674196963,\n    261: 0.022610418449000517419990391520, 262: 0.022570701609367717300745092083, 263: 0.022529136858314441215856762693, 264: 0.022495082146221514494580806220, 265: 0.022444160230695194823588056264,\n    266: 0.022398697814338573794248496356, 267: 0.022363264304949120895764261604, 268: 0.022317605020243469805457169785, 269: 0.022290287491545429323127887859, 270: 0.022245690608903079690293744197,\n    271: 0.022195409688557981616261999271, 272: 0.022160697725320837229754005722, 273: 0.022117229076365001134750496389, 274: 0.022086131505356453817858168329, 275: 0.022055886261172340114160973353,\n    276: 0.022010358605427197713609911864, 277: 0.021971840901308172088323012152, 278: 0.021924249634895798156805791058, 279: 0.021885676951730618952621482638, 280: 0.021853005235358596381471286167,\n    281: 0.021819887352002277079957747134, 282: 0.021786052404929988593179584923, 283: 0.021745284972951021241503348584, 284: 0.021695998052797688780586047086, 285: 0.021661292323165651734278444524,\n    286: 0.021631326997472829715029431219, 287: 0.021589188419877711311659524984, 288: 0.021555939988186400630352833205, 289: 0.021531503839036265433328712811, 290: 0.021489806016526542749545618876,\n    291: 0.021449966547123511348330417476, 292: 0.021424778601857855307697129991, 293: 0.021384735887631629126041174492, 294: 0.021346547960303288556739989055, 295: 0.021316856358852165442437038758,\n    296: 0.021275607176299788668150888244, 297: 0.021237377022300491080809459535, 298: 0.021208993940380620791808476959, 299: 0.021163661683864621636684778115,\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], c[1], (1 - c[0] - c[1]) / math.sqrt(2))\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\"crt|{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], c[1], (1 - c[0] - c[1]) / math.sqrt(2))\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"}}