Compute missing box dimensions from given ones - algorithm

Given the structure:
structure box_dimensions:
int? left
int? right
int? top
int? bottom
point? top_left
point? top_right
point? bottom_left
point? bottom_right
point? top_center
point? bottom_center
point? center_left
point? center_right
point? center
int? width
int? height
rectangle? bounds
where each field can be defined or not.
How would you implement the function check_and_complete(box_dimensions) ?
That function should return an error if there is not enough fields defined to describe a box, or too many.
If input is consistent, it should compute the undefined fields.
You can describe a box by its center, width and height, or top_left and bottom_right corners, etc
The only solution I can think of contains way to many if-elses. I'm sure there's a smart way to do it.
EDIT
If you wonder how I end up with a structure like that, here is why :
I'm toying with the idea of a "layout by constraints" system:
User define a bunch of boxes, and for each box define a set of constraints like "box_a.top_left = box_b.bottom_right", "box_a.width = box_b.width / 2".
The real structure fields are actually expression AST, not values.
So I need to check if a box is "underconstrained" or "overconstrained", and if it's ok, create the missing expression AST from the given ones.

Yes, certainly there will be too many if-elses.
Here's my attempt to keep them reasonably organized:
howManyLefts = 0
if (left is set) { realLeft = left; howManyLefts++; }
if (top_left is set) { realLeft = top_left.left; howManyLefts++; }
if (bottom_left is set) { realLeft = bottom_left.left; howManyLefts++; }
if (center_left is set) { realLeft = center_left.left; howManyLefts++; }
if (bounds is set) { realLeft = bounds.left; howManyLefts++; }
if (howManyLefts > 1) return error;
Now, repeat that code block for center, right and width.
Now you end up with howManyLefts, howManyCenters, howManyRights and howManyWidths, all of them being either zero or one, depending on whether the value was provided or not. You need exactly two values set and two unset, so:
if (howManyLefts + howManyRights + howManyCenters + howManyWidths != 2) return error
if (howManyWidths == 0)
{
// howManyWidths is 0, so we look for the remaining 0 and assume the rest is 1s
if (howManyCenters == 0)
{ realWidth = realRight - realLeft; realCenter = (realRight + realLeft) / 2; }
else if (howManyLefts == 0)
{ realWidth = 2 * (realRight - realCenter); realLeft = realRight - realWidth; }
else
{ realWidth = 2 * (realCenter - realLeft); realRight = realLeft + realWidth; }
}
else
{
// howManyWidths is 1, so we look for the remaining 1 and assume the rest is 0s
if (howManyCenters == 1)
{ realLeft = realCenter - realWidth / 2; realRight = realCenter + realWidth / 2; }
else if (howManyLefts == 1)
{ realRight = realLeft + realWidth; realCenter = (realRight + realLeft) / 2; }
else
{ realLeft = realRight - realWidth; realCenter = (realRight + realLeft) / 2; }
}
Now, repeat everything for the vertical axis (i.e. replacing { left, center, right, width } with { top, center, bottom, height }).

Related

When creating an angle, how do I control the attributes of the automatically created points?

