我正在尝试解决"Eric S. Roberts (1986)递归思考"一书中的任务 9.3。让我们考虑我们有简单的三角形:
.
/
/
/
/
/
/
/
/
/
/
/
/_______________________
将较小的跳蚤放在形成大跳蚤背面的两个部分中的每个部分上,可以进行下一阶段:
.
/
/
/
_________/ _________
/ /
/ /
/ /
/ /
/
/
/
/_______________________
这两种新跳蚤中的每一个都容纳了两只较小的跳蚤,它们为我们提供了以下动物园:
.
/
/
. / .
___/____/ ___/____
/ /
: / :
/_ / /_
/ /
/
/
/
/_______________________
问题是我无法弄清楚这里的递归模式。我什至不知道我应该如何开始考虑这项任务以找到解决方案。
对于绘图,我使用3个函数:
- setPointer(x, y) -- 将笔设置为坐标 x,y
- vector(dx,dy) -- 从 x, y 到 dx, dy 画线
- polarVec(l, angle) 从 x, y 绘制线,长度 l 按角度(以度为单位)
我在画布上绘画的课程:
var X_CENTER = 400;
var Y_CENTER = 400;
function DrawLib() {
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var inverted_y = 800;
var _dx = 0, _dy = 800;
this.setPoint = function (x, y) {
inverted_y = 800;
inverted_y -= y;
_dx = x;
_dy = inverted_y;
ctx.moveTo(x, inverted_y);
};
this.vector = function(dx, dy) {
_dx += dx;
_dy -= dy;
ctx.lineTo(_dx, _dy);
};
this.polarVec = function(lengthPx, angle) {
var radians = angle * Math.PI / 180;
this.vector(lengthPx * Math.cos(radians), lengthPx * Math.sin(radians));
}
this.stroke = function () {
ctx.stroke();
}
}
var drawLib = new DrawLib();
我的解决方案(仅适用于订单 0 和 1):
function fractLine(order, l, theta) {
if (order == 0) return drawLib.polarVec(l, theta);
fractLine(order - 1, 2 * l/3,theta);
fractLine(order - 1, l/3,theta - 120);
fractLine(order - 1, l/3,theta + 120);
fractLine(order - 1, 2* l/3,theta);
}
function triangleWithFleas(order, l) {
//left side of triangle
drawLib.setPoint(X_CENTER - l/2, Y_CENTER - Math.sqrt(3)* l/4);
//start drawing
drawLib.vector(l,0);
fractLine(order, l, 120);
fractLine(order, l, 240);
drawLib.stroke();
}
triangleWithFleas(1, 400);
根据@jxh评论,我需要一个函数,从特定起点以特定方向绘制三角形。然后,它应该递归调用自己两次,调整每次调用的方向和起点。
我已经更新了我的代码。 triangle
绘制三角形,showFlake
调用triangle
后递归绘制跳蚤三角形。
现在它完美运行。
var X_CENTER = 400;
var Y_CENTER = 400;
function DrawLib() {
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var inverted_y = 800;
var _dx = 0, _dy = 800;
this.setPoint = function (x, y) {
inverted_y = 800;
inverted_y -= y;
_dx = x;
_dy = inverted_y;
ctx.moveTo(x, inverted_y);
};
this.vector = function(dx, dy) {
_dx += dx;
_dy -= dy;
ctx.lineTo(_dx, _dy);
return {
x: _dx,
y: 800 - _dy // coord inversion
};
};
this.polarVec = function(lengthPx, angle, color) {
var radians = angle * Math.PI / 180;
return this.vector(lengthPx * Math.cos(radians), lengthPx * Math.sin(radians));
}
this.stroke = function () {
ctx.stroke();
}
}
var drawLib = new DrawLib();
function triangle(x, y, l, theta) {
drawLib.setPoint(x, y);
drawLib.polarVec(l, theta);
var firstAngle = theta + 120;
var secondAngle = theta + 240;
var firstTrianleStartPoint = drawLib.polarVec(2 * l / 3, firstAngle);
drawLib.polarVec( l / 3, firstAngle);
var secondTrianleStartPoint = drawLib.polarVec(2 * l / 3, secondAngle);
drawLib.polarVec(l / 3, secondAngle);
return {
x1: firstTrianleStartPoint.x,
y1: firstTrianleStartPoint.y,
x2: secondTrianleStartPoint.x,
y2: secondTrianleStartPoint.y,
}
}
function showFlake(order, x, y, l, theta) {
if(order === 0) return;
var coords = triangle(x, y, l, theta);
showFlake(order - 1, coords.x1, coords.y1, l / 3, theta + -60);
showFlake(order - 1, coords.x2, coords.y2, l / 3, theta + 60);
}
var len = 600
var x = X_CENTER - len / 2;
var y = Y_CENTER - Math.sqrt(3) * len / 4;
showFlake(5, x, y, len, 0);
drawLib.stroke();