9
\$\begingroup\$

A certain children's game, often called "Huckle Buckle Beanstalk", is played with two players. Here is a brief description of how the game is played:

  1. One player is designated the "hider", and the other the "seeker".
  2. The seeker goes out of the room while the hider hides a small, pre-selected object, the "treasure".
  3. The hider then attempts to look for the object while the seeker gives them helpful hints:
    • If the seeker is approaching the treasure, the hider will call out "warmer!"
    • If the seeker is moving away from the treasure, the hider will call out "cooler!"
  4. Once the seeker finds the treasure, they announce that they have found it.

Your children want you to play this game with them, however, you are very busy answering questions on codegolf.SE instead. So, you decide to write a program to play the game with them. However, you want to use as little time as possible typing, so you try to make the program as little characters as possible.

We can define the room in which the game is played as a two dimensional toroidal square field. The coordinate 0,0 is the bottom left corner, and the coordinate 99,99 is the top right corner. The treasure is placed at some position n,m where n and m are both positive integers between 0 and 99 inclusive.

Your program will obtain input from the player using its inbuilt user input function (e.g. prompt(), raw_input(), etc.) If your chosen language does not have a user input function, take input from STDIN instead. The game will work as follows:

  1. The program "hides" the treasure at a position n,m.
  2. The program prompts the seeker to input an initial searching position. The input will come in the form x y where x and y are positive integers.
  3. The program outputs "correct" if the initial searching position x,y is equal to the treasure's position n,m and terminates. Otherwise:
  4. The program will prompt the seeker to move. The input comes in the form a b where a and b are integers that may be negative. This represents the direction vector that the seeker is moving in (a is the x direction and b is the y direction).
  5. If the resultant position of the seeker is at the treasure, the program outputs "correct" and terminates. Otherwise:
  6. The program outputs "cooler" if the seeker is moving away from the treasure, or "hotter" if they are moving towards the treasure.
  7. Go to step 4.

The words "moving away" and "moving towards" may be ambigious. For this challenge, if the resultant position of the seeker after moving is closer to the treasure than their position before they were moving, they are moving towards the treasure. Otherwise, they are moving away. (Yes, this does mean that if the resultant and previous position are the same distance away, the program should output "cooler").

This is code golf, so shortest code wins. Ask questions if the specification is not clear.

\$\endgroup\$
19
  • \$\begingroup\$ Do the input prompts need to contain any text/question? If so, please specify it. \$\endgroup\$ Sep 5, 2014 at 23:13
  • 6
    \$\begingroup\$ I've seen this game played many times on TV and have done it a few times myself, but never have I heard the term "Huckle Buckle Beanstalk". \$\endgroup\$ Sep 5, 2014 at 23:13
  • \$\begingroup\$ ​​​​​​​​​​​​​​​@Martin No, there doesn't need to be any text. \$\endgroup\$
    – absinthe
    Sep 5, 2014 at 23:15
  • 1
    \$\begingroup\$ ​​​​​​​​​​​​​​​@ipi The field is toroidal, i.e. they'll wrap around to the other side of the field. \$\endgroup\$
    – absinthe
    Sep 6, 2014 at 0:25
  • 1
    \$\begingroup\$ The moves wrap around, but what about the distance computation? Is the distance between (0,0) and (99,99) equal to 1 or 99·√2? \$\endgroup\$
    – Tobia
    Sep 6, 2014 at 23:32

11 Answers 11

2
\$\begingroup\$

Javascript, 275 279

Not a winner by any means, but this should get things started. Uses a trick with eval() and defining 100 as a "constant" to shave off a few bytes. Ungolfed version below.

function D(){return Math.sqrt((x-n)*(x-n)+(y-m)*(y-m))}
H=100;
n=~~(Math.random()*H);m=~~(Math.random()*H);
P="s=prompt().split(' ')";
eval(P);
x=~~s[0];y=~~s[1];i=0;
while(x!=n||y!=m)
{
    if(i)alert(i>j?"hotter":"colder");
    i=D();
    eval(P);
    x=(x+~~s[0])%H;
    y=(y+~~s[1])%H;
    j=D()
}
alert("correct")

Edit: I fell victim to Javascript's string + number operations, hence why D() wasn't working properly. I also fixed a bug where "hotter" was displayed before "correct". This adds 4 bytes.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ why use semicolons? \$\endgroup\$ Sep 6, 2014 at 2:27
  • \$\begingroup\$ If n and m are both set to zero (for testing purposes), and 0 1 is entered as the initial position, both 0 -1 and 0 1 return colder. \$\endgroup\$
    – es1024
    Sep 6, 2014 at 5:24
  • \$\begingroup\$ In the for loop why do you have new lines? Put all of the code on one line and you can save 22 characters (maybe more). \$\endgroup\$
    – Beta Decay
    Sep 6, 2014 at 9:07
  • 1
    \$\begingroup\$ This is the ungolfed version. The original version is all on one line (275 characters long). \$\endgroup\$ Sep 6, 2014 at 9:16
  • \$\begingroup\$ javascript joke colder == cooler \$\endgroup\$
    – ajax333221
    Sep 11, 2014 at 15:03
