diff --git a/results.json b/results.json index 0bc7861..03b8ba4 100644 --- a/results.json +++ b/results.json @@ -1,62 +1,62 @@ { "openrouter/polaris-alpha": { - "1_dijkstra": 5.063492935, - "2_convex_hull": 7.998615312, - "3_lis": 2.2021910790000003, - "4_determinant": 2.4727166589999996, - "5_markdown_parser": 2.1889706240000013, - "6_csv_processor": 6.424773092, - "7_scheduler": 19.749020437, - "8_json_validator": 3.7860971980000033 + "1_dijkstra": 5.663508702, + "2_convex_hull": 5.853618222000001, + "3_lis": 2.7803642009999985, + "4_determinant": 2.2549030789999995, + "5_markdown_parser": 2.428845373, + "6_csv_processor": 7.004516176000001, + "7_scheduler": 14.370537171, + "8_json_validator": 4.488872165000001 }, "google/gemini-2.5-pro TEMP:0.7": { - "1_dijkstra": 30.986608248000003, - "2_convex_hull": 58.090286611, - "3_lis": 39.50342178599999, - "4_determinant": 21.314621672999987, - "5_markdown_parser": 21.140068067999994, - "6_csv_processor": 46.383014058, - "7_scheduler": 74.787878823, - "8_json_validator": 39.59319957399997 + "1_dijkstra": 44.600899471, + "2_convex_hull": 37.66833377400001, + "3_lis": 15.942395212000017, + "4_determinant": 14.880486881999998, + "5_markdown_parser": 22.373131437000005, + "6_csv_processor": 44.242416465999995, + "7_scheduler": 59.66216159599999, + "8_json_validator": 56.66983818199998 }, "anthropic/claude-sonnet-4.5": { - "1_dijkstra": 4.355259537999983, - "2_convex_hull": 4.980808106000011, - "3_lis": 2.2764143039999762, - "4_determinant": 1.8504535560000221, - "5_markdown_parser": 1.841865622000012, - "6_csv_processor": 4.9831007339999775, - "7_scheduler": 12.904369474000006, - "8_json_validator": 2.7832529310000247 + "1_dijkstra": 4.15588515399996, + "2_convex_hull": 4.806273176999995, + "3_lis": 2.2488794699999852, + "4_determinant": 1.442708507000003, + "5_markdown_parser": 2.1533864889999967, + "6_csv_processor": 4.5494161339999994, + "7_scheduler": 13.169441607000016, + "8_json_validator": 2.83180839000002 }, "anthropic/claude-sonnet-4.5 TEMP:0.7": { - "1_dijkstra": 3.933310278000019, - "2_convex_hull": 4.819035326000012, - "3_lis": 2.34827887899999, - "4_determinant": 1.644420714000007, - "5_markdown_parser": 2.280882503999979, - "6_csv_processor": 4.7151394149999835, - "7_scheduler": 13.658607328000013, - "8_json_validator": 3.4110046910000382 + "1_dijkstra": 4.402104449000035, + "2_convex_hull": 5.400227270999982, + "3_lis": 4.495708809000033, + "4_determinant": 1.8576504829999758, + "5_markdown_parser": 1.8857627109999884, + "6_csv_processor": 4.558546455000004, + "7_scheduler": 11.452500546000024, + "8_json_validator": 2.654919869999983 }, "anthropic/claude-sonnet-4.5 TEMP:0.4": { - "1_dijkstra": 3.954044443999999, - "2_convex_hull": 4.5914942489999815, - "3_lis": 2.4153946509999806, - "4_determinant": 1.7196861260000151, - "5_markdown_parser": 1.801734215000004, - "6_csv_processor": 4.646366793999972, - "7_scheduler": 12.781063763999962, - "8_json_validator": 3.3014615179999964 + "1_dijkstra": 4.231384166999953, + "2_convex_hull": 4.297011561000021, + "3_lis": 2.270648061999993, + "4_determinant": 1.5894071249999688, + "5_markdown_parser": 1.8096978460000246, + "6_csv_processor": 4.622239387999987, + "7_scheduler": 12.332949335000013, + "8_json_validator": 2.6777597769999995 }, "openai/gpt-5-codex": { - "1_dijkstra": 36.88321140999993, - "2_convex_hull": 26.59820080500003, - "3_lis": 12.8049466599999, - "4_determinant": 10.523928330000023, - "5_markdown_parser": 57.74550891099998, - "6_csv_processor": 105.18542238100001, - "7_scheduler": 127.650813921, - "8_json_validator": 24.58168081499997 + "1_dijkstra": 86.38025543199991, + "2_convex_hull": 37.86684929500008, + "3_lis": 9.727075501000042, + "4_determinant": 8.948688077000087, + "5_markdown_parser": 8.000620244999999, + "6_csv_processor": 31.738115685999976, + "7_scheduler": 155.32837211300003, + "8_json_validator": 27.551844137000035 } } \ No newline at end of file diff --git a/tests/1_dijkstra/outputs/anthropic_claude-sonnet-4.5 TEMP_0.4.js b/tests/1_dijkstra/outputs/anthropic_claude-sonnet-4.5 TEMP_0.4.js index f249712..edc9c65 100644 --- a/tests/1_dijkstra/outputs/anthropic_claude-sonnet-4.5 TEMP_0.4.js +++ b/tests/1_dijkstra/outputs/anthropic_claude-sonnet-4.5 TEMP_0.4.js @@ -1,28 +1,31 @@ async function findShortestPath(graph, start, end) { const { default: PriorityQueue } = await import('https://cdn.skypack.dev/js-priority-queue'); - const distances = {}; - const pq = new PriorityQueue({ comparator: (a, b) => a.dist - b.dist }); + const dist = Object.keys(graph).reduce((acc, node) => ({ ...acc, [node]: Infinity }), {}); + dist[start] = 0; - for (const node in graph) distances[node] = Infinity; - distances[start] = 0; - pq.queue({ node: start, dist: 0 }); + const pq = new PriorityQueue({ comparator: (a, b) => a[1] - b[1] }); + pq.queue([start, 0]); + + const visited = new Set(); while (pq.length) { - const { node, dist } = pq.dequeue(); + const [node, d] = pq.dequeue(); - if (node === end) return dist; - if (dist > distances[node]) continue; + if (visited.has(node)) continue; + visited.add(node); - for (const neighbor in graph[node]) { - const newDist = dist + graph[node][neighbor]; - if (newDist < distances[neighbor]) { - distances[neighbor] = newDist; - pq.queue({ node: neighbor, dist: newDist }); + if (node === end) return d; + + for (const [neighbor, weight] of Object.entries(graph[node] || {})) { + const newDist = d + weight; + if (newDist < dist[neighbor]) { + dist[neighbor] = newDist; + pq.queue([neighbor, newDist]); } } } - return distances[end]; + return dist[end]; } export default findShortestPath; \ No newline at end of file diff --git a/tests/1_dijkstra/outputs/anthropic_claude-sonnet-4.5 TEMP_0.7.js b/tests/1_dijkstra/outputs/anthropic_claude-sonnet-4.5 TEMP_0.7.js index a7afc4b..f7cf502 100644 --- a/tests/1_dijkstra/outputs/anthropic_claude-sonnet-4.5 TEMP_0.7.js +++ b/tests/1_dijkstra/outputs/anthropic_claude-sonnet-4.5 TEMP_0.7.js @@ -1,19 +1,15 @@ async function findShortestPath(graph, start, end) { - const { default: PriorityQueue } = await import('https://cdn.skypack.dev/js-priority-queue'); + const { default: PQ } = await import('https://cdn.jsdelivr.net/npm/js-priority-queue@0.1.5/+esm'); const dist = { [start]: 0 }; - const pq = new PriorityQueue({ comparator: (a, b) => a[1] - b[1] }); - const visited = new Set(); - + const pq = new PQ({ comparator: (a, b) => a[1] - b[1] }); pq.queue([start, 0]); while (pq.length) { const [node, d] = pq.dequeue(); - if (visited.has(node)) continue; - visited.add(node); - if (node === end) return d; + if (d > (dist[node] ?? Infinity)) continue; for (const [neighbor, weight] of Object.entries(graph[node] || {})) { const newDist = d + weight; diff --git a/tests/1_dijkstra/outputs/google_gemini-2.5-pro TEMP_0.7.js b/tests/1_dijkstra/outputs/google_gemini-2.5-pro TEMP_0.7.js index 256b59c..62431a3 100644 --- a/tests/1_dijkstra/outputs/google_gemini-2.5-pro TEMP_0.7.js +++ b/tests/1_dijkstra/outputs/google_gemini-2.5-pro TEMP_0.7.js @@ -1,33 +1,32 @@ -const findShortestPath = async (graph, start, end) => { - const cdn = 'https://cdn.jsdelivr.net/npm/js-priority-queue@0.1.5/priority-queue.min.js'; - const { default: PriorityQueue } = await import(cdn); +async function findShortestPath(graph, startNode, endNode) { + const { default: PriorityQueue } = await import('https://cdn.jsdelivr.net/npm/js-priority-queue@0.1.5/priority-queue.min.js'); - const distances = Object.fromEntries( - Object.keys(graph).map(node => [node, Infinity]) - ); - distances[start] = 0; + const dist = {}; + const pq = new PriorityQueue({ comparator: (a, b) => dist[a] - dist[b] }); - const pq = new PriorityQueue({ - comparator: (a, b) => a.priority - b.priority - }); - pq.queue({ value: start, priority: 0 }); + for (const vertex in graph) { + dist[vertex] = Infinity; + } + dist[startNode] = 0; + + pq.queue(startNode); while (pq.length) { - const { value: current } = pq.dequeue(); + const u = pq.dequeue(); - if (current === end) break; + if (u === endNode) break; + if (!graph[u] || dist[u] === Infinity) continue; - const neighbors = graph[current] || {}; - for (const [neighbor, weight] of Object.entries(neighbors)) { - const newDist = distances[current] + weight; + for (const v in graph[u]) { + const newDist = dist[u] + graph[u][v]; - if (newDist < distances[neighbor]) { - distances[neighbor] = newDist; - pq.queue({ value: neighbor, priority: newDist }); + if (newDist < dist[v]) { + dist[v] = newDist; + pq.queue(v); } } } - return distances[end]; -}; + return dist[endNode] ?? Infinity; +} export default findShortestPath; \ No newline at end of file diff --git a/tests/1_dijkstra/outputs/openai_gpt-5-codex.js b/tests/1_dijkstra/outputs/openai_gpt-5-codex.js index 8cfe929..e42ca2a 100644 --- a/tests/1_dijkstra/outputs/openai_gpt-5-codex.js +++ b/tests/1_dijkstra/outputs/openai_gpt-5-codex.js @@ -1,24 +1,29 @@ -let u -const o=()=>u||(u=import('https://cdn.skypack.dev/js-priority-queue').then(r=>r.default||r)) -async function findShortestPath(g,s,t){ -const PQ=await o() -if(s===t)return 0 -const d={},q=new PQ({comparator:(a,b)=>a[1]-b[1]}) -for(const k in g)d[k]=Infinity -d[s]=0 -q.queue([s,0]) -while(q.length){ -const[n,w]=q.dequeue() -if(w>d[n])continue -if(n===t)return w -for(const[nb,c]of Object.entries(g[n]||{})){ -const nw=w+c -if(nwpq||(pq=import('https://cdn.skypack.dev/js-priority-queue').then(m=>m.default)); + +async function findShortestPath(graph,start,end){ + const PQ=await loadPQ(); + if(start===end) return 0; + if(!graph||typeof graph!=='object') return Infinity; + const d=new Map([[start,0]]); + const q=new PQ({comparator:(a,b)=>a[0]-b[0]}); + q.queue([0,start]); + while(q.length){ + const [w,n]=q.dequeue(); + if(w>(d.get(n)??Infinity)) continue; + if(n===end) return w; + const edges=graph[n]; + if(!edges||typeof edges!=='object') continue; + for(const k of Object.keys(edges)){ + const c=edges[k]; + if(typeof c!=='number'||c<0||!Number.isFinite(c)) continue; + const nw=w+c; + if(nw<(d.get(k)??Infinity)){ + d.set(k,nw); + q.queue([nw,k]); + } + } + } + return Infinity; } export default findShortestPath; \ No newline at end of file diff --git a/tests/1_dijkstra/outputs/openrouter_polaris-alpha.js b/tests/1_dijkstra/outputs/openrouter_polaris-alpha.js index ea58b63..8846d4b 100644 --- a/tests/1_dijkstra/outputs/openrouter_polaris-alpha.js +++ b/tests/1_dijkstra/outputs/openrouter_polaris-alpha.js @@ -1,24 +1,30 @@ async function findShortestPath(g,s,e){ - if(!g||!g[s]||!g[e])return Infinity - const{default:PriorityQueue}=await import('https://cdn.jsdelivr.net/npm/js-priority-queue@0.1.5/js/priority-queue.min.js') - const d={},v={} - Object.keys(g).forEach(k=>d[k]=k===s?0:Infinity) - const q=new PriorityQueue({comparator:(a,b)=>a.w-b.w}) - q.queue({n:s,w:0}) - while(q.length){ - const{n,w}=q.dequeue() - if(v[n])continue - v[n]=1 - if(n===e)return w - const nbrs=g[n] - for(const x in nbrs){ - const nw=w+nbrs[x] - if(nw({default:class{ + constructor(o){this.c=o.comparator||((a,b)=>a-b);this.q=[]} + queue(v){this.q.push(v);this.q.sort(this.c)} + dequeue(){return this.q.shift()} + peek(){return this.q[0]} + get length(){return this.q.length} + }})); + if(!g||!g[s]||!g[e])return Infinity; + const d={},v={},pq=new PriorityQueue({comparator:(a,b)=>a.w-b.w}); + for(const n in g)d[n]=Infinity; + d[s]=0; + pq.queue({n:s,w:0}); + while(pq.length){ + const {n,w}=pq.dequeue(); + if(v[n])continue; + v[n]=1; + if(n===e)return w; + const nb=g[n]; + for(const k in nb){ + const nw=w+nb[k]; + if(nw m.default); + const { sortBy, uniqWith } = await import('https://cdn.jsdelivr.net/npm/lodash-es@4.17.21/lodash.js'); if (points.length < 3) return points; - const sorted = _.sortBy(_.uniqWith(points, _.isEqual), ['x', 'y']); + const sorted = sortBy(uniqWith(points, (a, b) => a.x === b.x && a.y === b.y), ['x', 'y']); if (sorted.length < 3) return sorted; const cross = (o, a, b) => (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x); - const buildHull = arr => { + const buildHull = pts => { const hull = []; - for (const p of arr) { + for (const p of pts) { while (hull.length >= 2 && cross(hull[hull.length - 2], hull[hull.length - 1], p) <= 0) { hull.pop(); } @@ -21,9 +21,6 @@ async function findConvexHull(points) { return hull; }; - const lower = buildHull(sorted); - const upper = buildHull([...sorted].reverse()); - - return [...lower, ...upper].reverse(); + return [...buildHull(sorted), ...buildHull(sorted.slice().reverse())]; } export default findConvexHull; \ No newline at end of file diff --git a/tests/2_convex_hull/outputs/anthropic_claude-sonnet-4.5.js b/tests/2_convex_hull/outputs/anthropic_claude-sonnet-4.5.js index 5021050..9c4ac7d 100644 --- a/tests/2_convex_hull/outputs/anthropic_claude-sonnet-4.5.js +++ b/tests/2_convex_hull/outputs/anthropic_claude-sonnet-4.5.js @@ -1,15 +1,15 @@ -const findConvexHull = async (points) => { - const { sortBy, uniqWith } = await import('https://cdn.jsdelivr.net/npm/lodash-es@4.17.21/lodash.min.js'); +async function findConvexHull(points) { + const _ = await import('https://cdn.jsdelivr.net/npm/lodash-es@4.17.21/lodash.min.js').then(m => m.default); if (points.length < 3) return points; - const sorted = sortBy(uniqWith(points, (a, b) => a.x === b.x && a.y === b.y), ['x', 'y']); + const sorted = _.sortBy(_.uniqWith(points, _.isEqual), ['x', 'y']); if (sorted.length < 3) return sorted; const cross = (o, a, b) => (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x); - const buildHalf = (pts) => { + const buildHull = pts => { const hull = []; for (const p of pts) { while (hull.length >= 2 && cross(hull[hull.length - 2], hull[hull.length - 1], p) <= 0) { @@ -21,9 +21,6 @@ const findConvexHull = async (points) => { return hull; }; - const lower = buildHalf(sorted); - const upper = buildHalf([...sorted].reverse()); - - return [...lower, ...upper].reverse(); -}; + return [...buildHull(sorted), ...buildHull(sorted.slice().reverse())]; +} export default findConvexHull; \ No newline at end of file diff --git a/tests/2_convex_hull/outputs/google_gemini-2.5-pro TEMP_0.7.js b/tests/2_convex_hull/outputs/google_gemini-2.5-pro TEMP_0.7.js index 1a2c810..7fa0b27 100644 --- a/tests/2_convex_hull/outputs/google_gemini-2.5-pro TEMP_0.7.js +++ b/tests/2_convex_hull/outputs/google_gemini-2.5-pro TEMP_0.7.js @@ -1,29 +1,29 @@ async function findConvexHull(points) { - const _ = await import('https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js'); + const { sortBy, uniqWith, isEqual } = await import('https://cdn.jsdelivr.net/npm/lodash-es@4.17.21/+esm'); - const sortedUniquePoints = _.uniqWith(_.sortBy(points, ['x', 'y']), _.isEqual); - - if (sortedUniquePoints.length < 3) { - return sortedUniquePoints; + if (points.length < 3) { + return [...points]; } const crossProduct = (p1, p2, p3) => (p2.x - p1.x) * (p3.y - p1.y) - (p2.y - p1.y) * (p3.x - p1.x); - const buildHalfHull = (pts) => { - const hull = []; - for (const p of pts) { - while (hull.length >= 2 && crossProduct(hull.at(-2), hull.at(-1), p) <= 0) { + const sortedPoints = sortBy(points, ['x', 'y']); + + const buildHull = (pts) => + pts.reduce((hull, p) => { + while (hull.length >= 2 && crossProduct(hull[hull.length - 2], hull.at(-1), p) <= 0) { hull.pop(); } hull.push(p); - } - return hull; - }; + return hull; + }, []); - const lowerHull = buildHalfHull(sortedUniquePoints); - const upperHull = buildHalfHull([...sortedUniquePoints].reverse()); + const lowerHull = buildHull(sortedPoints); + const upperHull = buildHull([...sortedPoints].reverse()); - return [...upperHull.slice(0, -1), ...lowerHull.slice(0, -1)]; + const combinedHull = [...lowerHull, ...upperHull]; + + return uniqWith(combinedHull, isEqual); } export default findConvexHull; \ No newline at end of file diff --git a/tests/2_convex_hull/outputs/openai_gpt-5-codex.js b/tests/2_convex_hull/outputs/openai_gpt-5-codex.js index 7d1c3d4..3c72018 100644 --- a/tests/2_convex_hull/outputs/openai_gpt-5-codex.js +++ b/tests/2_convex_hull/outputs/openai_gpt-5-codex.js @@ -1,19 +1,15 @@ -async function findConvexHull(points){ - const {default:_}=await import('https://cdn.skypack.dev/lodash-es'); - const pts=_.uniqWith(_.sortBy(points,['x','y']),(a,b)=>a.x===b.x&&a.y===b.y); - if(pts.length<3) return pts.slice(); - const c=(o,a,b)=>(a.x-o.x)*(b.y-o.y)-(a.y-o.y)*(b.x-o.x); - const l=[],u=[]; - for(const p of pts){ - while(l.length>1&&c(l.at(-2),l.at(-1),p)<=0)l.pop(); - l.push(p); - } - for(let i=pts.length;i--;){ - const p=pts[i]; - while(u.length>1&&c(u.at(-2),u.at(-1),p)<=0)u.pop(); - u.push(p); - } - l.pop();u.pop(); - return [...l,...u].reverse(); +let h +const findConvexHull=async v=>{ + const {sortBy,uniqWith,isEqual}=await(h??=import('https://cdn.jsdelivr.net/npm/lodash-es@4.17.21/+esm')) + const s=uniqWith(sortBy(v,['x','y']),isEqual) + if(s.length<3)return s.slice() + const r=(o,a,b)=>(a.x-o.x)*(b.y-o.y)-(a.y-o.y)*(b.x-o.x) + const l=[] + for(const p of s){while(l.length>1&&r(l.at(-2),l.at(-1),p)<=0)l.pop();l.push(p)} + const u=[] + for(let i=s.length;i--;){const p=s[i];while(u.length>1&&r(u.at(-2),u.at(-1),p)<=0)u.pop();u.push(p)} + l.pop() + u.pop() + return l.concat(u) } export default findConvexHull; \ No newline at end of file diff --git a/tests/2_convex_hull/outputs/openrouter_polaris-alpha.js b/tests/2_convex_hull/outputs/openrouter_polaris-alpha.js index 2e5473c..2ba39e7 100644 --- a/tests/2_convex_hull/outputs/openrouter_polaris-alpha.js +++ b/tests/2_convex_hull/outputs/openrouter_polaris-alpha.js @@ -1,29 +1,23 @@ async function findConvexHull(points) { - if (!Array.isArray(points) || points.length < 3) return points || []; + if (!Array.isArray(points) || points.length < 1) return []; const { default: _ } = await import('https://cdn.jsdelivr.net/npm/lodash-es@4.17.21/lodash.default.min.js'); - const ps = _.uniqWith(points, (a, b) => a.x === b.x && a.y === b.y); - if (ps.length < 3) return ps; - const pts = _.sortBy(ps, ['x', 'y']); - const cross = (o, a, b) => (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x); - const lower = []; + const s = _.uniqBy(points, p => `${p.x},${p.y}`); + if (s.length < 2) return s.slice(); + const pts = _.sortBy(s, ['x', 'y']); + const c = (o, a, b) => (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x); + const l = []; for (let p of pts) { - for (; lower.length >= 2 && cross(lower[lower.length - 2], lower[lower.length - 1], p) <= 0;) lower.pop(); - lower.push(p); + for (; l.length > 1 && c(l[l.length - 2], l[l.length - 1], p) <= 0;) l.pop(); + l.push(p); } - const upper = []; + const u = []; for (let i = pts.length - 1; i >= 0; i--) { const p = pts[i]; - for (; upper.length >= 2 && cross(upper[upper.length - 2], upper[upper.length - 1], p) <= 0;) upper.pop(); - upper.push(p); + for (; u.length > 1 && c(u[u.length - 2], u[u.length - 1], p) <= 0;) u.pop(); + u.push(p); } - const hull = lower.slice(0, -1).concat(upper.slice(0, -1)); - if (hull.length <= 2) return hull; - let area = 0; - for (let i = 0; i < hull.length; i++) { - const j = (i + 1) % hull.length; - area += hull[i].x * hull[j].y - hull[j].x * hull[i].y; - } - if (area > 0) hull.reverse(); - return hull; + l.pop(); + u.pop(); + return l.concat(u); } export default findConvexHull; \ No newline at end of file diff --git a/tests/3_lis/outputs/anthropic_claude-sonnet-4.5 TEMP_0.4.js b/tests/3_lis/outputs/anthropic_claude-sonnet-4.5 TEMP_0.4.js index a325e10..3e87752 100644 --- a/tests/3_lis/outputs/anthropic_claude-sonnet-4.5 TEMP_0.4.js +++ b/tests/3_lis/outputs/anthropic_claude-sonnet-4.5 TEMP_0.4.js @@ -1,7 +1,8 @@ const findLISLength = async (arr) => { if (!arr?.length) return 0; - const { bisectLeft } = await import('https://cdn.skypack.dev/d3-array'); + const { bisectLeft } = await import('https://cdn.jsdelivr.net/npm/d3-array@3/+esm'); + const tails = []; for (const num of arr) { diff --git a/tests/3_lis/outputs/anthropic_claude-sonnet-4.5 TEMP_0.7.js b/tests/3_lis/outputs/anthropic_claude-sonnet-4.5 TEMP_0.7.js index b3d6589..f7203e0 100644 --- a/tests/3_lis/outputs/anthropic_claude-sonnet-4.5 TEMP_0.7.js +++ b/tests/3_lis/outputs/anthropic_claude-sonnet-4.5 TEMP_0.7.js @@ -1,15 +1,15 @@ -async function findLISLength(arr) { - const { bisectLeft } = await import('https://cdn.skypack.dev/d3-array'); +const findLISLength = async (nums) => { + const { bisectLeft } = await import('https://cdn.jsdelivr.net/npm/d3-array@3/+esm'); - if (!arr?.length) return 0; + if (!nums?.length) return 0; const tails = []; - for (const num of arr) { + for (const num of nums) { const pos = bisectLeft(tails, num); tails[pos] = num; } return tails.length; -} +}; export default findLISLength; \ No newline at end of file diff --git a/tests/3_lis/outputs/anthropic_claude-sonnet-4.5.js b/tests/3_lis/outputs/anthropic_claude-sonnet-4.5.js index fd86b86..e05eaf8 100644 --- a/tests/3_lis/outputs/anthropic_claude-sonnet-4.5.js +++ b/tests/3_lis/outputs/anthropic_claude-sonnet-4.5.js @@ -1,15 +1,15 @@ -async function findLISLength(nums) { - if (!nums?.length) return 0; +const findLISLength = async (nums) => { + const { bisectLeft } = await import('https://cdn.jsdelivr.net/npm/d3-array@3/+esm'); - const { bisectLeft } = await import('https://cdn.skypack.dev/d3-array'); + if (!nums?.length) return 0; const tails = []; for (const num of nums) { - const pos = bisectLeft(tails, num); - tails[pos] = num; + const idx = bisectLeft(tails, num); + tails[idx] = num; } return tails.length; -} +}; export default findLISLength; \ No newline at end of file diff --git a/tests/3_lis/outputs/google_gemini-2.5-pro TEMP_0.7.js b/tests/3_lis/outputs/google_gemini-2.5-pro TEMP_0.7.js index 44a9648..92b83fe 100644 --- a/tests/3_lis/outputs/google_gemini-2.5-pro TEMP_0.7.js +++ b/tests/3_lis/outputs/google_gemini-2.5-pro TEMP_0.7.js @@ -1,15 +1,15 @@ const findLISLength = async (nums) => { - if (!nums?.length) { - return 0; + if (!nums?.length) return 0; + + const { bisectLeft } = await import('https://cdn.jsdelivr.net/npm/d3-array@3/+esm'); + + const tails = []; + + for (const num of nums) { + const i = bisectLeft(tails, num); + tails[i] = num; } - const { bisectLeft } = await import("https://cdn.jsdelivr.net/npm/d3-array@3"); - - const tails = nums.reduce((sub, num) => { - sub[bisectLeft(sub, num)] = num; - return sub; - }, []); - return tails.length; }; export default findLISLength; \ No newline at end of file diff --git a/tests/3_lis/outputs/openai_gpt-5-codex.js b/tests/3_lis/outputs/openai_gpt-5-codex.js index 65ed793..a14bd34 100644 --- a/tests/3_lis/outputs/openai_gpt-5-codex.js +++ b/tests/3_lis/outputs/openai_gpt-5-codex.js @@ -1,14 +1,14 @@ -const findLISLength=async a=>{ - if(!Array.isArray(a)) throw new TypeError('Expected an array') - const {bisectLeft:b}=await (findLISLength.m??=import('https://cdn.jsdelivr.net/npm/d3-array@3/+esm')) - const t=[] - for(const v of a){ - if(!Number.isFinite(v)) throw new TypeError('Array values must be finite numbers') - const i=b(t,v) - if(i===t.length) t.push(v) - else t[i]=v +let l; +const m=()=>l??=import('https://cdn.jsdelivr.net/npm/d3-array@3/+esm').then(({bisectLeft})=>bisectLeft); +export async function findLISLength(a){ + if(!Array.isArray(a)) throw new TypeError('Expected array'); + const b=await m(); + const t=[]; + for(const n of a){ + if(typeof n!=='number'||!Number.isFinite(n)) throw new TypeError('Expected finite numbers'); + const i=b(t,n); + t[i]=n; } - return t.length + return t.length; } -window.findLISLength=findLISLength export default findLISLength; \ No newline at end of file diff --git a/tests/4_determinant/outputs/google_gemini-2.5-pro TEMP_0.7.js b/tests/4_determinant/outputs/google_gemini-2.5-pro TEMP_0.7.js index c98689d..e551fc7 100644 --- a/tests/4_determinant/outputs/google_gemini-2.5-pro TEMP_0.7.js +++ b/tests/4_determinant/outputs/google_gemini-2.5-pro TEMP_0.7.js @@ -1,5 +1,5 @@ -const calculateDeterminant = async m => { - const { det } = await import('https://cdn.jsdelivr.net/npm/mathjs@13.0.0/es/math.mjs'); - return det(m); +const calculateDeterminant = async (matrix) => { + const { det } = await import('https://cdn.jsdelivr.net/npm/mathjs@13.0.0/es/index.js'); + return det(matrix); }; export default calculateDeterminant; \ No newline at end of file diff --git a/tests/4_determinant/outputs/openai_gpt-5-codex.js b/tests/4_determinant/outputs/openai_gpt-5-codex.js index ff7c9a6..c792e85 100644 --- a/tests/4_determinant/outputs/openai_gpt-5-codex.js +++ b/tests/4_determinant/outputs/openai_gpt-5-codex.js @@ -1,5 +1,7 @@ -async function calculateDeterminant(m){ - const {det}=await import('https://cdn.jsdelivr.net/npm/mathjs@11.11.0/dist/esm/math.js') - return det(m) +let c +const m=()=>c||(c=import('https://cdn.jsdelivr.net/npm/mathjs@11.11.1/+esm')) +async function calculateDeterminant(a){ + const{det}=await m() + return det(a) } export default calculateDeterminant; \ No newline at end of file diff --git a/tests/4_determinant/outputs/openrouter_polaris-alpha.js b/tests/4_determinant/outputs/openrouter_polaris-alpha.js index 3432fbe..fa2ec91 100644 --- a/tests/4_determinant/outputs/openrouter_polaris-alpha.js +++ b/tests/4_determinant/outputs/openrouter_polaris-alpha.js @@ -1,7 +1,7 @@ async function calculateDeterminant(m){ - if(!Array.isArray(m)||!m.length||!m.every(r=>Array.isArray(r)&&r.length===m.length))throw new Error('Input must be an n x n matrix'); - const {create,all,det}=await import('https://cdn.jsdelivr.net/npm/mathjs@11.11.0/+esm'); - const math=create(all); - return math.det(m); + if(!Array.isArray(m)||!m.length||!m.every(r=>Array.isArray(r)&&r.length===m.length))throw new Error('Matrix must be square') + const {create,all} = await import('https://cdn.jsdelivr.net/npm/mathjs@11.11.0/+esm') + const math = create(all) + return math.det(m) } export default calculateDeterminant; \ No newline at end of file diff --git a/tests/5_markdown_parser/outputs/anthropic_claude-sonnet-4.5 TEMP_0.7.js b/tests/5_markdown_parser/outputs/anthropic_claude-sonnet-4.5 TEMP_0.7.js index 0476b36..9bf74ee 100644 --- a/tests/5_markdown_parser/outputs/anthropic_claude-sonnet-4.5 TEMP_0.7.js +++ b/tests/5_markdown_parser/outputs/anthropic_claude-sonnet-4.5 TEMP_0.7.js @@ -1,5 +1,5 @@ -async function parseMarkdown(md) { +const parseMarkdown = async (md) => { const { marked } = await import('https://cdn.jsdelivr.net/npm/marked@11.1.1/+esm'); return marked.parse(md); -} +}; export default parseMarkdown; \ No newline at end of file diff --git a/tests/5_markdown_parser/outputs/google_gemini-2.5-pro TEMP_0.7.js b/tests/5_markdown_parser/outputs/google_gemini-2.5-pro TEMP_0.7.js index 53fd2f4..108da51 100644 --- a/tests/5_markdown_parser/outputs/google_gemini-2.5-pro TEMP_0.7.js +++ b/tests/5_markdown_parser/outputs/google_gemini-2.5-pro TEMP_0.7.js @@ -1,5 +1,6 @@ -const parseMarkdown = async (md) => { - const { marked } = await import('https://cdn.jsdelivr.net/npm/marked@5/+esm'); - return marked.parse(md); -}; +async function parseMarkdown(markdown) { + const cdn = 'https://cdn.jsdelivr.net/npm/marked@12/lib/marked.esm.js'; + const { marked } = await import(cdn); + return marked.parse(markdown); +} export default parseMarkdown; \ No newline at end of file diff --git a/tests/5_markdown_parser/outputs/openai_gpt-5-codex.js b/tests/5_markdown_parser/outputs/openai_gpt-5-codex.js index 6b5f9f9..004f2e9 100644 --- a/tests/5_markdown_parser/outputs/openai_gpt-5-codex.js +++ b/tests/5_markdown_parser/outputs/openai_gpt-5-codex.js @@ -1,15 +1,6 @@ -let md,pd -const getMd=()=>md||(md=import('https://cdn.jsdelivr.net/npm/marked@12.0.2/+esm').then(x=>{ - let m=x.marked||x.default - m.setOptions?.({gfm:true,breaks:true,smartypants:true}) - return s=>m.parse?m.parse(s):m(s) -})) -const getPurify=()=>pd||(pd=import('https://esm.sh/dompurify@3?target=es2020').then(x=>{ - let d=x.default||x.DOMPurify||x - return typeof d.sanitize=='function'?d:d(window) -})) -async function parseMarkdown(s){ - let [render,pur]=await Promise.all([getMd(),getPurify()]) - return pur.sanitize(render(s)) -} +const parseMarkdown=async t=>{ + parseMarkdown.l??=import('https://cdn.jsdelivr.net/npm/marked@12.0.2/lib/marked.esm.js'); + const{marked}=await parseMarkdown.l; + return marked.parse(t||''); +}; export default parseMarkdown; \ No newline at end of file diff --git a/tests/5_markdown_parser/outputs/openrouter_polaris-alpha.js b/tests/5_markdown_parser/outputs/openrouter_polaris-alpha.js index 03cdb80..22b7bd4 100644 --- a/tests/5_markdown_parser/outputs/openrouter_polaris-alpha.js +++ b/tests/5_markdown_parser/outputs/openrouter_polaris-alpha.js @@ -1,11 +1,14 @@ -async function parseMarkdown(markdown) { - const {marked} = await import('https://cdn.jsdelivr.net/npm/marked@12.0.2/lib/marked.esm.js') +async function parseMarkdown(md) { + if (typeof md !== "string") md = String(md ?? ""); + const [{ default: marked }] = await Promise.all([ + import("https://cdn.jsdelivr.net/npm/marked@12.0.2/lib/marked.esm.js") + ]); marked.setOptions({ - gfm:true, - breaks:false, - headerIds:true, - mangle:false - }) - return marked.parse(String(markdown ?? '')) + gfm: true, + breaks: false, + headerIds: true, + mangle: false + }); + return marked.parse(md); } export default parseMarkdown; \ No newline at end of file diff --git a/tests/6_csv_processor/outputs/anthropic_claude-sonnet-4.5 TEMP_0.4.js b/tests/6_csv_processor/outputs/anthropic_claude-sonnet-4.5 TEMP_0.4.js index b11ec62..5d216b6 100644 --- a/tests/6_csv_processor/outputs/anthropic_claude-sonnet-4.5 TEMP_0.4.js +++ b/tests/6_csv_processor/outputs/anthropic_claude-sonnet-4.5 TEMP_0.4.js @@ -1,26 +1,29 @@ -async function processCSV(csv, config) { - const { parse } = await import('https://cdn.skypack.dev/papaparse@5.4.1'); +const processCSV = async (csv, config) => { + const { parse } = await import('https://cdn.jsdelivr.net/npm/papaparse@5.4.1/+esm'); - const { filterColumn: fc, filterValue: fv, groupBy: gb, aggregateColumn: ac, operation: op } = config; const { data } = parse(csv, { header: true, skipEmptyLines: true }); - const filtered = data.filter(r => r[fc] == fv); + const filtered = data.filter(row => + String(row[config.filterColumn]).trim() === String(config.filterValue).trim() + ); + const grouped = filtered.reduce((acc, row) => { - const key = row[gb]; + const key = row[config.groupBy]; if (!acc[key]) acc[key] = []; acc[key].push(row); return acc; }, {}); - return Object.entries(grouped).map(([key, rows]) => { - const vals = rows.map(r => parseFloat(r[ac]) || 0); - const result = op === 'sum' - ? vals.reduce((a, b) => a + b, 0) - : op === 'avg' - ? vals.reduce((a, b) => a + b, 0) / vals.length - : vals.length; - - return { [gb]: key, result }; - }); -} + const aggregate = (rows) => { + const values = rows.map(r => parseFloat(r[config.aggregateColumn]) || 0); + if (config.operation === 'sum') return values.reduce((a, b) => a + b, 0); + if (config.operation === 'avg') return values.reduce((a, b) => a + b, 0) / values.length; + return values.length; + }; + + return Object.entries(grouped).map(([key, rows]) => ({ + [config.groupBy]: key, + result: aggregate(rows) + })); +}; export default processCSV; \ No newline at end of file diff --git a/tests/6_csv_processor/outputs/anthropic_claude-sonnet-4.5 TEMP_0.7.js b/tests/6_csv_processor/outputs/anthropic_claude-sonnet-4.5 TEMP_0.7.js index 750c4bf..01ae5d7 100644 --- a/tests/6_csv_processor/outputs/anthropic_claude-sonnet-4.5 TEMP_0.7.js +++ b/tests/6_csv_processor/outputs/anthropic_claude-sonnet-4.5 TEMP_0.7.js @@ -1,12 +1,12 @@ -const processCSV = async (csv, { filterColumn, filterValue, groupBy, aggregateColumn, operation }) => { - const { default: Papa } = await import('https://cdn.jsdelivr.net/npm/papaparse@5.4.1/+esm'); +const processCSV = async (csvString, config) => { + const { parse } = await import('https://cdn.skypack.dev/papaparse'); - const { data } = Papa.parse(csv, { header: true, skipEmptyLines: true }); + const { data } = parse(csvString, { header: true, skipEmptyLines: true }); - const filtered = data.filter(row => row[filterColumn] == filterValue); + const filtered = data.filter(row => row[config.filterColumn] == config.filterValue); const grouped = filtered.reduce((acc, row) => { - const key = row[groupBy]; + const key = row[config.groupBy]; if (!acc[key]) acc[key] = []; acc[key].push(row); return acc; @@ -14,17 +14,15 @@ const processCSV = async (csv, { filterColumn, filterValue, groupBy, aggregateCo return Object.entries(grouped).map(([key, rows]) => { let result; - - if (operation === 'count') { + if (config.operation === 'count') { result = rows.length; } else { - const values = rows.map(r => parseFloat(r[aggregateColumn]) || 0); - result = operation === 'sum' + const values = rows.map(r => parseFloat(r[config.aggregateColumn]) || 0); + result = config.operation === 'sum' ? values.reduce((a, b) => a + b, 0) : values.reduce((a, b) => a + b, 0) / values.length; } - - return { [groupBy]: key, [operation]: result }; + return { [config.groupBy]: key, result }; }); }; export default processCSV; \ No newline at end of file diff --git a/tests/6_csv_processor/outputs/anthropic_claude-sonnet-4.5.js b/tests/6_csv_processor/outputs/anthropic_claude-sonnet-4.5.js index 4565062..bc7c3af 100644 --- a/tests/6_csv_processor/outputs/anthropic_claude-sonnet-4.5.js +++ b/tests/6_csv_processor/outputs/anthropic_claude-sonnet-4.5.js @@ -1,30 +1,26 @@ -async function processCSV(csvString, config) { - const { parse } = await import('https://cdn.skypack.dev/papaparse@5.4.1'); +async function processCSV(csv, config) { + const { parse } = await import('https://esm.sh/papaparse@5.4.1'); + const { groupBy, sumBy, meanBy, countBy } = await import('https://esm.sh/lodash-es@4.17.21'); - const { filterColumn: fc, filterValue: fv, groupBy: gb, aggregateColumn: ac, operation: op } = config; + const { data } = parse(csv, { header: true, skipEmptyLines: true }); - const { data } = parse(csvString, { header: true, skipEmptyLines: true }); + const filtered = data.filter(row => + String(row[config.filterColumn]) === String(config.filterValue) + ); - const filtered = data.filter(row => row[fc] == fv); + const grouped = Object.entries( + groupBy(filtered, config.groupBy) + ); - const grouped = filtered.reduce((acc, row) => { - const key = row[gb]; - if (!acc[key]) acc[key] = []; - acc[key].push(row); - return acc; - }, {}); + const ops = { + sum: arr => sumBy(arr, r => parseFloat(r[config.aggregateColumn]) || 0), + avg: arr => meanBy(arr, r => parseFloat(r[config.aggregateColumn]) || 0), + count: arr => arr.length + }; - return Object.entries(grouped).map(([key, rows]) => { - let result; - if (op === 'count') { - result = rows.length; - } else { - const values = rows.map(r => parseFloat(r[ac]) || 0); - result = op === 'sum' - ? values.reduce((a, b) => a + b, 0) - : values.reduce((a, b) => a + b, 0) / values.length; - } - return { [gb]: key, result }; - }); + return grouped.map(([key, rows]) => ({ + [config.groupBy]: key, + result: ops[config.operation](rows) + })); } export default processCSV; \ No newline at end of file diff --git a/tests/6_csv_processor/outputs/google_gemini-2.5-pro TEMP_0.7.js b/tests/6_csv_processor/outputs/google_gemini-2.5-pro TEMP_0.7.js index c4ecd74..4aafa40 100644 --- a/tests/6_csv_processor/outputs/google_gemini-2.5-pro TEMP_0.7.js +++ b/tests/6_csv_processor/outputs/google_gemini-2.5-pro TEMP_0.7.js @@ -1,40 +1,42 @@ -const processCSV = async (csvString, { +const processCSV = async ( + csvString, { filterColumn, filterValue, groupBy, aggregateColumn, operation -}) => { - const { default: Papa } = await import('https://cdn.jsdelivr.net/npm/papaparse@5.4.1/+esm'); + } +) => { + const [Papa, { + default: _ + }] = await Promise.all([ + import('https://cdn.jsdelivr.net/npm/papaparse@5.4.1/papaparse.min.js'), + import('https://cdn.jsdelivr.net/npm/lodash-es@4.17.21/+esm'), + ]); - const aggregations = { - sum: g => g.s, - count: g => g.c, - avg: g => g.c ? g.s / g.c : 0, - }; + const { + data + } = Papa.parse(csvString, { + header: true, + dynamicTyping: true, + skipEmptyLines: true, + }); - const groupedData = Papa.parse(csvString, { - header: true, - skipEmptyLines: true, - dynamicTyping: true, - }).data - .filter(row => row[filterColumn] === filterValue) - .reduce((acc, row) => { - const key = row[groupBy]; - const val = row[aggregateColumn]; + const aggregators = { + sum: g => _.sumBy(g, aggregateColumn), + avg: g => _.meanBy(g, aggregateColumn), + count: g => g.length, + }; - acc[key] = acc[key] || { s: 0, c: 0 }; - if (typeof val === 'number' && !isNaN(val)) { - acc[key].s += val; - } - acc[key].c++; - - return acc; - }, {}); - - return Object.entries(groupedData).map(([key, group]) => ({ - [groupBy]: /^-?\d+(\.\d+)?$/.test(key) ? Number(key) : key, - [operation]: aggregations[operation](group), - })); + return _.chain(data) + .filter({ + [filterColumn]: filterValue + }) + .groupBy(groupBy) + .map((rows, key) => ({ + [groupBy]: Number.isNaN(+key) ? key : +key, + result: aggregators[operation](rows), + })) + .value(); }; export default processCSV; \ No newline at end of file diff --git a/tests/6_csv_processor/outputs/openai_gpt-5-codex.js b/tests/6_csv_processor/outputs/openai_gpt-5-codex.js index deeda75..640342d 100644 --- a/tests/6_csv_processor/outputs/openai_gpt-5-codex.js +++ b/tests/6_csv_processor/outputs/openai_gpt-5-codex.js @@ -1,20 +1,18 @@ let cache; -async function processCSV(csv,cfg){ - const {csvParse,rollups}=await (cache??=import('https://cdn.jsdelivr.net/npm/d3@7/+esm')); - const {filterColumn,filterValue,groupBy,aggregateColumn,operation}=cfg; - if(!['sum','avg','count'].includes(operation))throw new Error('Unsupported operation'); - if(!csv||!filterColumn||!groupBy)throw new Error('Missing essentials'); - if(operation!=='count'&&!aggregateColumn)throw new Error('Missing aggregateColumn'); - const rows=csvParse(csv).filter(r=>r[filterColumn]==filterValue); - if(!rows.length)return[]; - const fn=operation==='count'?v=>v.length:v=>{ - let s=0,n=0; - for(const row of v){ - const val=+row[aggregateColumn]; - if(!Number.isNaN(val)){s+=val;n++;} - } - return operation==='sum'?s:n?s/n:0; - }; - return rollups(rows,fn,r=>r[groupBy]).map(([k,v])=>({[groupBy]:k,[operation]:v})); -} +const load=()=>cache||(cache=Promise.all([ + import('https://cdn.jsdelivr.net/npm/papaparse@5.4.1/papaparse.min.mjs'), + import('https://cdn.jsdelivr.net/npm/d3-array@3/+esm') +])); +const processCSV=async(csv,cfg)=>{ + const[{default:Papa},{rollup}]=await load(); + const{filterColumn:f,filterValue:v,groupBy:g,aggregateColumn:a,operation:o}=cfg; + const rows=Papa.parse(csv,{header:1,dynamicTyping:1,skipEmptyLines:1}).data.filter(r=>r[f]===v); + if(!rows.length)return[]; + const map=rollup(rows,s=>{ + if(o==='count')return s.length; + const t=s.reduce((p,c)=>p+(Number(c[a])||0),0); + return o==='avg'?t/s.length:t; + },r=>r[g]); + return Array.from(map,([k,val])=>({[g]:k,result:val})); +}; export default processCSV; \ No newline at end of file diff --git a/tests/6_csv_processor/outputs/openrouter_polaris-alpha.js b/tests/6_csv_processor/outputs/openrouter_polaris-alpha.js index 547c963..3c193f4 100644 --- a/tests/6_csv_processor/outputs/openrouter_polaris-alpha.js +++ b/tests/6_csv_processor/outputs/openrouter_polaris-alpha.js @@ -1,30 +1,35 @@ -async function processCSV(csv, cfg) { - const {filterColumn,filterValue,groupBy,aggregateColumn,operation} = cfg - if(!csv||!filterColumn||!groupBy||!operation) throw new Error('Invalid configuration') - const [{parse},{default:lodash}] = await Promise.all([ - import('https://cdn.jsdelivr.net/npm/papaparse@5.4.1/+esm'), - import('https://cdn.jsdelivr.net/npm/lodash-es@4.17.21/+esm') - ]) - const {data,errors} = parse(csv,{header:true,skipEmptyLines:true,dynamicTyping:true}) - if(errors?.length) throw new Error('CSV parse error') - const rows = data.filter(r=>r[filterColumn]===filterValue) - if(!rows.length) return [] - const grouped = lodash.groupBy(rows,r=>r[groupBy]) +async function processCSV(csv, c) { + if (typeof csv !== 'string') throw new TypeError('csv must be string') + if (!c || typeof c !== 'object') throw new TypeError('config required') + let { filterColumn, filterValue, groupBy, aggregateColumn, operation } = c + if (!filterColumn || !groupBy || !operation) throw new Error('missing config') + if (!['sum', 'avg', 'count'].includes(operation)) throw new Error('bad op') + + const { parse } = await import('https://cdn.skypack.dev/papaparse@5.4.1') + const _ = (await import('https://cdn.skypack.dev/lodash-es@4.17.21')).default + + const { data, errors } = parse(csv, { header: true, dynamicTyping: true, skipEmptyLines: true }) + if (errors && errors.length) throw new Error('csv parse error') + + const rows = _.filter(data, r => r && r[filterColumn] === filterValue) + if (!rows.length) return [] + + const grouped = _.groupBy(rows, r => r[groupBy]) const out = [] - for(const k in grouped){ - const g = grouped[k] - let v - if(operation==='count') v = g.length - else{ - const nums = g.map(r=>Number(r[aggregateColumn])).filter(n=>Number.isFinite(n)) - if(!nums.length) { v = operation==='sum'?0:null } - else{ - const s = nums.reduce((a,b)=>a+b,0) - v = operation==='sum'?s:s/nums.length - } + + _.forOwn(grouped, (items, k) => { + let result + if (operation === 'count') { + result = items.length + } else { + const nums = _.map(items, i => Number(i[aggregateColumn])).filter(v => Number.isFinite(v)) + if (!nums.length) return + const sum = _.sum(nums) + result = operation === 'sum' ? sum : sum / nums.length } - out.push({[groupBy]:k,result:v}) - } + out.push({ [groupBy]: k, result }) + }) + return out } export default processCSV; \ No newline at end of file diff --git a/tests/7_scheduler/outputs/anthropic_claude-sonnet-4.5 TEMP_0.4.js b/tests/7_scheduler/outputs/anthropic_claude-sonnet-4.5 TEMP_0.4.js index e08274f..c6483bf 100644 --- a/tests/7_scheduler/outputs/anthropic_claude-sonnet-4.5 TEMP_0.4.js +++ b/tests/7_scheduler/outputs/anthropic_claude-sonnet-4.5 TEMP_0.4.js @@ -1,9 +1,9 @@ const findAvailableSlots = async (cal1, cal2, constraints) => { const { default: dayjs } = await import('https://cdn.jsdelivr.net/npm/dayjs@1.11.10/+esm'); const [{ default: utc }, { default: customParseFormat }, { default: isBetween }] = await Promise.all([ - import('https://cdn.jsdelivr.net/npm/dayjs@1.11.10/plugin/utc.js'), - import('https://cdn.jsdelivr.net/npm/dayjs@1.11.10/plugin/customParseFormat.js'), - import('https://cdn.jsdelivr.net/npm/dayjs@1.11.10/plugin/isBetween.js') + import('https://cdn.jsdelivr.net/npm/dayjs@1.11.10/plugin/utc.js/+esm'), + import('https://cdn.jsdelivr.net/npm/dayjs@1.11.10/plugin/customParseFormat.js/+esm'), + import('https://cdn.jsdelivr.net/npm/dayjs@1.11.10/plugin/isBetween.js/+esm') ]); dayjs.extend(utc); @@ -11,65 +11,59 @@ const findAvailableSlots = async (cal1, cal2, constraints) => { dayjs.extend(isBetween); const { durationMinutes, searchRange, workHours } = constraints; - const duration = durationMinutes; + const [whStart, whEnd] = [workHours.start.split(':'), workHours.end.split(':')]; - const mergedBusy = [...cal1, ...cal2] + const allBusy = [...cal1, ...cal2] .map(({ start, end }) => ({ start: dayjs(start), end: dayjs(end) })) - .sort((a, b) => a.start - b.start) - .reduce((acc, curr) => { - if (!acc.length) return [curr]; - const last = acc[acc.length - 1]; - if (curr.start <= last.end) { - last.end = dayjs.max(last.end, curr.end); - return acc; - } - return [...acc, curr]; - }, []); + .sort((a, b) => a.start - b.start); + + const merged = allBusy.reduce((acc, curr) => { + if (!acc.length || acc[acc.length - 1].end < curr.start) { + acc.push(curr); + } else { + acc[acc.length - 1].end = dayjs.max(acc[acc.length - 1].end, curr.end); + } + return acc; + }, []); - const searchStart = dayjs(searchRange.start); - const searchEnd = dayjs(searchRange.end); - const [workStart, workEnd] = [workHours.start, workHours.end]; - const slots = []; - let current = searchStart; + let current = dayjs(searchRange.start); + const searchEnd = dayjs(searchRange.end); while (current < searchEnd) { - const dayStart = dayjs(`${current.format('YYYY-MM-DD')}T${workStart}`); - const dayEnd = dayjs(`${current.format('YYYY-MM-DD')}T${workEnd}`); + const dayStart = current.hour(+whStart[0]).minute(+whStart[1]).second(0); + const dayEnd = current.hour(+whEnd[0]).minute(+whEnd[1]).second(0); - const workStart_ = dayjs.max(current, dayStart); - const workEnd_ = dayjs.min(searchEnd, dayEnd); - - if (workStart_ < workEnd_) { - const dayBusy = mergedBusy.filter(b => - b.start < workEnd_ && b.end > workStart_ - ); - - let pointer = workStart_; + let pointer = dayStart > current ? dayStart : current; + + for (const busy of merged) { + if (busy.start >= dayEnd) break; + if (busy.end <= pointer) continue; - for (const busy of dayBusy) { - const gapEnd = dayjs.min(busy.start, workEnd_); - - while (pointer.add(duration, 'minute') <= gapEnd) { + while (pointer.add(durationMinutes, 'minute') <= dayjs.min(busy.start, dayEnd)) { + const slotEnd = pointer.add(durationMinutes, 'minute'); + if (pointer >= dayStart && slotEnd <= dayEnd && pointer >= dayjs(searchRange.start)) { slots.push({ start: pointer.toISOString(), - end: pointer.add(duration, 'minute').toISOString() + end: slotEnd.toISOString() }); - pointer = pointer.add(duration, 'minute'); } - - pointer = dayjs.max(pointer, busy.end); + pointer = pointer.add(durationMinutes, 'minute'); } - - while (pointer.add(duration, 'minute') <= workEnd_) { + pointer = dayjs.max(pointer, busy.end); + } + + while (pointer.add(durationMinutes, 'minute') <= dayEnd) { + const slotEnd = pointer.add(durationMinutes, 'minute'); + if (pointer >= dayStart && slotEnd <= searchEnd) { slots.push({ start: pointer.toISOString(), - end: pointer.add(duration, 'minute').toISOString() + end: slotEnd.toISOString() }); - pointer = pointer.add(duration, 'minute'); } + pointer = pointer.add(durationMinutes, 'minute'); } - + current = current.add(1, 'day').startOf('day'); } diff --git a/tests/7_scheduler/outputs/anthropic_claude-sonnet-4.5 TEMP_0.7.js b/tests/7_scheduler/outputs/anthropic_claude-sonnet-4.5 TEMP_0.7.js index a1b8699..ea52831 100644 --- a/tests/7_scheduler/outputs/anthropic_claude-sonnet-4.5 TEMP_0.7.js +++ b/tests/7_scheduler/outputs/anthropic_claude-sonnet-4.5 TEMP_0.7.js @@ -1,93 +1,85 @@ const findAvailableSlots = async (cal1, cal2, constraints) => { - const { default: dayjs } = await import('https://cdn.skypack.dev/dayjs@1.11.10'); - const { default: utc } = await import('https://cdn.skypack.dev/dayjs@1.11.10/plugin/utc'); - const { default: customParseFormat } = await import('https://cdn.skypack.dev/dayjs@1.11.10/plugin/customParseFormat'); + const { DateTime, Interval } = await import('https://cdn.skypack.dev/luxon'); - dayjs.extend(utc); - dayjs.extend(customParseFormat); - - const { durationMinutes, searchRange, workHours } = constraints; - const duration = durationMinutes * 60000; + const { durationMinutes: dur, searchRange: range, workHours: wh } = constraints; + const [rangeStart, rangeEnd] = [DateTime.fromISO(range.start), DateTime.fromISO(range.end)]; + const [whStart, whEnd] = wh.start.split(':').map(Number); + const [whStartMin, whEndMin] = [whStart * 60 + (wh.start.split(':')[1] || 0), + whEnd.split(':').map(Number).reduce((h, m) => h * 60 + m)]; - const merged = [...cal1, ...cal2] - .map(({ start, end }) => ({ start: new Date(start).getTime(), end: new Date(end).getTime() })) - .sort((a, b) => a.start - b.start); - - const busy = merged.reduce((acc, slot) => { - if (!acc.length) return [slot]; - const last = acc[acc.length - 1]; - if (slot.start <= last.end) { - last.end = Math.max(last.end, slot.end); - return acc; + const mergeIntervals = (intervals) => { + if (!intervals.length) return []; + const sorted = intervals.sort((a, b) => a.start - b.start); + const merged = [sorted[0]]; + for (let i = 1; i < sorted.length; i++) { + const last = merged[merged.length - 1]; + if (sorted[i].start <= last.end) { + last.end = last.end > sorted[i].end ? last.end : sorted[i].end; + } else { + merged.push(sorted[i]); + } } - acc.push(slot); - return acc; - }, []); - - const rangeStart = new Date(searchRange.start).getTime(); - const rangeEnd = new Date(searchRange.end).getTime(); - const [whStart, whEnd] = [workHours.start, workHours.end]; - - const isWithinWorkHours = (ts) => { - const d = dayjs(ts); - const time = d.format('HH:mm'); - return time >= whStart && time <= whEnd; + return merged; }; - - const getWorkDayBounds = (ts) => { - const d = dayjs(ts); - const [h1, m1] = whStart.split(':').map(Number); - const [h2, m2] = whEnd.split(':').map(Number); - return { - start: d.hour(h1).minute(m1).second(0).millisecond(0).valueOf(), - end: d.hour(h2).minute(m2).second(0).millisecond(0).valueOf() - }; + + const toBusy = (cal) => cal.map(({ start, end }) => ({ + start: DateTime.fromISO(start), + end: DateTime.fromISO(end) + })); + + const allBusy = mergeIntervals([...toBusy(cal1), ...toBusy(cal2)]); + + const isWorkHour = (dt) => { + const min = dt.hour * 60 + dt.minute; + return min >= whStartMin && min < whEndMin; }; - + const slots = []; - let current = rangeStart; - - for (let ts = rangeStart; ts < rangeEnd; ts += 86400000) { - const { start: dayStart, end: dayEnd } = getWorkDayBounds(ts); - current = Math.max(current, dayStart); - - busy.forEach(({ start: bStart, end: bEnd }) => { - if (bStart > current && bStart <= dayEnd) { - let slotStart = current; - while (slotStart + duration <= Math.min(bStart, dayEnd)) { - const slotEnd = slotStart + duration; - if (isWithinWorkHours(slotStart) && isWithinWorkHours(slotEnd)) { - slots.push({ - start: new Date(slotStart).toISOString(), - end: new Date(slotEnd).toISOString() - }); - } - slotStart = slotEnd; - } - current = Math.max(current, bEnd); - } - if (bEnd > current && bEnd <= dayEnd) { - current = Math.max(current, bEnd); - } - }); - - if (current < dayEnd) { - let slotStart = current; - while (slotStart + duration <= dayEnd) { - const slotEnd = slotStart + duration; - if (isWithinWorkHours(slotStart) && isWithinWorkHours(slotEnd)) { - slots.push({ - start: new Date(slotStart).toISOString(), - end: new Date(slotEnd).toISOString() - }); - } - slotStart = slotEnd; - } + let cursor = rangeStart; + + while (cursor < rangeEnd) { + if (!isWorkHour(cursor)) { + cursor = cursor.plus({ minutes: 1 }); + continue; } - current = dayStart + 86400000; + const slotEnd = cursor.plus({ minutes: dur }); + + if (slotEnd > rangeEnd) break; + + let validSlot = true; + let tempCursor = cursor; + while (tempCursor < slotEnd) { + if (!isWorkHour(tempCursor)) { + validSlot = false; + break; + } + tempCursor = tempCursor.plus({ minutes: 1 }); + } + + if (!validSlot) { + cursor = cursor.plus({ minutes: 1 }); + continue; + } + + const overlaps = allBusy.some(busy => + (cursor >= busy.start && cursor < busy.end) || + (slotEnd > busy.start && slotEnd <= busy.end) || + (cursor <= busy.start && slotEnd >= busy.end) + ); + + if (!overlaps) { + slots.push({ + start: cursor.toISO(), + end: slotEnd.toISO() + }); + cursor = slotEnd; + } else { + const nextBusy = allBusy.find(b => b.end > cursor && b.start <= cursor); + cursor = nextBusy ? nextBusy.end : cursor.plus({ minutes: 1 }); + } } - + return slots; }; export default findAvailableSlots; \ No newline at end of file diff --git a/tests/7_scheduler/outputs/anthropic_claude-sonnet-4.5.js b/tests/7_scheduler/outputs/anthropic_claude-sonnet-4.5.js index 0ed9bab..6bcb028 100644 --- a/tests/7_scheduler/outputs/anthropic_claude-sonnet-4.5.js +++ b/tests/7_scheduler/outputs/anthropic_claude-sonnet-4.5.js @@ -1,74 +1,78 @@ -const findAvailableSlots = async (cal1, cal2, constraints) => { - const { DateTime, Interval } = await import('https://cdn.skypack.dev/luxon'); +async function findAvailableSlots(cal1, cal2, constraints) { + const { default: dayjs } = await import('https://cdn.jsdelivr.net/npm/dayjs@1.11.10/+esm'); + const [{ default: utc }, { default: isBetween }, { default: customParseFormat }] = await Promise.all([ + import('https://cdn.jsdelivr.net/npm/dayjs@1.11.10/esm/plugin/utc/+esm'), + import('https://cdn.jsdelivr.net/npm/dayjs@1.11.10/esm/plugin/isBetween/+esm'), + import('https://cdn.jsdelivr.net/npm/dayjs@1.11.10/esm/plugin/customParseFormat/+esm') + ]); - const { durationMinutes: dur, searchRange: sr, workHours: wh } = constraints; - const [srStart, srEnd] = [DateTime.fromISO(sr.start), DateTime.fromISO(sr.end)]; - const [whStart, whEnd] = wh.start.split(':').map(Number); - - const toInterval = ({ start, end }) => - Interval.fromDateTimes(DateTime.fromISO(start), DateTime.fromISO(end)); - - const busySlots = [...cal1, ...cal2] - .map(toInterval) - .sort((a, b) => a.start - b.start); - - const merged = busySlots.reduce((acc, curr) => { - if (!acc.length) return [curr]; - const last = acc[acc.length - 1]; - return last.overlaps(curr) || last.abutsStart(curr) - ? [...acc.slice(0, -1), last.union(curr)] - : [...acc, curr]; + dayjs.extend(utc); + dayjs.extend(isBetween); + dayjs.extend(customParseFormat); + + const { durationMinutes, searchRange, workHours } = constraints; + const allBusy = [...cal1, ...cal2] + .map(s => ({ start: dayjs(s.start), end: dayjs(s.end) })) + .sort((a, b) => a.start.valueOf() - b.start.valueOf()); + + const merged = allBusy.reduce((acc, curr) => { + if (!acc.length || acc[acc.length - 1].end.isBefore(curr.start)) { + acc.push(curr); + } else { + acc[acc.length - 1].end = dayjs.max(acc[acc.length - 1].end, curr.end); + } + return acc; }, []); - - const isWorkHours = dt => { - const h = dt.hour, m = dt.minute; - const mins = h * 60 + m; - const whStartMins = whStart[0] * 60 + whStart[1]; - const whEndMins = whEnd[0] * 60 + whEnd[1]; - return mins >= whStartMins && mins < whEndMins; - }; - + const slots = []; - let curr = srStart; - - while (curr < srEnd) { - const dayStart = curr.set({ hour: whStart[0], minute: whStart[1], second: 0 }); - const dayEnd = curr.set({ hour: whEnd[0], minute: whEnd[1], second: 0 }); - - if (dayStart >= srEnd) break; - - const effectiveStart = dayStart > srStart ? dayStart : srStart; - const effectiveEnd = dayEnd < srEnd ? dayEnd : srEnd; - - let pointer = effectiveStart; - - while (pointer.plus({ minutes: dur }) <= effectiveEnd) { - const slotEnd = pointer.plus({ minutes: dur }); - const slotInterval = Interval.fromDateTimes(pointer, slotEnd); + const rangeStart = dayjs(searchRange.start); + const rangeEnd = dayjs(searchRange.end); + const [workStart, workEnd] = [workHours.start, workHours.end]; + + const getWorkBounds = (date) => { + const [sh, sm] = workStart.split(':').map(Number); + const [eh, em] = workEnd.split(':').map(Number); + return { + start: date.hour(sh).minute(sm).second(0).millisecond(0), + end: date.hour(eh).minute(em).second(0).millisecond(0) + }; + }; + + let currentDay = rangeStart.startOf('day'); + while (currentDay.isBefore(rangeEnd) || currentDay.isSame(rangeEnd, 'day')) { + const { start: dayWorkStart, end: dayWorkEnd } = getWorkBounds(currentDay); + const dayStart = dayjs.max(dayWorkStart, rangeStart); + const dayEnd = dayjs.min(dayWorkEnd, rangeEnd); + + if (dayStart.isBefore(dayEnd)) { + let cursor = dayStart; - const isFree = !merged.some(busy => - busy.overlaps(slotInterval) || slotInterval.overlaps(busy) - ); - - if (isFree && isWorkHours(pointer) && isWorkHours(slotEnd.minus({ minutes: 1 }))) { - slots.push({ - start: pointer.toISO(), - end: slotEnd.toISO() - }); - pointer = slotEnd; - } else { - const nextBusy = merged.find(busy => busy.start > pointer); - if (nextBusy && nextBusy.start < effectiveEnd) { - pointer = nextBusy.end > pointer ? nextBusy.end : pointer.plus({ minutes: 1 }); - } else { - pointer = pointer.plus({ minutes: 1 }); + for (const busy of merged) { + if (busy.end.isBefore(dayStart) || busy.start.isAfter(dayEnd)) continue; + + const gapEnd = dayjs.min(busy.start, dayEnd); + while (cursor.add(durationMinutes, 'minute').isSameOrBefore(gapEnd)) { + slots.push({ + start: cursor.toISOString(), + end: cursor.add(durationMinutes, 'minute').toISOString() + }); + cursor = cursor.add(durationMinutes, 'minute'); } + cursor = dayjs.max(cursor, busy.end); + } + + while (cursor.add(durationMinutes, 'minute').isSameOrBefore(dayEnd)) { + slots.push({ + start: cursor.toISOString(), + end: cursor.add(durationMinutes, 'minute').toISOString() + }); + cursor = cursor.add(durationMinutes, 'minute'); } } - curr = curr.plus({ days: 1 }).startOf('day'); + currentDay = currentDay.add(1, 'day'); } - + return slots; -}; +} export default findAvailableSlots; \ No newline at end of file diff --git a/tests/7_scheduler/outputs/google_gemini-2.5-pro TEMP_0.7.js b/tests/7_scheduler/outputs/google_gemini-2.5-pro TEMP_0.7.js index 4cab5d6..835897a 100644 --- a/tests/7_scheduler/outputs/google_gemini-2.5-pro TEMP_0.7.js +++ b/tests/7_scheduler/outputs/google_gemini-2.5-pro TEMP_0.7.js @@ -1,56 +1,68 @@ -async function findAvailableSlots( - calendar1, - calendar2, - { durationMinutes: dur, searchRange: sr, workHours: wh } -) { - const dayjs = (await import('https://cdn.skypack.dev/dayjs')).default; - const utc = (await import('https://cdn.skypack.dev/dayjs/plugin/utc')).default; - dayjs.extend(utc); +async function findAvailableSlots(calendar1, calendar2, constraints) { + const [dayjsModule, durationModule] = await Promise.all([ + import('https://cdn.jsdelivr.net/npm/dayjs@1/dayjs.min.js'), + import('https://cdn.jsdelivr.net/npm/dayjs@1/plugin/duration.js') + ]); + const dayjs = dayjsModule.default; + dayjs.extend(durationModule.default); - const d = (s) => dayjs.utc(s); - const rangeStart = d(sr.start); - const rangeEnd = d(sr.end); - const [whsH, whsM] = wh.start.split(':'); - const [wheH, wheM] = wh.end.split(':'); + const { durationMinutes: duration, searchRange, workHours } = constraints; + const searchStart = dayjs(searchRange.start); + const searchEnd = dayjs(searchRange.end); + const [workStartH, workStartM] = workHours.start.split(':').map(Number); + const [workEndH, workEndM] = workHours.end.split(':').map(Number); - const busySlots = [...calendar1, ...calendar2].map(({ start, end }) => ({ - start: d(start), - end: d(end), - })); + const toDayjs = ({ start, end }) => ({ start: dayjs(start), end: dayjs(end) }); + const allBusy = [...calendar1, ...calendar2].map(toDayjs); - for (let day = rangeStart.clone().startOf('d'); day.isBefore(rangeEnd); day = day.add(1, 'd')) { - busySlots.push({ start: day.startOf('d'), end: day.hour(whsH).minute(whsM) }); - busySlots.push({ start: day.hour(wheH).minute(wheM), end: day.endOf('d') }); + for (let day = searchStart.clone().startOf('day'); day.isBefore(searchEnd); day = day.add(1, 'day')) { + allBusy.push({ + start: day, + end: day.hour(workStartH).minute(workStartM) + }); + allBusy.push({ + start: day.hour(workEndH).minute(workEndM), + end: day.endOf('day') + }); } - const merged = busySlots - .filter(({ start, end }) => start.isBefore(end)) + const mergedBusy = allBusy .sort((a, b) => a.start - b.start) - .reduce((acc, cur) => { + .reduce((acc, slot) => { const last = acc.at(-1); - if (!last || cur.start.isAfter(last.end)) { - acc.push(cur); - } else if (cur.end.isAfter(last.end)) { - last.end = cur.end; + if (last && slot.start <= last.end) { + if (slot.end > last.end) last.end = slot.end; + } else { + acc.push({ ...slot }); } return acc; }, []); - const available = []; - let cursor = rangeStart; + const availableSlots = []; + let nextFreeStart = searchStart; - [...merged, { start: rangeEnd, end: rangeEnd }].forEach((busy) => { - const gapEnd = busy.start; - for (let slotStart = cursor; !slotStart.add(dur, 'm').isAfter(gapEnd); slotStart = slotStart.add(dur, 'm')) { - const slotEnd = slotStart.add(dur, 'm'); - available.push({ - start: slotStart.toISOString(), - end: slotEnd.toISOString(), - }); + const findSlotsInGap = (start, end) => { + let slotStart = start; + while (slotStart.add(duration, 'minute') <= end) { + const slotEnd = slotStart.add(duration, 'minute'); + availableSlots.push({ start: slotStart.toISOString(), end: slotEnd.toISOString() }); + slotStart = slotEnd; + } + }; + + mergedBusy.forEach(busySlot => { + if (busySlot.start > nextFreeStart) { + findSlotsInGap(nextFreeStart, busySlot.start); + } + if (busySlot.end > nextFreeStart) { + nextFreeStart = busySlot.end; } - cursor = cursor.isAfter(busy.end) ? cursor : busy.end; }); - return available; + if (searchEnd > nextFreeStart) { + findSlotsInGap(nextFreeStart, searchEnd); + } + + return availableSlots; } export default findAvailableSlots; \ No newline at end of file diff --git a/tests/7_scheduler/outputs/openai_gpt-5-codex.js b/tests/7_scheduler/outputs/openai_gpt-5-codex.js index 7c8a3c6..2b91fda 100644 --- a/tests/7_scheduler/outputs/openai_gpt-5-codex.js +++ b/tests/7_scheduler/outputs/openai_gpt-5-codex.js @@ -1,55 +1,40 @@ -let df -async function findAvailableSlots(a,b,c){ - df??=await import('https://cdn.jsdelivr.net/npm/date-fns@3.6.0/+esm') - const {parseISO:pi,formatISO:fi,eachDayOfInterval:ed,set:st}=df - const sr=pi(c.searchRange.start),er=pi(c.searchRange.end),srT=+sr,erT=+er - const [hs,ms]=c.workHours.start.split(':').map(Number) - const [he,me]=c.workHours.end.split(':').map(Number) - const step=c.durationMinutes*6e4 - const norm=u=>{ - const arr=u.map(v=>({s:+pi(v.start),e:+pi(v.end)})).filter(v=>v.e>srT&&v.s({s:Math.max(v.s,srT),e:Math.min(v.e,erT)})).filter(v=>v.e>v.s).sort((x,y)=>x.s-y.s) - const out=[] - arr.forEach(v=>{ - const w=out[out.length-1] - if(!w||v.s>w.e)out.push({s:v.s,e:v.e}) - else w.e=Math.max(w.e,v.e) - }) - return out +let cache +const load=()=>cache||(cache=import('https://cdn.skypack.dev/date-fns@2.30.0?min')) +async function findAvailableSlots(calA,calB,rules){ + const {parseISO:iso,addMinutes:plus,differenceInMinutes:gap,eachDayOfInterval:days,set:setTime,max:maxDate,min:minDate}=await load() + const parseCal=c=>c.map(({start,end})=>({start:iso(start),end:iso(end)})) + const [sh,sm]=rules.workHours.start.split(':').map(Number) + const [eh,em]=rules.workHours.end.split(':').map(Number) + const rangeStart=iso(rules.searchRange.start),rangeEnd=iso(rules.searchRange.end) + const entries=[...parseCal(calA),...parseCal(calB)].filter(b=>b.end>rangeStart&&b.starta.start-b.start) + const slots=[] + const addFree=(s,e)=>{ + let cursor=s + while(gap(e,cursor)>=rules.durationMinutes){ + const stop=plus(cursor,rules.durationMinutes) + slots.push({start:cursor.toISOString(),end:stop.toISOString()}) + cursor=stop } - const free=u=>{ - const busy=norm(u),days=ed({start:sr,end:er}),out=[] - let i=0 - for(const day of days){ - const d0=Math.max(+st(day,{hours:hs,minutes:ms,seconds:0,milliseconds:0}),srT) - const d1=Math.min(+st(day,{hours:he,minutes:me,seconds:0,milliseconds:0}),erT) - if(d0>=d1)continue - while(icur)out.push({s:cur,e:Math.min(busy[j].s,d1)}) - cur=Math.max(cur,busy[j].e) - if(cur>=d1)break - j++ - } - if(cur=spanEnd)continue + const busy=entries.filter(b=>b.end>spanStart&&b.start({start:maxDate([b.start,spanStart]),end:minDate([b.end,spanEnd])})).sort((a,b)=>a.start-b.start) + const merged=[] + for(const block of busy){ + const last=merged[merged.length-1] + if(!last||block.start>last.end)merged.push({start:block.start,end:block.end}) + else if(block.end>last.end)last.end=block.end } - const x=free(a),y=free(b),res=[] - let i=0,j=0 - while(i=step){ - const k=Math.floor((e-s)/step) - for(let n=0;ny[j].e?j++:(i++,j++) + let cursor=spanStart + for(const block of merged){ + if(block.start>cursor)addFree(cursor,block.start) + if(block.end>cursor)cursor=block.end } - return res + if(cursor m); - const d = c.durationMinutes; - const z = DateTime.utc().zoneName; - const parseIso = s => DateTime.fromISO(s, { zone: 'utc' }); - const parseHm = (hm, base) => { - const [H, M] = hm.split(':').map(Number); - return base.set({ hour: H, minute: M, second: 0, millisecond: 0 }); - }; - const toIso = dt => dt.toUTC().toISO(); +async function findAvailableSlots(cal1, cal2, c) { + const { DateTime, Interval } = await import('https://cdn.skypack.dev/luxon') + const d = c.durationMinutes + const sR = c.searchRange + const wH = c.workHours + const z = 'UTC' + const p = (x, y) => DateTime.fromISO(x, { zone: y }) + const b = c => c.map(v => Interval.fromDateTimes(p(v.start, z), p(v.end, z))) + const m = (a, b) => [...a, ...b].sort((x, y) => x.start - y.start) + const n = i => { + const r = [] + let c = i[0] + for (let k = 1; k < i.length; k++) { + const v = i[k] + if (c.overlaps(v) || c.abutsStart(v)) c = Interval.fromDateTimes(c.start, c.end > v.end ? c.end : v.end) + else r.push(c), (c = v) + } + r.push(c) + return r + } + const iA = b(cal1) + const iB = b(cal2) + const all = m(iA, iB) + const busy = all.length ? n(all) : [] + const srI = Interval.fromDateTimes(p(sR.start, z), p(sR.end, z)) + const whS = wH.start.split(':').map(Number) + const whE = wH.end.split(':').map(Number) - const rStart = parseIso(c.searchRange.start); - const rEnd = parseIso(c.searchRange.end); - - const dayRange = []; - for (let d0 = rStart.startOf('day'); d0 < rEnd; d0 = d0.plus({ days: 1 })) { - const ws = parseHm(c.workHours.start, d0); - const we = parseHm(c.workHours.end, d0); - const s = ws < rStart ? rStart : ws; - const e = we > rEnd ? rEnd : we; - if (e > s) dayRange.push(Interval.fromDateTimes(s, e)); + const dayI = [] + let cur = srI.start.startOf('day') + const endDay = srI.end.startOf('day') + while (cur <= endDay) { + const ws = cur.set({ hour: whS[0], minute: whS[1] }) + const we = cur.set({ hour: whE[0], minute: whE[1] }) + const w = Interval.fromDateTimes(ws, we) + const clipped = srI.intersection(w) + if (clipped && clipped.isValid && clipped.length('minutes') >= d) dayI.push(clipped) + cur = cur.plus({ days: 1 }) } - const normalizeBusy = cal => - cal - .map(({ start, end }) => { - const s = parseIso(start), e = parseIso(end); - return e > s ? Interval.fromDateTimes(s, e) : null; - }) - .filter(Boolean) - .sort((a, b) => a.start - b.start); - - const mergeBusy = busy => { - const m = []; - for (const i of busy) { - const last = m[m.length - 1]; - if (!last || i.start > last.end) m.push(i); - else if (i.end > last.end) last.end = i.end; + const inv = [] + let pS = null + for (const x of busy) { + const xs = x.start < srI.start ? srI.start : x.start + const xe = x.end > srI.end ? srI.end : x.end + if (!pS) { + if (xs > srI.start) inv.push(Interval.fromDateTimes(srI.start, xs)) + pS = xe + } else { + if (xs > pS) inv.push(Interval.fromDateTimes(pS, xs)) + if (xe > pS) pS = xe } - return m; - }; + } + if (!busy.length) inv.push(srI) + else if (pS < srI.end) inv.push(Interval.fromDateTimes(pS, srI.end)) - const intersectWithRange = (busy, ranges) => { - const res = []; - let j = 0; - for (const r of ranges) { - while (j < busy.length && busy[j].end <= r.start) j++; - let k = j; - while (k < busy.length && busy[k].start < r.end) { - const s = busy[k].start < r.start ? r.start : busy[k].start; - const e = busy[k].end > r.end ? r.end : busy[k].end; - if (e > s) res.push(Interval.fromDateTimes(s, e)); - k++; - } + const freeWithinRange = inv + .map(v => dayI.map(dv => dv.intersection(v)).filter(x => x && x.isValid)) + .flat() + .filter(x => x.length('minutes') >= d) + + const res = [] + for (const f of freeWithinRange) { + let st = f.start + const mins = f.length('minutes') + const steps = Math.floor(mins / d) + for (let i = 0; i < steps; i++) { + const en = st.plus({ minutes: d }) + res.push({ start: st.toISO(), end: en.toISO() }) + st = en } - return mergeBusy(res); - }; - - const invertBusy = (busy, ranges) => { - const free = []; - for (const r of ranges) { - let cur = r.start; - for (const b of busy) { - if (b.end <= r.start || b.start >= r.end) continue; - if (b.start > cur) free.push(Interval.fromDateTimes(cur, b.start)); - if (b.end > cur) cur = b.end; - if (cur >= r.end) break; - } - if (cur < r.end) free.push(Interval.fromDateTimes(cur, r.end)); - } - return free; - }; - - const intersectFree = (fa, fb) => { - const res = []; - let i = 0, j = 0; - while (i < fa.length && j < fb.length) { - const a = fa[i], b = fb[j]; - const s = a.start > b.start ? a.start : b.start; - const e = a.end < b.end ? a.end : b.end; - if (e > s) res.push(Interval.fromDateTimes(s, e)); - if (a.end < b.end) i++; - else j++; - } - return res; - }; - - const filterByDuration = (slots, minutes) => { - const out = []; - const dur = { minutes }; - for (const s of slots) { - let cur = s.start; - while (cur.plus(dur) <= s.end) { - const end = cur.plus(dur); - out.push({ start: toIso(cur), end: toIso(end) }); - cur = end; - } - } - return out; - }; - - const busyA = mergeBusy(normalizeBusy(calA)); - const busyB = mergeBusy(normalizeBusy(calB)); - - const busyAIn = intersectWithRange(busyA, dayRange); - const busyBIn = intersectWithRange(busyB, dayRange); - - const freeA = invertBusy(busyAIn, dayRange); - const freeB = invertBusy(busyBIn, dayRange); - - const mutualFree = intersectFree(freeA, freeB); - - return filterByDuration(mutualFree, d); + } + return res } export default findAvailableSlots; \ No newline at end of file diff --git a/tests/8_json_validator/outputs/anthropic_claude-sonnet-4.5 TEMP_0.4.js b/tests/8_json_validator/outputs/anthropic_claude-sonnet-4.5 TEMP_0.4.js index f1866da..5fbf094 100644 --- a/tests/8_json_validator/outputs/anthropic_claude-sonnet-4.5 TEMP_0.4.js +++ b/tests/8_json_validator/outputs/anthropic_claude-sonnet-4.5 TEMP_0.4.js @@ -1,18 +1,14 @@ const validateJSON = async (data, schema) => { - const { default: Ajv } = await import('https://cdn.jsdelivr.net/npm/ajv@8.12.0/dist/2020.min.js'); - - const ajv = new Ajv({ allErrors: true, strict: false }); + const { default: Ajv } = await import('https://esm.sh/ajv@8.12.0'); + const ajv = new Ajv({ allErrors: true }); const validate = ajv.compile(schema); const valid = validate(data); return { valid, - errors: valid ? [] : validate.errors.map(e => ({ - path: e.instancePath || '/', - message: e.message, - keyword: e.keyword, - params: e.params - })) + errors: valid ? [] : validate.errors.map(e => + `${e.instancePath || '/'} ${e.message}`.trim() + ) }; }; export default validateJSON; \ No newline at end of file diff --git a/tests/8_json_validator/outputs/anthropic_claude-sonnet-4.5 TEMP_0.7.js b/tests/8_json_validator/outputs/anthropic_claude-sonnet-4.5 TEMP_0.7.js index bc8bb7e..5fbf094 100644 --- a/tests/8_json_validator/outputs/anthropic_claude-sonnet-4.5 TEMP_0.7.js +++ b/tests/8_json_validator/outputs/anthropic_claude-sonnet-4.5 TEMP_0.7.js @@ -1,16 +1,14 @@ const validateJSON = async (data, schema) => { - const { default: Ajv } = await import('https://cdn.jsdelivr.net/npm/ajv@8/dist/2020.min.js'); - const ajv = new Ajv({ allErrors: true, verbose: true }); + const { default: Ajv } = await import('https://esm.sh/ajv@8.12.0'); + const ajv = new Ajv({ allErrors: true }); const validate = ajv.compile(schema); const valid = validate(data); + return { valid, - errors: valid ? [] : validate.errors.map(e => ({ - path: e.instancePath || '/', - message: e.message, - keyword: e.keyword, - params: e.params - })) + errors: valid ? [] : validate.errors.map(e => + `${e.instancePath || '/'} ${e.message}`.trim() + ) }; }; export default validateJSON; \ No newline at end of file diff --git a/tests/8_json_validator/outputs/anthropic_claude-sonnet-4.5.js b/tests/8_json_validator/outputs/anthropic_claude-sonnet-4.5.js index 4c929d0..e32b9f1 100644 --- a/tests/8_json_validator/outputs/anthropic_claude-sonnet-4.5.js +++ b/tests/8_json_validator/outputs/anthropic_claude-sonnet-4.5.js @@ -1,14 +1,13 @@ const validateJSON = async (data, schema) => { - const { default: Ajv } = await import('https://cdn.jsdelivr.net/npm/ajv@8/dist/ajv.bundle.js'); - + const { default: Ajv } = await import('https://esm.sh/ajv@8.12.0'); const ajv = new Ajv({ allErrors: true }); const validate = ajv.compile(schema); const valid = validate(data); return { valid, - errors: valid ? [] : validate.errors.map(e => - `${e.instancePath || 'root'} ${e.message}` + errors: valid ? [] : validate.errors.map(err => + `${err.instancePath || '/'} ${err.message}`.trim() ) }; }; diff --git a/tests/8_json_validator/outputs/google_gemini-2.5-pro TEMP_0.7.js b/tests/8_json_validator/outputs/google_gemini-2.5-pro TEMP_0.7.js index 5aa6d27..e6a31d6 100644 --- a/tests/8_json_validator/outputs/google_gemini-2.5-pro TEMP_0.7.js +++ b/tests/8_json_validator/outputs/google_gemini-2.5-pro TEMP_0.7.js @@ -1,32 +1,25 @@ -let ajvPromise; -const compiledSchemas = new WeakMap(); +const validateJSON = (() => { + let ajvPromise; + const validatorCache = new WeakMap(); + + return async (json, schema) => { + ajvPromise ||= import('https://cdn.jsdelivr.net/npm/ajv@8/dist/ajv2020.min.js') + .then(({ default: Ajv }) => new Ajv({ allErrors: true })); -const validateJSON = async (json, schema) => { - try { - ajvPromise ||= import('https://esm.sh/ajv@8').then( - ({ default: Ajv }) => new Ajv({ allErrors: true }) - ); const ajv = await ajvPromise; - let validate = compiledSchemas.get(schema); + let validate = validatorCache.get(schema); if (!validate) { validate = ajv.compile(schema); - compiledSchemas.set(schema, validate); + validatorCache.set(schema, validate); } const valid = validate(json); - const errors = valid - ? [] - : (validate.errors ?? []).map(({ instancePath, message }) => - `${instancePath.substring(1) || 'root'}: ${message}` - ); + const errors = valid ? [] : validate.errors.map( + ({ instancePath, message }) => `${instancePath || 'object'} ${message}` + ); return { valid, errors }; - } catch (error) { - return { - valid: false, - errors: [error.message || 'An unknown validation error occurred.'], - }; - } -}; + }; +})(); export default validateJSON; \ No newline at end of file diff --git a/tests/8_json_validator/outputs/openai_gpt-5-codex.js b/tests/8_json_validator/outputs/openai_gpt-5-codex.js index 2bf20b0..96979ba 100644 --- a/tests/8_json_validator/outputs/openai_gpt-5-codex.js +++ b/tests/8_json_validator/outputs/openai_gpt-5-codex.js @@ -1,17 +1,25 @@ -let ajvReady -const loadAjv=()=>ajvReady??=(async()=>{ - const {default:Ajv}=await import('https://cdn.jsdelivr.net/npm/ajv@8/dist/ajv2020.mjs') - return new Ajv({allErrors:true,strict:false}) -})() +let ajv +const cache=new WeakMap() +const ensureAjv=async()=>ajv??=new (await import('https://cdn.jsdelivr.net/npm/ajv@8.12.0/+esm')).default({allErrors:true,strict:false}) +const getValidator=async schema=>{ + if(cache.has(schema))return cache.get(schema) + const v=(await ensureAjv()).compile(schema) + cache.set(schema,v) + return v +} async function validateJSON(data,schema){ - const ajv=await loadAjv() - const validate=ajv.compile(schema) - const valid=validate(data) - const errors=valid?[]:validate.errors?.map(({instancePath,message,params})=>{ - const here=instancePath||'/' - const extra=params&&Object.keys(params).length?JSON.stringify(params):'' - return [here,message,extra].filter(Boolean).join(' ') - })||[] - return {valid,errors} + try{ + const v=await getValidator(schema) + const valid=v(data) + const errors=valid?[]:(v.errors||[]).map(e=>{ + const path=e.instancePath||'/' + const msg=e.message||'Invalid value' + const meta=e.params&&Object.keys(e.params).length?` ${JSON.stringify(e.params)}`:'' + return`${path} ${msg}${meta}`.trim() + }) + return{valid,errors} + }catch(err){ + return{valid:false,errors:[err?.message||String(err)]} + } } export default validateJSON; \ No newline at end of file diff --git a/tests/8_json_validator/outputs/openrouter_polaris-alpha.js b/tests/8_json_validator/outputs/openrouter_polaris-alpha.js index 7e0f540..6018eed 100644 --- a/tests/8_json_validator/outputs/openrouter_polaris-alpha.js +++ b/tests/8_json_validator/outputs/openrouter_polaris-alpha.js @@ -1,15 +1,21 @@ async function validateJSON(data, schema) { - const {default: Ajv} = await import('https://cdn.jsdelivr.net/npm/ajv@8/dist/ajv.min.js') - const ajv = new Ajv({allErrors:true, strict:false}) - const validate = ajv.compile(schema) - const valid = validate(data) - if (valid) return {valid:true, errors:[]} - const errors = (validate.errors || []).map(e => { - const path = (e.instancePath || e.dataPath || '') || (e.schemaPath || '') - const msg = e.message || 'Invalid value' - const params = e.params ? JSON.stringify(e.params) : '' - return [path, msg, params].filter(Boolean).join(' - ') - }) - return {valid:false, errors} + const { default: Ajv } = await import('https://cdn.skypack.dev/ajv@8?min'); + const { default: addFormats } = await import('https://cdn.skypack.dev/ajv-formats@2?min'); + const ajv = new Ajv({ allErrors: true, strict: false }); + addFormats(ajv); + const compile = s => { + const c = ajv.compile(s); + return d => ({ ok: c(d), errs: c.errors || [] }); + }; + const run = compile(schema); + const r = run(data); + if (r.ok) return { valid: true, errors: [] }; + const errors = r.errs.map(e => { + const p = e.instancePath || e.dataPath || ''; + const loc = p || e.schemaPath || ''; + const msg = e.message || 'Invalid value'; + return loc ? loc + ' ' + msg : msg; + }); + return { valid: false, errors }; } export default validateJSON; \ No newline at end of file