I'm working with a polygon and attempting to create angles with labels but when angles are created, so are the points used to define them. This would be fine but I can't control the labels on the automatically created points (and I don't know what they are called or how to find out).
var points = [
[0, 0],
[0, 5],
[3, 0]
];
for (k = 0; k < showAngle.length; k++) {
if (showAngle[k] == 1) {
var angle = board.create('angle', [points[k], points[((k + 1) % points.length)], points[((k + 2) % points.length)]],{fixed:true});
} else if (showAngle[k] == 2) {
var angle = board.create('angle', [points[k], points[((k + 1) % points.length)], points[((k + 2) % points.length)]], {
fixed: false,
name: function() {
return ((180/Math.PI)*JXG.Math.Geometry.rad(points[k], points[((k + 1) % points.length)], points[((k + 2) % points.length)])).toFixed(1) + '°';
}
});
}
}
https://jsfiddle.net/jscottuq/acyrLxfh/12/ contains what I've got so far.
The arrays showLen and showAngle are setting what labels are shown for each side/angle (0 - no label, 1 - name , 2 - measurement).
These will be set when the jsxgraph is created.
At the time being, the possibility to control the style of the newly created points of an angle is missing. We will add this soon.
However, a solution would be to use the already existing points which are hidden in this example. For this it would be helpful to kee a list of these points, e.g. jxg_points:
var jxg_points = [];
for (i = 0; i < points.length; i++) {
var rise = points[(i + 1) % points.length][1] - points[i][1];
var run = points[(i + 1) % points.length][0] - points[i][0];
var point = board.create('point', [points[i][0], points[i][1]], {
fixed: true,
visible:false
});
jxg_points.push(point); // Store the point
points[i].pop();
len[i] = Math.round((Math.sqrt(rise * rise + run * run) + Number.EPSILON) * 100) / 100;
}
Then the points can be reused for the angles without creating new points:
for (k = 0; k < showAngle.length; k++) {
if (showAngle[k] == 1) {
angle = board.create('angle', [
jxg_points[k],
jxg_points[((k + 1) % jxg_points.length)],
jxg_points[((k + 2) % jxg_points.length)]
],{fixed:true});
} else if (showAngle[k] == 2) {
var angle = board.create('angle', [
jxg_points[k],
jxg_points[((k + 1) % jxg_points.length)],
jxg_points[((k + 2) % jxg_points.length)]], {
fixed: false,
name: function() {
return ((180/Math.PI)*JXG.Math.Geometry.rad(points[k], points[((k + 1) % points.length)], points[((k + 2) % points.length)])).toFixed(1) + '°';
}
});
}
}
See it live at https://jsfiddle.net/d8an0epy/.

how to solve the overlapping sub problems in Dynamic programming

Problem statement =>
You are given queries. Each query consists of a single number N. You can perform any of the 2 operations on in each move:
1: If we take 2 integers a and b where N=a*b (a>1,b>1), then we can change N=max(a,b).
2: Decrease the value of N by 1.
Determine the minimum number of moves required to reduce the value of N to 0.
here is the link for better understanding.
https://www.hackerrank.com/challenges/down-to-zero-ii/problem
I know here are some overlapping sub-problems and we can use DP to ignore the computation of same sub-problems again and again.
Now, my question is how in this problem, same sub-problems have same solutions. Because we have to solve this from top to bottom and sub-problem have same solution if we solved them from bottom to top.
For example
N=4
1 possibility = 4->3->2->1->0
2 possibility = 4->2->1->0
Now in above two possibility, 2 is repeating and I can use DP, but how I store their values. I mean, in 1 possibility solution of 2 is different from 2nd possibility because in first one I've to traverse 4->3->2 here solution of 2 is 2 and in 2nd possibility we traverse 4->2 and solution of 2 here is 1 now these 2 same sub-problems have different values because of the solving from top to bottom. Now I'm totally confused here. Please someone help me out in this.
The solution for a number N should store the minimun steps required to make it 0
this is how the sol should look
int dp[1000001];
memset(dp,-1,sizeof(dp);
int sol(N){
if(N == 2){
return 2;
}
if(dp[n]!=-1){
return dp[n]'
}
int sol = 1+sol(min(move1,move2));
dp[n] = sol ;
return sol;
}
EDIT 2:
I think this is a solution for your problem. The solution is in JavaScript:
// ****************************************************************************
function findPaths(tree, depth = 0, path = [], paths = [-1, []]) {
const [node, children] = tree
path.push(node)
if (!children) {
// console.log(path, depth)
if (paths[0] === -1 || paths[0] > depth) {
paths[0] = depth
paths[1] = [paths.length]
} else if (paths[0] === depth) {
paths[1].push(paths.length)
}
paths.push([...path])
path.pop()
return
}
children.forEach((el) => {
findPaths(el, depth + 1, path, paths)
})
path.pop()
return paths
}
// ****************************************************************************
function downToZero(n) {
const tree = [n]
const divisors = []
for (let i = 2; i <= Math.sqrt(n); i++) {
if (n % i == 0) {
divisors.push(Math.max(i, n / i))
}
}
if (divisors.length) {
tree.push(divisors.map(downToZero))
} else if (n > 0) {
tree.push([downToZero(n - 1)])
}
return tree
}
// ****************************************************************************
function printPaths(paths) {
console.log('Total number of solutions:', paths.length - 2)
console.log('Total number of solutions with minimal moves:', paths[1].length)
console.log('Minimal moves:', paths[0])
paths[1].forEach((pathIndex) => {
let printPath = ''
paths[pathIndex].forEach((element) => {
printPath = `${printPath}${printPath === '' ? '' : '->'}${element}`
})
console.log(printPath)
})
console.log('')
}
// ****************************************************************************
// Test
printPaths(findPaths(downToZero(812849)))
printPaths(findPaths(downToZero(100)))
printPaths(findPaths(downToZero(19)))
printPaths(findPaths(downToZero(4)))

Custom time interval in bar chart has no gaps between bars

I created my own d3-time interval and added it to the switching time intervals example (ported to this jsfiddle).
But I'm unhappy with the result. The gaps between two bars are not shown.
I'd like the bars looking with a gap as all the other intervals. I suspect my implementation of the custom interval is wrong, but I cannot figure out what the problem is.
I used this implementation in another project and there the opposite happened: The gaps are maximal large and the bars very small.
var threeMonthsInterval = d3.timeInterval(
function (date) {
date.setDate(1);
date.setHours(0, 0, 0, 0);
var currentMounth = date.getMonth()
if (currentMounth <= 2) {
// 'Q1';
date.setMonth(0)
} else if (currentMounth > 2 && currentMounth <= 5) {
// 'Q2';
date.setMonth(3)
} else if (currentMounth > 5 && currentMounth <= 8) {
// 'Q3';
date.setMonth(6)
} else {
// 'Q4';
date.setMonth(9)
}
},
function (date, step) {
date.setMonth(date.getMonth() * 3 + step);
},
function (start, end) {
return (end.getMonth() - start.getMonth()) / 3 + (end.getFullYear() - start.getFullYear()) * 3;
},
function (date) {
return date.getMonth() * 3;
}
);
The one that counts the number between two dates
function (start, end) {
return (end.getMonth() - start.getMonth()) / 3 + (end.getFullYear() - start.getFullYear()) * 3;
},
is the one that tells dc.js how many bars to plan for, and therefore how wide they should be.
I haven't tested your code, so there could be other problems, but there are four quarters in a year, so that last number should be 4.

Swift fatal error: Can't form Range with end < start

LeetCode medium 120. Triangle (Dynamic Programming)
Question:
Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.
For example, given the following triangle
[
[2],
[3,4],
[6,5,7],
[4,1,8,3]
]
//The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11).
//Note:
//Bonus point if you are able to do this using only O(n) extra space, where n is the total number of rows in the triangle.
I always get
fatal error: Can't form Range with end < start
on "for i in (row-1)...0".
Thank you so much! Appreciate your time!
class Solution
{
func minimumTotal(triangle: [[Int]]) -> Int
{
if triangle.count == 0
{
return 0
}
if triangle.count == 1
{
return triangle[0][0]
}
var arr = [Int](count: triangle.last!.count, repeatedValue: 0)
let row = triangle.count
for i in (row-1)...0
{
let col = triangle[i].count
for j in 0...col-1
{
if i == row-1
{
arr[i] = triangle[i][j]
continue
}
arr[j] = min(arr[j], arr[j+1]) + triangle[i][j]
}
}
return arr[0]
}
}
var test1 = Solution()
//var input = [[10]]
//var input = [[1],[2,3]]
var input = [[-1],[2,3],[1,-1,-3]]
var result = test1.minimumTotal(input)
print(result)
for in (0...row-1).reverse()
Swift can't read row-1...0
It's a bad idea to create a range where the start is higher than the end: your code will compile, but it will crash at runtime, so use stride instead of ranage
for i in (row-1).stride(to: 0, by: 1) { }

barnes hut tree endlessly looping between insert and internalInsert

I'm trying to implement this data structure, a Barnes-Hut Octree, and I keep running into an endless loop, terminated by an out of memory exception.
The complete fiddle is here: http://jsfiddle.net/cWvex/
but the functions I'm looping between are these:
OctreeNode.prototype.insert = function (body) {
console.log('insert');
if(this.isInternal){
this.internalInsert(body);
return;
}
if(this.isExternal){
// insert the body into the spec. quadrant, call internalUpdate
for(var quadrant in this.internal.quadrants){
if(this.internal.quadrants.hasOwnProperty(quadrant)){
this.internal.quadrants[quadrant] = new OctreeNode();
}
}
this.isExternal = false;
this.isInternal = true;
this.internalInsert(this.external);
this.external = null;
this.internalInsert(body);
return;
}
if(this.isEmpty){
this.external = body;
this.isEmpty = false;
this.isExternal = true;
return;
}
};
// Precondition: quadrants' nodes must be instantiated
OctreeNode.prototype.internalInsert = function(body) {
console.log('internalInsert');
this.internal.quadrants[this.quadrant(body)].insert(body);
this.internalUpdate(body);
};
Anyone got an idea of what I'm missing?
I think the problem is to do with the quadrant function:
OctreeNode.prototype.quadrant = function (body) {
console.log('quadrant');
var pos = this.internal.pos;
var quadrant = (body.pos.x < pos ? 'l' : 'r') +
(body.pos.y < pos ? 'u' : 'd') +
(body.pos.z < pos ? 'i' : 'o');
return quadrant;
};
The chosen quadrant should be based on the centre of the quadrant, not on the centre of mass. I think you need to create a new variable to define the centre of the quadrant.
Note that when you add nodes, the centre of mass (stored in pos) can change, but the centre of the quadrant remains fixed (otherwise things will go wrong when you descend into the octtree).
At the moment, each new node is generated with a pos of 0,0,0 and so every point will always end up being assigned into the same quadrant of the node. Therefore when you try to place two bodies into the tree, you end up with an infinite recursion:
Body 1 is inserted into node x
Body 2 is inserted into node x
Node 1 is split.
Body 1 is inserted into quadrant 1 of node x
Body 2 is inserted into quadrant 1 of node x
Back to step 1 with x changed to the node at quadrant 1 of node x
EDIT
Incidentally, in the code that reads:
avgPos.x = (body.pos.x*body.mass +
avgPos.x * totalMass) / totalMass + body.mass
I think you need some more brackets to become
avgPos.x = (body.pos.x*body.mass +
avgPos.x * totalMass) / (totalMass + body.mass)
or the update of centre of mass will go wrong.

Resources