2
\$\begingroup\$

Python 3 - 238 bytes


Code:

from random import*
r=randint;a=100;X=r(0,a);Y=r(0,a);d=0;F=lambda:((X-x%a)**2+(Y-y%a)**2)**0.5;i=lambda:map(int,input().split());x,y=i()
while F():
 if d:print(["cooler","hotter"][d<D])
 D=F();Z,K=i();x+=Z+a;y+=K+a;d=F()
print("correct")

Ungolfed:

from random import*

treasure_x = random.randint(0,100)
treasure_y = random.randint(0,100)
distance = lambda:((treasure_x - x % 100) ** 2 + (treasure_y - y % 100) ** 2) ** 0.5
x, y = map(int, input("Coordinates in the form x y: ").split())
new_distance = 0

while distance():
    if new_distance:
        if new_distance < prev_distance:
            print("hotter")
        else:
            print("cooler")
    prev_distance = distance()
    dx, dy = map(int, input("Move in the form dx dy: ").split())
    x = (dx + x) % 100
    y = (dy + y) % 100
    new_distance = distance()

print("correct")

Sample run:

$ python hotter_colder.py 
50 50
10 0
cooler
-10 0
hotter
-10 0
hotter
-10 0
hotter
-10 0
hotter
-10 0
cooler
5 0
hotter
1 0
hotter
1 0
hotter
1 0
hotter
1 0
hotter
1 0
cooler
-1 0
hotter
0 10
cooler
0 -10
hotter
0 -10
hotter
0 -10
cooler
0 5
hotter
0 1
hotter
0 1
correct

I won't say that my strategy in finding the treasure is particularity fast...

\$\endgroup\$
2
\$\begingroup\$

Groovy - 278 266 262

Golfed:

def x,y,n,m,d,D=999,S=100,r=newScanner(System.in);n=Math.floor(Math.random()*S);m=Math.floor(Math.random()*S);while(true){x=r.nextInt();y=r.nextInt();d=Math.sqrt((x-n)**2+(y-m)**2);if(d==0){print"Correct";break;}else if(d<D){print"Cooler"}else{print"Hotter"}D=d}

Ungolfed:

def x,y,n,m,d
def dist = 99999
def r = new Scanner(System.in)
def S = 100
n = Math.floor(Math.random()*S)
m = Math.floor(Math.random()*S)
println "Treasure is at: $n $m"
while(true){
    x = r.nextInt()
    y = r.nextInt()
    d = Math.sqrt((x-n)**2+(y-m)**2)
    if(d == 0){print "Correct"; break;}
    else if(d > dist){print "Hotter" }
    else{print "Cooler"}
    dist = d
}

Trial:

-1 -1
Cooler 12 12
Cooler 14 14
Cooler 13 13
Hotter 15 15
Cooler 90 55
Cooler 95 -100
Hotter 95 83
Correct
\$\endgroup\$
5
  • \$\begingroup\$ Can you please document some sample runs of this solution in action? I believe Math.sqrt((x-n2)+(y-m2)) returns NaN when x<n, y<m . \$\endgroup\$ Sep 6, 2014 at 12:37
  • \$\begingroup\$ Yes, sure. As soon as I get home :) \$\endgroup\$
    – An SO User
    Sep 6, 2014 at 12:47
  • \$\begingroup\$ Cool... Note: as I understand the OP, the initial input is an absolute position, and subsequent inputs are relative. Also, the grid wraps around (toroidal). I don't see how this works, as-is, and am surprised it received an upvote. \$\endgroup\$ Sep 6, 2014 at 13:56
  • \$\begingroup\$ @MichaelEaster Please check the edit. Let me know if I have done anything wrong :) \$\endgroup\$
    – An SO User
    Sep 6, 2014 at 18:57
  • \$\begingroup\$ I've posted my solution, as I understand the problem. I can't comment on yours but will let the voters decide :) \$\endgroup\$ Sep 6, 2014 at 21:25
2
\$\begingroup\$

Groovy - 343 chars

Derived somewhat from LittleChild's answer.

Golfed:

z=100
f={Math.floor(Math.random()*z)}
h={println it}
r=new Scanner(System.in)
i={r.nextInt()}
n=f();m=f();x=i();y=i();p=z;a=0;b=0
g={(Math.abs(it))**2};o={i,j->(j<0)?(((i+j)<0)?(((i+j)+z)%z):(i+j)):(i+j)%z};u={Math.sqrt g(n-x)+g(m-y)};d=u()
while(d>0.1){if(d<p){h "Hotter"}else{h "Cooler"};a=i();b=i();x=o(x,a);y=o(y,b);p=d;d=u()}
h "Correct"

