DeepSeek-r1和O1、O3mini谁更强?
题目:编写一个 js 程序,显示一个球在旋转的六边形内弹跳。球应该受到重力和摩擦力的影响,并且必须逼真地从旋转的墙壁上弹起
DeepSeek-r1
<!DOCTYPE html>
<html>
<body>
<canvas id="canvas" width="600" height="400"></canvas>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const center = { x: canvas.width/2, y: canvas.height/2 };// 六边形参数
const hexRadius = 150;
let hexRotation = 0;
const hexRotationSpeed = 0.02;// 球参数
const ball = {x: center.x,y: center.y,radius: 10,vx: 2,vy: 0
};// 物理参数
const gravity = 0.5;
const restitution = 0.8; // 弹性系数
const friction = 0.7; // 摩擦力系数function getHexagonPoints(cx, cy, radius, rotation) {const points = [];for (let i = 0; i < 6; i++) {const angle = rotation + (i * Math.PI/3);points.push({x: cx + radius * Math.cos(angle),y: cy + radius * Math.sin(angle)});}return points;
}function distanceToSegment(p, a, b) {const ab = { x: b.x - a.x, y: b.y - a.y };const ap = { x: p.x - a.x, y: p.y - a.y };const dot = ap.x * ab.x + ap.y * ab.y;if (dot <= 0) return Math.hypot(ap.x, ap.y);if (dot >= ab.x**2 + ab.y**2) return Math.hypot(p.x - b.x, p.y - b.y);const t = dot / (ab.x**2 + ab.y**2);const proj = { x: a.x + t*ab.x, y: a.y + t*ab.y };return Math.hypot(p.x - proj.x, p.y - proj.y);
}function update() {// 应用物理ball.vy += gravity;ball.x += ball.vx;ball.y += ball.vy;// 碰撞检测const points = getHexagonPoints(center.x, center.y, hexRadius, hexRotation);for (let i = 0; i < 6; i++) {const a = points[i];const b = points[(i+1)%6];const distance = distanceToSegment(ball, a, b);if (distance < ball.radius) {// 计算碰撞法线const mid = { x: (a.x + b.x)/2, y: (a.y + b.y)/2 };const normal = { x: (center.x - mid.x)/hexRadius,y: (center.y - mid.y)/hexRadius };// 校正位置const overlap = ball.radius - distance;ball.x += normal.x * overlap;ball.y += normal.y * overlap;// 计算速度变化const velocityDot = ball.vx * normal.x + ball.vy * normal.y;if (velocityDot < 0) {// 法向反弹const bounce = -velocityDot * restitution;// 切向摩擦const tangentVx = ball.vx - velocityDot * normal.x;const tangentVy = ball.vy - velocityDot * normal.y;ball.vx = tangentVx * friction + bounce * normal.x;ball.vy = tangentVy * friction + bounce * normal.y;}}}// 更新旋转hexRotation += hexRotationSpeed;// 绘制ctx.clearRect(0, 0, canvas.width, canvas.height);// 绘制六边形ctx.beginPath();ctx.moveTo(points[0].x, points[0].y);points.slice(1).forEach(p => ctx.lineTo(p.x, p.y));ctx.closePath();ctx.strokeStyle = '#000';ctx.stroke();// 绘制球ctx.beginPath();ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI*2);ctx.fillStyle = 'red';ctx.fill();requestAnimationFrame(update);
}update();
</script>
</body>
</html>
O1
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>旋转六边形内弹跳的球</title><style>body { margin: 0; overflow: hidden; background: #222; }canvas { display: block; }</style>
</head>
<body><canvas id="canvas"></canvas><script>// 获取 canvas 并设置全屏const canvas = document.getElementById('canvas');const ctx = canvas.getContext('2d');canvas.width = window.innerWidth;canvas.height = window.innerHeight;// 六边形的参数const center = { x: canvas.width / 2, y: canvas.height / 2 }; // 六边形中心const hexRadius = 200; // 六边形半径(顶点到中心的距离)let hexRotation = 0; // 当前旋转角度const hexRotationSpeed = 0.01; // 每帧旋转的弧度// 小球的参数const ballRadius = 10;let ball = {// 初始位置设在中心附近,可自行调整x: center.x,y: center.y,// 初始速度(可调整以获得不同运动效果)vx: 5,vy: -2};// 物理参数const gravity = 0.3; // 重力加速度(单位:像素/帧²)const airFriction = 0.999; // 空气阻力,每帧对速度轻微衰减const restitution = 0.9; // 碰撞时法向速度的反弹系数(0~1之间)const wallFriction = 0.98; // 墙面摩擦,降低切向分量// 动画主循环function animate() {update();draw();requestAnimationFrame(animate);}// 更新物理状态function update() {// 更新六边形旋转角度hexRotation += hexRotationSpeed;// 对小球施加重力ball.vy += gravity;// 应用空气阻力ball.vx *= airFriction;ball.vy *= airFriction;// 更新小球的位置ball.x += ball.vx;ball.y += ball.vy;// 计算当前旋转后的六边形各顶点const vertices = [];for (let i = 0; i < 6; i++) {const angle = hexRotation + i * Math.PI / 3; // 360°/6 = 60° = π/3vertices.push({x: center.x + hexRadius * Math.cos(angle),y: center.y + hexRadius * Math.sin(angle)});}// 对六边形每条边检测碰撞for (let i = 0; i < 6; i++) {const p1 = vertices[i];const p2 = vertices[(i + 1) % 6];// 计算边向量const edge = { x: p2.x - p1.x, y: p2.y - p1.y };const edgeLenSq = edge.x * edge.x + edge.y * edge.y;// 将小球中心投影到边所在直线上,求最接近边的点let t = ((ball.x - p1.x) * edge.x + (ball.y - p1.y) * edge.y) / edgeLenSq;t = Math.max(0, Math.min(1, t)); // 限定在 [0, 1] 内,保证点在边上const closest = { x: p1.x + t * edge.x, y: p1.y + t * edge.y };// 计算小球中心到最近点的距离const dx = ball.x - closest.x;const dy = ball.y - closest.y;const dist = Math.sqrt(dx * dx + dy * dy);// 若距离小于小球半径,则发生碰撞if (dist < ballRadius) {// 计算碰撞点处墙壁的速度// 对于以 center 为旋转中心、角速度 ω 的旋转体,// 任一点 r 相对于 center 的瞬时速度 v = ω × r,// 对于二维而言 v = ω * (-r.y, r.x)const rx = closest.x - center.x;const ry = closest.y - center.y;const wallV = {x: -hexRotationSpeed * ry,y: hexRotationSpeed * rx};// 计算小球相对于墙壁的速度(相对速度)const relV = {x: ball.vx - wallV.x,y: ball.vy - wallV.y};// 碰撞法线:从最近点指向小球中心let n = { x: dx, y: dy };const nMag = Math.sqrt(n.x * n.x + n.y * n.y) || 1;n.x /= nMag;n.y /= nMag;// 检查相对速度在法线方向上的分量(若小于 0,则表示正向墙壁运动)const relDotN = relV.x * n.x + relV.y * n.y;if (relDotN < 0) {// 将相对速度分解为法向分量和切向分量const vN = { x: n.x * relDotN, y: n.y * relDotN };const vT = { x: relV.x - vN.x, y: relV.y - vN.y };// 反弹:法向分量取反并乘以反弹系数,同时对切向分量施加摩擦衰减const newRelV = {x: -restitution * vN.x + wallFriction * vT.x,y: -restitution * vN.y + wallFriction * vT.y};// 小球碰撞后的速度 = 墙壁速度 + 更新后的相对速度ball.vx = newRelV.x + wallV.x;ball.vy = newRelV.y + wallV.y;// 将小球稍微移出碰撞状态,防止卡住const penetration = ballRadius - dist;ball.x += n.x * penetration;ball.y += n.y * penetration;}}}}// 绘制六边形和小球function draw() {// 清空画布ctx.clearRect(0, 0, canvas.width, canvas.height);// 绘制旋转六边形ctx.strokeStyle = "#fff";ctx.lineWidth = 3;ctx.beginPath();for (let i = 0; i < 6; i++) {const angle = hexRotation + i * Math.PI / 3;const x = center.x + hexRadius * Math.cos(angle);const y = center.y + hexRadius * Math.sin(angle);if (i === 0) {ctx.moveTo(x, y);} else {ctx.lineTo(x, y);}}ctx.closePath();ctx.stroke();// 绘制小球ctx.fillStyle = "#f00";ctx.beginPath();ctx.arc(ball.x, ball.y, ballRadius, 0, Math.PI * 2);ctx.fill();}// 开始动画animate();// 窗口尺寸变化时,重新设置 canvas 尺寸和中心点window.addEventListener('resize', function() {canvas.width = window.innerWidth;canvas.height = window.innerHeight;center.x = canvas.width / 2;center.y = canvas.height / 2;});</script>
</body>
</html>
O3-mini
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><title>旋转六边形内弹跳的球</title><style>body { margin: 0; background: #f0f0f0; }canvas { display: block; margin: 0 auto; background: #fff; }</style>
</head>
<body><canvas id="canvas" width="800" height="600"></canvas><script>// 获取 Canvas 及上下文const canvas = document.getElementById('canvas');const ctx = canvas.getContext('2d');// 全局参数const centerX = canvas.width / 2;const centerY = canvas.height / 2;const hexRadius = 250; // 六边形的“外接圆”半径let hexRotation = 0; // 六边形当前旋转角度(弧度)const omega = 0.01; // 六边形旋转角速度(每帧增加的弧度)const gravity = 0.5; // 重力加速度(像素/帧²)const airFriction = 0.999; // 空气摩擦,每帧稍微衰减球的速度const restitution = 0.9; // 反弹系数(碰撞时法向速度反向并缩小)const wallFriction = 0.98; // 碰撞时切向速度摩擦(模拟与墙面接触时的摩擦损耗)// 球的属性const ball = {x: centerX,y: centerY - 100,radius: 15,vx: 3,vy: 0,};// --- 辅助函数 ---// 计算两个向量的点积function dot(ax, ay, bx, by) {return ax * bx + ay * by;}// 归一化向量 (x, y)function normalize(x, y) {const mag = Math.hypot(x, y);if (mag === 0) return { x: 0, y: 0 };return { x: x / mag, y: y / mag };}// 根据当前旋转角计算六边形的 6 个顶点(数组中的每个元素都是 {x, y} 对象)function getHexagonVertices() {const vertices = [];for (let i = 0; i < 6; i++) {// 每个顶点的角度:初始角加上 i * 60°const angle = hexRotation + i * Math.PI / 3;const x = centerX + hexRadius * Math.cos(angle);const y = centerY + hexRadius * Math.sin(angle);vertices.push({ x, y });}return vertices;}// 绘制六边形function drawHexagon(vertices) {ctx.beginPath();ctx.moveTo(vertices[0].x, vertices[0].y);for (let i = 1; i < vertices.length; i++) {ctx.lineTo(vertices[i].x, vertices[i].y);}ctx.closePath();ctx.lineWidth = 3;ctx.strokeStyle = '#333';ctx.stroke();}// 绘制球function drawBall() {ctx.beginPath();ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);ctx.fillStyle = 'red';ctx.fill();ctx.lineWidth = 1;ctx.strokeStyle = '#000';ctx.stroke();}// 检测并处理球与一条边(p1 到 p2)的碰撞function resolveCollisionWithEdge(p1, p2) {// 求球心到边的最近点(将 p1p2 作为线段处理)const dx = p2.x - p1.x;const dy = p2.y - p1.y;const lengthSq = dx * dx + dy * dy;let t = ((ball.x - p1.x) * dx + (ball.y - p1.y) * dy) / lengthSq;t = Math.max(0, Math.min(1, t)); // 限制 t 在 [0, 1] 内const closestX = p1.x + t * dx;const closestY = p1.y + t * dy;// 计算球心与最近点的向量及距离const diffX = ball.x - closestX;const diffY = ball.y - closestY;const distance = Math.hypot(diffX, diffY);// 如果距离小于球半径,说明发生了碰撞if (distance < ball.radius) {const penetration = ball.radius - distance; // 穿透深度// 计算碰撞法线:初步取从最近点指向球心的方向let normal = normalize(diffX, diffY);// 如果球心恰好与边重合(distance == 0),则使用边的法线if (distance === 0) {normal = normalize(dy, -dx);}// 也可以根据边向量计算两个垂直方向,并选择指向六边形内部的那个const edgeNormalCandidate = normalize(dy, -dx);const midX = (p1.x + p2.x) / 2;const midY = (p1.y + p2.y) / 2;const toCenter = { x: centerX - midX, y: centerY - midY };if (dot(edgeNormalCandidate.x, edgeNormalCandidate.y, toCenter.x, toCenter.y) > 0) {normal = edgeNormalCandidate;} else {normal = { x: -edgeNormalCandidate.x, y: -edgeNormalCandidate.y };}// 计算碰撞点处边的运动速度(因为六边形在旋转,边上的点有切向速度)// 对于一个位于 P 点(最近点)的位置,其速度 v_wall = ω × (P - center)// 在 2D 中:v_wall = (-ω*(P.y-centerY), ω*(P.x-centerX))const vWall = {x: -omega * (closestY - centerY),y: omega * (closestX - centerX)};// 计算球相对于“运动边”的相对速度const relV = {x: ball.vx - vWall.x,y: ball.vy - vWall.y};// 计算相对速度在法线方向上的分量const relVNormal = dot(relV.x, relV.y, normal.x, normal.y);// 如果球正向墙面运动(相对速度法向分量为负),才处理碰撞if (relVNormal < 0) {// 反转法向分量,并按反弹系数缩放const newRelVNormal = -restitution * relVNormal;// 分离出切向分量,并加入碰撞摩擦(减少切向分量能量)const relVTangent = {x: (relV.x - relVNormal * normal.x) * wallFriction,y: (relV.y - relVNormal * normal.y) * wallFriction};// 碰撞后的相对速度const newRelV = {x: newRelVNormal * normal.x + relVTangent.x,y: newRelVNormal * normal.y + relVTangent.y};// 转换回绝对速度(加上边的运动速度)ball.vx = newRelV.x + vWall.x;ball.vy = newRelV.y + vWall.y;// 将球推出边界,防止“卡在墙内”ball.x += normal.x * penetration;ball.y += normal.y * penetration;}}}// --- 主循环 ---function update() {// 更新六边形的旋转角度hexRotation += omega;// 更新球的速度:加重力、应用空气摩擦ball.vy += gravity;ball.vx *= airFriction;ball.vy *= airFriction;// 更新球的位置ball.x += ball.vx;ball.y += ball.vy;// 获取当前六边形的顶点const vertices = getHexagonVertices();// 检测并处理球与六边形每条边的碰撞for (let i = 0; i < vertices.length; i++) {const p1 = vertices[i];const p2 = vertices[(i + 1) % vertices.length];resolveCollisionWithEdge(p1, p2);}// 清空画布ctx.clearRect(0, 0, canvas.width, canvas.height);// 绘制六边形和球drawHexagon(vertices);drawBall();// 循环调用下一帧requestAnimationFrame(update);}// 启动动画update();</script>
</body>
</html>
运行结果
运行视频