Construct the point with two segments

Given a rational point P, return four integral points A, B, C, and D, such that the line segments AB and CD intersect only at P. To make it a bit more interesting, segment AB doesn't include A and B.

You can take input P as $$\\left(\frac ab,\frac cd\right)\$$ or $$\\left(\frac ab,\frac cb\right)\$$, and assume that b and d are the smallest possible positive integers for the value. a and c are also integers (not necessarily positive).

Shortest code wins.

Test cases (answers are not unique):

(1/2,1/2), aka. (1,1)/2 => (0,0)-(1,1);(0,1)-(1,0)
(1/2,-1/3), aka. (3,-2)/6 => (1,0)-(-2,-2);(0,0)-(6,-4)
(-5/2,5/4), aka. (-10,5)/4 => (0,0)-(-60,30);(-3,2)-(1,-4)
(1/2,0), aka. (1,0)/2 => (0,0)-(42,0);(0,1)-(1,-1)

• Nice problem! I'm sure the outputs are not unique, but you could list at least one example for each test case. Also I would add test cases where the input point is itself integral in one or both coordinates. Can we output A=B=C=D=P in that case? Or maybe it's better to explicitly exclude such inputs from the problem.
– lynn
Apr 6 at 9:44
• May we output eight integers in some consistent order? Apr 6 at 17:06
• Solvers be warned, if you pick two fixed points as one endpoint of each segment, you'll fail when the point P is collinear because you'll get parallel segments.
– xnor
Apr 6 at 20:56
• "To make it a bit more interesting" = "To make those who already solved this do even more work, to address something that was previously allowed by my comment which I have now deleted" ... SIGH. -1 Apr 8 at 17:16
• @JonathanAllan Agree. I tried to simplify description and there exist solution that break with it. Is my fault so agree your -1
– l4m2
Apr 10 at 19:21

Charcoal, 38 bytes

ＮθＮηＮζ≔⁺×³θζε≔⁻⊗θ×ε⊖⊗ζδＩ⟦ε⁰δ⊗ηε¹δ⊕⊗⁻ηζ


Try it online! Link is to verbose version of code. Takes (a/b,c/b) as input as three integers a, c, b. Explanation:

ＮθＮηＮζ


Input a, c and b.

≔⁺×³θζε


Calculate 3a+b.

≔⁻⊗θ×ε⊖⊗ζδ


Calculate 5a+b-6ab-2b².

Ｉ⟦ε⁰δ⊗ηε¹δ⊕⊗⁻ηζ


Output the lines (3a+b,0)-(5a+b-6ab-2b²,2c);(3a+b,1)-(5a+b-6ab-2b²,2c-2b+1).

• Fails on -2 1 2
– att
Apr 8 at 6:55
• @att Indeed, it fails for a+b=0. Thanks for pointing that out!
– Neil
Apr 8 at 9:06
• @att New version is up, hopefully without any edge cases this time!
– Neil
Apr 8 at 16:24

Wolfram Language (Mathematica), 282522 17 bytes

#2{0,1,I,1+I-I#}&


Try it online!

Input [b, a+c*I] corresponding to the point $$\\big(\frac ab,\frac cb\big)\$$. Output four complex numbers, grouping the first and last two into segments. For tuple output, append /*ReIm (+6 bytes).

The segments $$\\big((0,0),(1,0)\big)\$$ and $$\\big((0,1),(1,1-b)\big)\$$ intersect at $$\\big(\frac1b,0\big)\$$. We can then rotate-scale about the origin so that $$\(1,0)\$$ coincides with $$\(a,c)\$$, and $$\\big(\frac1b,0\big)\$$ coincides with $$\\big(\frac ab,\frac cb\big)\$$. This yields the segments $$\\big((0,0),(a,c)\big)\$$, $$\\big((-c,a),(a-c+bc, a+c-ab)\big)\$$.

Python3, 183 bytes:

lambda A,B,C:[*P(A/B,C/A,0),*P(A/B,C/A-B,A)]
from math import*
def P(p,a,b):
q=[(floor(p),-1),(ceil(p),1)]
for J,K in q:
if round(T:=J*a+b,5)==int(T):yield J,T
else:q+=[(J+K,K)]


Try it online!

• f could be just lambda A,B,C:[*P(A/B,C/A,0),*P(A/B,C/A-B,A)]. Also yield J,T saves one. Apr 7 at 21:17
• @JonathanAllan Thank you, updated Apr 7 at 21:58

Ruby, 49 bytes

->a,c,b{[x=3*a+b,0,a+=a-x*b+=b-1,c+=c,x,1,a,c-b]}


Try it online!

Ruby port of Jonathan Allan's Python port of Neil's Charcoal solution.

Fixed by using the new formula from Neil's answer.

• ...which made the same line for a=-2, b=2, c=1 unfortunately. The spec has also since been amended to make AB end-point-exclusive. Feel free to update to Niel's latest which I imagine conforms to all of the new spec. Apr 8 at 17:31
• @JonathanAllan Indeed my comment has been upvoted so maybe that's a sign that I've got it right this time ;-)
– Neil
Apr 9 at 20:50