Ungolfed:

z=100
f={Math.floor(Math.random()*z)}
h={println it}
r=new Scanner(System.in)
i={r.nextInt()}

n=f();m=f()
x=i();y=i()
p=z;a=0;b=0

g = {(Math.abs(it))**2}
o = {i,j->(j<0)?(((i+j)<0)?(((i+j)+z)%z):(i+j)):(i+j)%z}
u = {Math.sqrt g(n-x)+g(m-y)};d=u()

while (d>0.1) {
    if (d<p) { h "Hotter" } else { h "Cooler" }
    a=i();b=i()
    x=o(x,a);y=o(y,b)
    p=d;d=u()
}
h "Correct"

Sample run, where program emits the target for illustration. From my understanding of OP, the initial input is absolute, and subsequent inputs are relative. Also, the grid wraps around.

run A:

bash$ groovy X.groovy 
goal 98.0 19.0
1 19
Hotter
-1 0
Cooler
-1 0
Hotter
-1 0
Correct

run B:

bash$ groovy X.groovy 
goal 93.0 20.0
90 16
Hotter
2 2
Hotter
1 0
Hotter
0 -18
Cooler
0 -1
Cooler
0 -1
Hotter
0 -79
Hotter
0 1
Correct
\$\endgroup\$
1
  • \$\begingroup\$ Glad that my code be of use to you! thumbs up :) \$\endgroup\$
    – An SO User
    Sep 7, 2014 at 7:18
2
\$\begingroup\$

APL, 86 chars

h←?2⍴s←100⋄1{h≡n←s|s+⍵+⎕:⎕←"correct"⋄⍺:0∇n⋄⎕←(</+/⊃×⍨n⍵-¨⊂h)⌷"cooler" "hotter"⋄0∇n}0 0

Distance computation doesn't wrap around, but moves do.

Ungolfed:

h←?2⍴s←100                  ⍝ generate random starting point
1{                          ⍝ loop starting with ⍺←1 (1 if first loop) and ⍵←0 0 (position)
    n←s|s+⍵+⎕               ⍝ n←new position, ⍵ plus the move read from input, modulo 100
    n≡h: ⎕←"correct"        ⍝ check for end condition
    ⍺: 0∇n                  ⍝ if first loop, skip the rest and ask for a move again
    t←</+/⊃×⍨n⍵-¨⊂h         ⍝ t←1 if n is closer to h than ⍵ (squared distance)
    ⎕←t⌷"cooler" "hotter"   ⍝ output thermal gradient label
    0∇n                     ⍝ loop with new position
}0 0

Example:

⎕:
      22 33
⎕:
      2 6
hotter
⎕:
      0 1
cooler
⎕:
      0 ¯3
correct
\$\endgroup\$
2
\$\begingroup\$

Python 2.7, 227

from random import*
r=randint
h=100
n=r(0,h)
m=r(0,h)
i=lambda:map(int,raw_input().split())
x,y=i()
d=lambda:(x%h-n)**2+(y%h-m)**2
e=d()
while e:
 p=e;a,b=i();x+=a;y+=b;e=d()
 if e:print e<p and'hotter'or'cooler'
print'correct'

I got the input function and the idea of applying the modulo in the distance calculation rather than the location update from matsjoyce's answer.

We only need distances for comparisions: Are we at the exact location? Are we closer than before? For both of these, we get the same result comparing the squares of the distances as we would comparing the distances. The square-root calculation required to get the actual distance is unnecessary.

Ungolfed:

import random

h = 100 # height (and width) of the square grid

# location of item
n = random.randint(0, h)
m = random.randint(0, h)

def input_pair():
    return map(int, raw_input().split())

x,y = input_pair()

def distance_squared():
    return (x % h - n)**2 + (y % h - m)**2

er = distance_squared()
while er:
    previous_er = er
    a,b = input_pair()
    x += a
    y += b
    er = distance_squared()
    if er:
        print 'hotter' if er < previous_er else 'cooler'
print 'correct'

Sample run:

50 50
20 0
hotter
20 0
cooler
-20 0
hotter
10 0
cooler
-10 0
hotter
-1 0
hotter
-1 0
hotter
-5 0
cooler
5 0
hotter
-1 0
cooler
1 0
hotter
1 0
cooler
-1 0
hotter
0 10
hotter
0 10
hotter
0 10
cooler
0 -5
hotter
0 -1
hotter
0 -1
hotter
0 -1
correct
\$\endgroup\$
1
  • \$\begingroup\$ The trick with the squares, ignoring the square root step, is very clever.​​​​​​​​​​​​​​​ +1 \$\endgroup\$
    – absinthe
    Sep 7, 2014 at 4:01
