3
\$\begingroup\$

Challenge

Your goal is to write a program which will output the 8 measurements of a rectangle, with only some measurements in the input. Your program should throw an error if it cant be done.

Here is what each measurement means:

|          left
|          |      centerX
|          |      |      right
|          |      |      |
|          v      v      v
|           _____________ 
|       ^  |             |  <---top 
|       |  |             |
|       |  |             | 
|height |  |             |  <---centerY
|       |  |             | 
|       |  |             |
|       v  |_____________|  <---bottom 
|                             
|          <----width---->      
|________________________________________

Input/Output Formats:

Input is in the form of some measurements of a box, one on each line. Output should be all 8 measurements of the corresponding box (or an error if the given measurements can not be used to find the other measurements).

For example, an input of

left 6
centerX 10
top 40
height 20

should print out

left 6
right 14
top 40
bottom 20
centerX 10
centerY 30
width 8
height 20

This is code-golf, so the shortest code wins.

\$\endgroup\$
5
  • 3
    \$\begingroup\$ It's unclear what the input should be. \$\endgroup\$
    – feersum
    Commented Oct 3, 2015 at 3:56
  • \$\begingroup\$ I don't get it. Generally, you will need 4 values (two of the horizontal, two of the vertical) to define the rectangle. Is the goal to get 4 values as input, and produce all of the values in the list? Just guessing, because it seems quite unclear. \$\endgroup\$ Commented Oct 3, 2015 at 3:58
  • 2
    \$\begingroup\$ The first sentence is a bit unclear as well—does only two pairs mean 4? This seems to conflict with the second sentence, given any pair of coordinates. \$\endgroup\$
    – Doorknob
    Commented Oct 3, 2015 at 3:58
  • 1
    \$\begingroup\$ i added some edits, sorry for the phrasing! \$\endgroup\$ Commented Oct 3, 2015 at 4:06
  • \$\begingroup\$ Is my attempt as a function valid? MFC: pastebin.com/raw/Pbi68pLj \$\endgroup\$
    – sergiol
    Commented Jul 7, 2017 at 14:09

2 Answers 2

6
\$\begingroup\$

Python 2 with SWI Prolog ('typical' install), on Windows, 595 565 bytes.

import sys,subprocess as w;o='left right top bottom centerX centerY width height'
g={k:v for k,v in [l.strip().split() for l in sys.stdin.readlines()]};s='L,R,T,B,C,D,W,H';
open('t','w').write(
":-use_module(library(clpfd)).\nr(%s):-L#=R-2*(R-C),L#=R-W,L#=C-W//2,B#=T-2*(T-D),B#=T-H,B#=D-H//2,%s."%
(s,','.join('writeln(%s)'%x for x in s.split(','))));r='\n'.join([a+' '+b for (
a,b) in zip(o.split(),w.check_output("swipl -q -f t -t r(%s)."%(','.join(g.get(
x,x[0].replace('centerY','d').upper()) for x in o.split()))).split('\r\n'))])
print '!' if '_' in r else r

e.g. with a text file for input, containing:

right 14
centerX 10
top 40
height 20

it does this:

D:\>type rectin.txt|c:\python27\python.exe d:\rect.py
left 6
right 14
top 40
bottom 20
centerX 10
centerY 30
width 8
height 20

And in the error condition if the contents of the stdin file are not enough to calculate the other values, it does this:

D:\>type rectin.txt|c:\python27\python.exe d:\rect.py
!

NB. It relies on swipl.exe being in the PATH

Explanation

I started writing in Python, got bored of expressing all the possible combinations of relationship (each one can be derived from three different combinations). I thought "must be a job for Prolog". So I installed a Prolog, headed for a tutorial, and got something that just about works. It's this:

:-use_module(library(clpfd)).

r(L,R,T,B,C,D,W,H):-
    L#=R-2*(R-C),
    L#=R-W,
    L#=C-W//2,
    B#=T-2*(T-D),
    B#=T-H,
    B#=D-H//2,

    writeln(L),
    writeln(R),
    writeln(T),
    writeln(B),
    writeln(C),
    writeln(D),
    writeln(W),
    writeln(H).

It uses the clpfd library (part of the 'typical install' requirement), which provides 'declarative integer arithmetic'. This gives the big advantage that I only need to define Left in terms of (Right and CenterX), (Right and Width), (CenterX and Width). From that, it can derive Right, Center and Width. (Same with the vertical set Top/Bottom/CenterY/Height).

This also means I don't have to check which specific values are provided; I give all the available values and placeholders for the rest, and it either calculates the answers, or outputs some unknown variable placeholders.

Being extremely novice at Prolog, handling STDIN was too much for me right now, so I wrapped it with Python. I don't have an ungolfed version of the Python, but it's not doing anything too amazing; it reads STDIN into a dictionary of {measurement:value} pairs, then puts them in the preset order the Prolog code is expecting, merged with the uppercase first letter of the unknowns.

(There's an annoyance where all the measurements are unique by first letter, except centerX and centerY, so it replaces centerY with D).

Then it writes the Prolog script out to a file, shells out to Prolog to run it and read the result, parses the number output and pairs them up with the measurements in order.

Then checks if any of the outputs were uncomputable and throws an error (!), otherwise prints the result.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Awesome use of Prolog and CLP(FD) constraints! You can combine all these writeln/1 calls into a single call of format/2. For example, try: ?- format("~w~n~w~n~w~n", [a,b,c]). to see what I mean. To read from standard input, I recommend you use a DCG and then apply the DCG to user_input with SWI-Prolog's library(pio) and phrase_from_stream/2. See library(dcg/basics) for some useful definitions. I hope that this will allow you to shorten your code significantly. \$\endgroup\$
    – mat
    Commented Oct 7, 2015 at 15:22
  • \$\begingroup\$ @mat Thanks for the suggestions! (But they look too intimidating. I think I lucked out with how easy CLP(FD) is to use, after that I couldn't even make a recursive list-is-sorted-if predicate. I'm nowhere near applying a DCG to an io stream). (All my writeln/1 calls are generated from a Python list comprehension, they're already shorter than a basic format("~w~n~w~n~... call would be, even if I had known it existed). \$\endgroup\$ Commented Oct 10, 2015 at 5:37
0
\$\begingroup\$

MFC, 212

void P(int l,int t,int r,int b){CRect R(l,t,r,b);POINT c=R.CenterPoint();TRACE("Left:%d Top:%d Right:%d Bottom:%d CenterX:%d CenterY:%d Width:%d H:%d",R.left,R.top,R.right,R.bottom,c.x,c.y,R.Width(),R.Height());}

MFC, 213

void P(int l,int t,int r,int b){CRect R(l,t,r,b);CPoint c=R.CenterPoint();TRACE("Left:%d Top:%d Right:%d Bottom:%d CenterX:%d CenterY:%d Width:%d H:%d",R.left,R.top,R.right,R.bottom,c.x,c.y,R.Width(),R.Height());}

Outputs the result to Visual Studio's Debug Output Window.

Example:

P(12,7,23,30);

outputs

Left:12 Top:7 Right:23 Bottom:30 CenterX:17 CenterY:18 Width:11

Uncondensed format:

void P(int l, int t, int r, int b)
{
    CRect R(l, t, r, b);
    CPoint c= R.CenterPoint();
    TRACE("Left %d Top:%d Right:%d Bottom:%d CenterX:%d CenterY:%d Width:%d H:%d", R.left, R.top, R.right, R.bottom, c.x, c.y, R.Width(), R.Height());
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.