1
\$\begingroup\$

ECMAScript 6, 262

Z=100;A=Math.abs;P=(a,b)=>(q=Math.min(A(a-b),Z-A(a-b)),q*q);G=_=>prompt().split(' ');R=_=>new Date%Z;V=_=>P(X,I)+P(Y,J);I=R();L=G();X=+L[0];Y=+L[1];J=R();for(D=V();D;D=N)T=G(),X=(+T[0]+Z+X)%Z,Y=(+T[1]+Z+Y)%Z,N=V(),N&&alert(N<D?"hotter":"cooler");alert("correct")

Ungolfed:

Z=100;
M=Math.min;
A=Math.abs;
S=a=>a*a;
P=(a,b)=>S(M(A(a-b),Z-A(a-b)));
G=_=>prompt().split(' ');
R=_=>new Date%Z;
V=_=>P(X,I)+P(Y,J);
I=R();
L=G();
X=+L[0],Y=+L[1];
J=R();
for(D=V();D;D=N)
    T=G(),
    X=(+T[0]+Z+X)%Z,Y=(+T[1]+Z+Y)%Z,
    N=V(),
    N&&alert(N<D?"hotter":"cooler");
alert("correct")
\$\endgroup\$
1
\$\begingroup\$

C 193 176 171

#define F x*x+y*y
x,y,a,b,d;main(){srand(time(0));x=rand();y=rand();while(scanf("%d %d",&a,&b),x-=a,x%=100,y-=b,y%=100,puts(F?F<d?"hotter":d?"cooler":"":"correct"),d=F);}

I'm sure there must be savings on the random number generation. Apart from that the key point is that reading in x & y is just treated as an offset from 0, so I only need one scanf. It does mean that I have to suppress printing hotter or cooler on the first iteration though.

Changes:

Put the location into x & y directly and then shift this back to (0,0) rather than put it in m & n and use x & y to search for it.

I realised that I was printing "hotter" and "correct" so I had to add an extra three characters here.

Rewritten the printing to put all conditions in it, saving an extra call to puts().

\$\endgroup\$
1
\$\begingroup\$

JavaScript ES6, Latest Firefox, 177 173 164 characters

Obviously, this cannot beat the APL one. That language is crazy! Maybe developed solely for code-golf questions :D :P

But here goes my solution in ES6 JavaScript. Run it in latest Firefox Nightly (or may be release version too) in the Web Console or Scratchpad.

A=a=>a*a;a=alert;g=v=>[x,y]=prompt().split(" ");r=v=>Math.random()*100|0;n=r(m=r(d=0));D=v=>A(n-x)+A(m-y);while(d=D(g(l=d)))l&&a(l<d?"hotter":"cooler");a("correct")

I'd like to skip the ungolfed version for now. Comment if you want to see the ungolfed version :)

EDIT : Golfed a lot! reduced 9 characters. Still seeing if further scope of golfing.

\$\endgroup\$
0
\$\begingroup\$

Python 226

from random import randint as r
x=r(0,100)
y=r(0,100)
l=9**9
while True:
    i,j=map(int,raw_input().split())
    if x==i and y==j:
        print 'correct'
        break
    c=(x-i)**2+(y-j)**2
    if c<l:print 'warmer'
    elif c>l:print 'colder'
    l=c

That import looks really long and stupid, but it actually saves me 8 chars. :D

Example game:

50 50
warmer
50 75
colder
50 25
warmer
50 13
colder
50 37
colder
50 20
warmer
50 21
warmer
50 22
warmer
50 23
warmer
50 24
warmer
50 26
colder
50 25
warmer
25 25
colder
75 25
warmer
74 25
warmer
62 25
warmer
61 25
warmer
55 25
colder
56 25
warmer
57 25
warmer
58 25
warmer
59 25
warmer
60 25
warmer
61 25
warmer
62 25
colder
61 25
warmer
61 24
correct
\$\endgroup\$
1
0
\$\begingroup\$

Sinclair /ZX Spectrum BASIC - 305 bytes

10 RANDOMIZE:LET o=99:LET a=INT(RND*99)+1:LET b=INT(RND*99)+1:PRINT a,b
20 INPUT "sx,sy:";c,d
30 LET g=SQR(ABS(a-c)^2+ABS(b-d)^2)
40 PRINT g'c,d
60 IF g=0 THEN PRINT "Found!":STOP
70 INPUT "mx,my:";x,y:LET c=c+x:let d=d+y
80 PRINT ("hotter" AND g<o)+("colder" AND g>o)
90 LET o=g:GOTO 30

As the Spectrum stores each keyword as one byte, it helps keep the size down. After it's been entered, found out the size with

print "bytes:";peek 23641+256*peek 23642-(peek 23635+256*peek 23636)+1
\$\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.