text:
Not Quite Roman Ternary
Given an integer n ≥ 0 , output it in a non-positional base-3 notation, using digits 139ABCDE… and a 1-character separator. Every digit is a consecutive power of 3 and the digits on the left side of the separator are negated, e.g.     A931|B   →    81−(1+3+9+27)   →    41. A digit may appear only once.
Rigorously, let the value of a digit be:

its value if the digit is 1, 3 or 9
27 if the digit is A
3 times the value of the digit right before it for B..Z

Your output should satisfy sum(value of digits to the right of |) - sum(value of digits to the left of |) == input .
Examples
input     output
----------------
0         |
1         |1
7         3|91
730       |D1
9999      FEDC|GA9

You may use a different non-space character as a separator. You are also allowed to have no separator, in which case the largest digit starts the positive sequence. You don’t need to handle anything larger than 232−1 (PMIGDCBA9|RQNLH3).
You may write a full program or function, and input and output may be provided on any of the usual channels.
This is code-golf, so the shorter your answer the better!

Related

Also related.

Balanced ternary is a positional notation.

@FrownyFrog just de-position it and you get roman ternary

(related doesn't mean duplicate, calm down)

Am I the only one who has no clue what's being asked here?

@Shaggy Express the input as a sum of powers of 3 and their negatives. Put the negatives left of a | and the positives to the right of it.

Do the digits need to be sorted from largest to smallest?

Thanks, @MartinEnder; that explains the 0, 1 & 7 test cases but I still don't see where/how the letters come into play.

Maybe some additional information on non-positional base-3 notation would be helpful here

@Shaggy 1 is 1, 3 is 3, 9 is 9, A is 27, B is 81, C is 243, ...

@Shaggy They're just used for "digits" which can't be represented by a single decimal digit. A = 27, B = 81, etc.

@MartinEnder no, the order is free.

Is the order strict (as in does it matter if we output CDEF|9AG, CDEF|GA9, FEDC|9AG, or FEDC|GA9)? If it is, all three current answers are invalid..

You are also allowed to have no separator, in which case the largest digit starts the positive sequence. What? So, if we don't use a separator, the output is to be computed differently so as for the largest digit to be the one which starts the positive sequence?

@EriktheOutgolfer Because the order is not important...

@KevinCruijssen "no, the order is free." -- OP

@user202729 Ah, missed that comment. Thanks. That's what happens when rules are in the comments instead of edited into the challenge.. (FrownyFrog, could you add that rule to the challenge: either order on either side of the delimiter is fine?)

@KevinCruijssen Isn't that inferrable from the rules?

@EriktheOutgolfer If you don't use a separator, the largest digit in the right sequence has to go first. The largest digit in the right sequence is guaranteed to be the largest overall, because the input is positive.

@FrownyFrog Well, it kind of makes the order matter then, but I guess it's not really avoidable, given no separator..

Is it also OK to have (positive digits, no separator, negative digits) and the largest digit ends the positive sequence? Is space between digits OK?

@nwellnhof no, lets keep it vaguely Roman and entirely space-free

FYI instead of posting "X_____________________X" in the sandbox when deleting, just paste in the URL of your main post (I already fixed it).

Clarification please: What is the largest value that we need to be able to convert? 0x7fffffff (signed 32 bit int), 0xffffffff (unsigned 32 bit int), or 0x100000000 (some 64 bit type, most likely)? The last option is what your wording requires currently, but I'm positive that you meant one of the other two possibilities.

@cmaster I wasn’t sure what the options even were, thanks for spelling them out. It’s the second one.

Order matter should go main for some comment folded

Why did you accept my Java answer? :S It's definitely not the shortest. ;) The 26-bytes Jelly answer is.

@KevinCruijssen 9 edits worth of effort

@FrownyFrog Usually it's best practice to accept the shortest answer in code-golf challenges. I still really appreciate the gesture, though. Thanks. :)

Java 10, 120 113 112 109 107 102 92 bytes
n->{var r="|";for(var c='1';n++>0;c+=c>64?1:c*4%22%9,n/=3)r=n%3<1?c+r:n%3>1?r+c:r;return r;}

-3 bytes by using part of the trick of @Arnauld's JavaScript (ES6) answer,
changing i=0 and i++<1?49:i<3?51:i<4?57:i+61 to i=4 and ++i>9?i+55:i>8?57:++i+43.
-6 bytes thanks to @Arnauld directly, by getting rid of i.
-10 bytes thanks to @ceilingcat.
Order of output: Highest-to-lowest, |-delimiter, lowest-to-highest.
Explanation:
Try it online.
n->{              // Method with integer parameter and String return-type
  var r="|";      //  Result-String, starting at the delimiter "|"
  for(var c='1';  //  Character, starting at '1'
      n++>0       //  Loop as long as `n` is larger than 0
                  //  Increasing it by 1 with `n++` at the start of every iteration
      ;           //    After every iteration:
       c+=        //     Change character `c` to:
          c>64?   //      If the current `c` is an uppercase letter:
               1  //       Simply go to the next letter using `c+=1`
              :   //      Else:
               c*4%22%9,
                  //       Change '1' to '3', '3' to '9', or '9' to 'A'
       n/=3)      //     Integer-divide `n` by 3
     r=           //   Change the result to:
       n%3<1?     //    If `n` modulo-3 is 0:
        c+r       //     Prepend the character to the result
       :n%3>1?    //    Else-if `n` modulo-3 is 2:
        r+c       //     Append the character to the result
       :          //    Else (`n` modulo-3 is 1):
        r;        //     Leave `r` unchanged
   return r;}     //  Return the result-String

I think this works: 103 bytes

@Arnauld Nice one! And -1 more byte by putting r in the loop body. Thanks!

@Arnauld Out of curiosity, what does the brute-forcers look like you've used for these last two magic numbers (when you still used i, and when you re-use c)?

I've already thrown it away ... :-/ But here is the last one. (Very inefficient, but that's OK for such small values.)

(Also, I really should test whether p=1 and don't include *1 in the code if it is -- even though it doesn't lead to a better formula in that case.)

@Arnauld Ah, that's more basic than I was expecting, thanks for sharing though. I guess it can quickly become more complex when more values are being asked, and where you end up needing more modulos, bitwise operations, base-conversions and/or standard arithmetic operations. Is there any general rule of thumb you can give as a tip to determine what is best to try next? For example, if your linked code wouldn't have given a result, would you add a third modulo? Just trying to understand it a bit more so I can hopefully do something myself with future challenges. :) (Thanks for your time, btw)

I rely more on intuition than on rigorous maths to find a correct formula, so it's quite hard to write a tip. A multiply followed by one or several modulos works reasonably well most of the time, especially when combined with a lookup table. Here, we want to find the correct value directly, so it could indeed become more complex very quickly. Maybe someday I'll try again to work on a more clever and more generic brute-forcer that starts with quick and easy formulae and gradually increases the complexity.

Python 3, 103 99 91 bytes
4 bytes thanks to Lynn.
8 bytes thanks to ovs.
def f(n,s="|",b=0):c=('139'+chr(b+62)*b)[b];return n and f(-~n//3,[s,s+c,c+s][n%3],b+1)or s

Try it online!
Credits to xnor for the logic.

JavaScript (ES6), 82 80 79 bytes
Outputs in lowercase, which should hopefully be fine.
f=(n,s=(k=4,'|'),c=++k>8?k.toString(36):++k-5)=>n?f(++n/3|0,[c+s,s,s+c][n%3]):s

Try it online!
Similar to Leaky "Ninja Master" Nun's answer and also based on xnor's answer.
Digit conversion
We start with k = 4. While k is less than 9, we increment it twice at each iteration and subtract 5. After that, we increment it only once and convert it to base-36.
  k  | ++k > 8       | k.toString(36) | ++k - 5  | result
-----+---------------+----------------+----------+--------
  4  | k=5  -> false |                | k=6 -> 1 | 1
  6  | k=7  -> false |                | k=8 -> 3 | 3
  8  | k=9  -> true  | '9'            |          | '9'
  9  | k=10 -> true  | 'a'            |          | 'a'
  10 | k=11 -> true  | 'b'            |          | 'b'
 ... | ...           | ...            | ...      | ...

Jelly, 26 bytes
‘:3Ɗ⁹Ð¡‘%3ẹÐ€0,2ị139D;ØA¤Y

Try it online!
Use a newline as the separator.

26 bytes

25 bytes

J, 69 64  58 bytes
('931',~u:90-i.26){~0(>,&I.<)(29$3)((+1&|.-3&*)]-*)^:_@#:]

Try it online!

Perl 6, 80 bytes
{map({|(1,3,9,|('A'..'Z'))[grep :k,*%3==$^v,($_,-+^*div 3...0)]},1,2).join.flip}

Try it online!
No separator. Based on xnor's answer.

Stax, 30 29 bytes
£└≤☻╘pÿ╖╡A[ô%æτ⌐}►ºôßHl4⌡π%^

Run and debug it
Port of my Stax answer in Balanced Ternary Converter.
Explanation
Uses the unpacked version to explain.
139$VA+cz{;3%+,^3/~;wY1|I@'|ay2|I@L
139$VA+c                               "139AB...Z", make a copy
        z                              Empty array to store the digits
          {         w                  Do the following until 0.
           ;3%+                           Append `b%3` to the digits
                                          Originally, `b` is the input
              ,^3/                        `b=(b+1)/3`
                  ~;                       Make a copy of `b` which is used as the condition for the loop

                     Y                 Save array of digits in `y` for later use
                      1|I              Find index of 1's
                         @             Find the characters in "139AB...Z" corresponding to those indices
                          '|           A bar
                            ay2|I@     Do the same for 2's
                                  L    Join the two strings and the bar and implicit output

Charcoal, 36 bytes
ＮθＦ³⊞υ⟦⟧Ｆ⁺139α«⊞§υθι≔÷⊕θ³θ»Ｆ²«×|ι↑⊟υ

Try it online! Link is to verbose version of code. Explanation:
Ｎθ

Input the value.
Ｆ³⊞υ⟦⟧

Push three empty lists to the predefined empty list.
Ｆ⁺139α«

Loop through the characters 139 and the uppercase alphabet.
⊞§υθι

Cyclically index the list of lists with the value and push the current character to it.
≔÷⊕θ³θ»

Divide the value by 3 but round it by adding 1 first.
Ｆ²«×|ι

Loop twice. The second time, print a |.
↑⊟υ

Each loop we pop the last entry from the list; the first time this gives us the entries that had a remainder of 2 (which corresponds to a balanced ternary digit of -1), while the second time this gives us the entries corresponding to a balanced ternary digit of 1. The resulting array would normally print vertically, but rotating the print direction upwards cancels that out.

J, 129 bytes
f=:3 :0
a=.'139',u:65+i.26
s=.'|'while.y>0 do.if.1=c=.3|y do.s=.s,{.a end.y=.<.y%3
if.c=2 do.s=.s,~{.a
y=.1+y end.a=.}.a end.s
)

Try it online!
Too lengthy, especially for a J program...
Explanation:
f =: 3 : 0
   a =. '139',u:65+i.26   NB. a list '139ABC...Z'
   s =. '|'               NB. initialize the list for the result
   while. y>0 do.         NB. while the number is greater than 0
      c =. 3|y            NB. find the remainder (the number modulo 3)
      y =. <.y%3          NB. divide the number by 3
      if. c = 1 do.       NB. if the remainder equals 1
         s =. s,{.a       NB. Append the current power of 3 to the result
      end.
      if. c = 2 do.       NB. if the remainder equals 2
         s =. s,~{.a      NB. prepends the result with the current power of 3
         y =. 1+y         NB. and increase the number with 1
      end.
      a =. }.a            NB. next power of 3
   end.
   s                      NB. return the result
)

C, int: 138 123 bytes, long: 152 131 bytes
I have created two versions of this, as the challenges' limit of a working max input of 0x100000000 seemed a bit odd. One version works with 32 bit integers (which fails the limit for obvious reasons), the other version works with 64 bits (which goes way beyond the given limit, at the cost of 14 8 extra bytes).
32 bit version:
char b[22],*r=b;f(v,l)char*l;{v%3>1?*r++=*l,v++:0;v&&f(v/3,l+1);v%3?*r++=*l:0;}g(v){f(v,"139ABCDEFGHIJKLMNOPQR");*r=0;r=b;}

64 bit version:
char b[22],*r=b;f(long v,char*l){v%3>1?*r++=*l,v++:0;v&&f(v/3,l+1);v%3?*r++=*l:0;}g(long v){f(v,"139ABCDEFGHIJKLMNOPQR");*r=0;r=b;}

This is identical except that it declares the integer variable to be long (which is 64 bits on linux).
The ungolfed long version:
char buffer[22],*result=buffer;
f(long value,char*letter){
    if(value%3>1){
        *result++=*letter,value++;
    }
    if(value){
        f(value/3,letter+1);
    }
    if(value%3){
        *result++=*letter;
    }
}
g(long value){
    f(value,"139ABCDEFGHIJKLMNOPQR");
    *result=0;
    result=buffer;
}

As you can see, this works by recursive decent: If the remainder is 1, the respective character is appended to the output string after the recursive call. If the remainder is 2, the output is performed before the recursing. In this case, I also increment the value by one to handle the negative digit correctly. This has the added benefit of changing the remainder to zero, allowing me to use value%3 as the condition for the post-recursion if.
The result of the conversion is placed into the global buffer. The g() wrapper has the job of zero terminating the resulting string correctly, and to reset the result pointer to its start (which is also how g() "returns" the result).
Test the long version with this code:
#include <stdio.h>

char b[22],*r=b;f(long v,char*l){v%3>1?*r++=*l,v++:0;v&&f(v/3,l+1);v%3?*r++=*l:0;}g(long v){f(v,"139ABCDEFGHIJKLMNOPQR");*r=0;r=b;}

void printConversion(long value) {
    g(value);
    printf("%ld: %s\n", value, r);
}

int main() {
    for(long i = 0; i <= 40; i++) {
        printConversion(i);
    }
    printConversion(0x7fffffff);
    printConversion(0xffffffffu);
    printConversion(0x100000000);
}

Possible further, but destructive golfing:

-4 bytes: make the function a one-shot by removing the pointer reset in g().

-5 bytes: force the caller to perform the string termination, returning the string without termination in buffer, and the end of the string in result.

Ruby, 87 84 82 bytes
Saved 2 bytes thanks to @benj2240.
->n,s=[?1,?3,?9,*?A..?Z],r=[""]*3{r[-m=n%3]+=s.shift
n=n/3+m/2
n>0?redo:r[1,2]*?|}

Try it online!

I'd be lying if I said I'm completely following this code, but I do know you shave off 2 bytes with the redo trick: Try it online!

C# .NET, 103 100 bytes
n=>{var r="|";for(var c='1';n++>0;c+=(char)(c>64?1:c*4%22%9),n/=3)r=n%3<1?c+r:n%3>1?r+c:r;return r;}

-3 bytes thanks to @ceilingcat.
Port of my Java 10 answer. If a direct port (except for n-> to n=>) would have been possible, I would have edited my Java answer with this polyglot. Unfortunately however, having c=49 isn't possible in C#, nor the c+= without (char) cast, hence this loose ported answer.
Try it online.

Perl 5 -p, 71 69 bytes
uses no separator. The negative and positive parts are in "roman order" (largest digit first)
#!/usr/bin/perl -p
$n=$_}{s/@{[$n++%3]}\K/]/,$n/=3,y/?-]/>-]/for($_=21)x31;y/>?@12/139/d

Try it online!

Perl 5, 92 89 bytes
Inspired by the java and python answers.
sub n{($n,$r,$c,@a)=(@_,'|',1,3,9,'A'..'Z');$n?n(int++$n/3,($c.$r,$r,$r.$c)[$n%3],@a):$r}

Try it online!
With some white space:
sub n {
  ($n, $r, $c, @_) = (@_, "|", 1, 3, 9, 'A' .. 'Z');
  $n ? n( int++$n/3, ($c.$r, $r, $r.$c)[$n%3], @_)
     : $r
}

PHP, 73 bytes
for(;0|$n=&$argn;$n/=3)${$n++%3}.=_139[++$i]?:chr(61+$i);echo${2},_,${1};

port of xnor´s answer, 53 bytes
for(;0|$n=&$argn;$n/=3)$s="0+-"[$n++%3].$s;echo$s??0;

Run as pipe with -nr or try them online.


text:
The Great API Easter Egg Hunt!
API Easter egg hunt!
There's an API at http://easter_egg_hunt.andrewfaraday.com which will provide a special Easter egg hunt, just for you...
You can see the API docs at the above address, or try it from here.
The API:
All calls to this API are GET requests, which will return a JSON string.
These examples are in a 5x5 garden, for illustration only.
The API will actually operate on a 100x100 garden (from indexes 1 to 100)
/new_game

Internally, the API produces a garden, and hides an egg in it.
In this example the egg is at 4, 4
+----------+
|          |
|          |
|          |
|          |
|   E      |
|          |
|          |
|          |
|          |
|          |
+----------+

Call
/new_game

Returns
{game_id: 'abcde'}

/guess/:game_id/:x/:y

The API looks in the garden and tells you how close you are.
If you guess 2 across and 8 down, the garden looks like this
+----------+
|          |
|          |
|          |
|          |
|   E      |
|          |
|          |
| g        |
|          |
|          |
+----------+

Call
/guess/abcde/2/8

Returns
{x: 'higher', y: 'lower'}

This means:
* Your x is too low (the egg position is higher)
* Your y is too high (The egg position is lower)
Correct call:
/guess/abcde/4/4

Returns
{x: 'right', y: 'right', turns: 10}

The Rules
Write a program to find the Easter egg with an API.

Use any language.
Try to write concise, but readable code.
Your program MUST call '/new_game' every time, and use the game_id returned in all 'guess' calls. No peeking at the garden!
Try to consistently finish the game with the smallest number of calls possible.
This is not code golf.

Competetive answer?
To be in with a chance of winning here's what we need to know:

What code are you using (In your answer, or a github link if it's bigger than you like to put in an answer).
Run your code 10 times, and record the game_id and score each time.

-game_id-: -score-
e.g.
abbbbbbb: 10
abbbbbdd: 5
(Note: The game_ids are required to verify a result)
The score will be calculated thus:

The highest and lowest two results will be ignored.
The remaining 6 scores will be added together.
This is your score.
Lowest score wins.

Addendum
Tl,dr: The app is a little shoddy.
The API was written in the space of about 90 minutes, and is deployed on a Raspberry Pi 2. Please be gentle with my API server. If you DDOS this poor thing you could spoil it for everyone.
Also, it's implemented with NOIP to simulate a static IP address, but sometimes this will drop out for a little while. That's what I get for using for zero-budget web hosting.
Just for giggles, here's a simple statistical analysis of games played... http://easter_egg_hunt.andrewfaraday.com/stats

Comments are not for extended discussion; this conversation has been moved to chat.

APL+WIN
Works by starting in the centre and converges on the location by setting the upper or lower limit to the last value and adding or subtracting half the difference to the appropriate limit to the last guess on each iteration.
API
id←¯20↑¯2↓GetUrl 'http://easter_egg_hunt.andrewfaraday.com/new_game'
xh←yh←100 ⋄ xl←yl←0 ⋄ x←50 ⋄ y←50 ⋄ c←0
:repeat
    xy←GetUrl 'http://easter_egg_hunt.andrewfaraday.com/guess/',id,'/',(⍕x),'/',⍕y
    xy←(('higher'⍷xy)+(¯1×'lower'⍷xy)+2×'right'⍷xy)~0
    :if xy[1]=1 ⋄ xl←x ⋄ x←x+⌈(xh-x)÷2 ⋄ :endif
    :if xy[1]=¯1 ⋄ xh←x ⋄ x←x-⌈(x-xl)÷2 ⋄ :endif
    :if xy[2]=1 ⋄ yl←y ⋄ y←y+⌈(yh-y)÷2 ⋄ :endif
    :if xy[2]=¯1 ⋄ yh←y ⋄ y←y-⌈(y-yl)÷2 ⋄ :endif
    c←c+1
:until 4=+/2↑xy
'id:',id,' x:',(⍕x),' y:',(⍕y),' count:',⍕c

This function uses the following function to do the API calls:
r←GetUrl url
⎕wself←'HTTP' ⎕wi 'Create' 'MSXML2.ServerXMLHTTP'
⎕wi 'XOpen' 'GET' url 0
⎕wi 'XSend'
r←⎕wi 'xresponseText'

The results for 10 trys were:
id:rbgprkxrqzzhwdfsbszn x:36 y:52 count:7
id:nmpcxdqsdzhgrbtlcpbp x:35 y:49 count:6
id:qqnsbpwnlbptxxblywnz x:99 y:22 count:6
id:nsytnvcgnsyrgzvjcysc x:45 y:28 count:6
id:yfkpfhphjpqxtqnwpmhv x:95 y:40 count:7
id:kxhszzrhxqlnvwvwjgnm x:49 y:6 count:6
id:rwnwfgdpzcjpzzfmgcfn x:93 y:34 count:7
id:tcvhtpqlfrwngybsyzqh x:95 y:94 count:6
id:pmlmqnprwcjggjfhttmy x:20 y:41 count:6
id:kpsmmhfhxxrrlvbbgzkv x:9 y:28 count:5

Haskell, Total Score 66 40
(Edit: Missed the part about dropping highest and lowest results in scoring)
I'm just using binary search. Not sure if there's a way to get better than 6.5 per try on average without cheating (I suppose I could just keep running sets of 10 until I get a better score, but where's the fun in that?).
Ah, by the way very fun challenge. The idea is simple enough to be inclusive of everyone, and I don't usually deal with web APIs in my day job and I was just itching for an excuse to try out servant, so thanks for that :) Probably not so great if you're hoping for competition, but I think challenges like this could be used to gather code samples for beginners and things like that.
Executable script (runs one game and reports the gameId and score):
#!/usr/bin/env stack
{- stack
   --resolver lts-11.2
   script
   --package servant
   --package servant-client
   --package http-client
   --package aeson
   --package text
-}

-- the above comments allow this to be run as a script if haskell-stack is installed.
-- Actual source starts here.
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}

module Main where

import Data.Aeson
import Servant.API
import Servant.Client
import qualified Network.HTTP.Client as HttpClient
import Data.Proxy
import Data.Text(Text)
import Text.Printf
import System.IO(stderr)

newtype GameID = GameID Text deriving (PrintfArg, ToHttpApiData)

instance FromJSON GameID where
  parseJSON = withObject "GameID" $ \o ->
    fmap GameID (o .: "game_id")

data Accuracy = Lower | Higher | Correct

readAccuracy :: Text -> Accuracy
readAccuracy t
  | t == "lower" = Lower
  | t == "higher" = Higher
  | t == "right" = Correct
  | otherwise = error $ printf "Unexpected accuracy text: \"%s\"" t

data GuessResult = GuessResult { xAccuracy :: Accuracy, yAccuracy :: Accuracy, turnCount :: Maybe Int }

instance FromJSON GuessResult where
  parseJSON = withObject "GuessResult" $ \o ->
    GuessResult
      <$> fmap readAccuracy (o .: "x")
      <*> fmap readAccuracy (o .: "y")
      <*> o .:? "turns"

type EggAPI =    "new_game" :> Get '[JSON] GameID
            :<|> "guess"
              :> Capture "game_id" GameID
              :> Capture "x" Int
              :> Capture "y" Int
              :> Get '[JSON] GuessResult

getNewGame :: ClientM GameID
makeGuess :: GameID -> Int -> Int -> ClientM GuessResult
getNewGame :<|> makeGuess = client (Proxy :: Proxy EggAPI)

data CoordinateRange = CoordinateRange { lowerBound :: Int, higherBound :: Int }

middleOfRange :: CoordinateRange -> Int
middleOfRange rng = lowerBound rng + (higherBound rng - lowerBound rng) `div` 2

adjustCoordinateRange :: Accuracy -> CoordinateRange -> CoordinateRange
adjustCoordinateRange Lower rng = CoordinateRange (lowerBound rng) (middleOfRange rng)
adjustCoordinateRange Higher rng = CoordinateRange (middleOfRange rng) (higherBound rng)
adjustCoordinateRange Correct rng = rng

searchForEggs :: ClientM (GameID, Int)
searchForEggs = do
  game <- getNewGame
  let initialRange = CoordinateRange 1 100
  score <- loop game initialRange initialRange
  return (game, score) where
    loop gId xRange yRange = do
      guessResult <- makeGuess gId (middleOfRange xRange) (middleOfRange yRange)
      let newXRange = adjustCoordinateRange (xAccuracy guessResult) xRange
          newYRange = adjustCoordinateRange (yAccuracy guessResult) yRange
      maybe (loop gId newXRange newYRange) return $ turnCount guessResult

main :: IO ()
main = do
  manager' <- HttpClient.newManager HttpClient.defaultManagerSettings
  let clientEnv = mkClientEnv manager' (BaseUrl Http "easter_egg_hunt.andrewfaraday.com" 80 "")
  result <- runClientM searchForEggs clientEnv
  case result of
    Left err -> hPrintf stderr  "Error: %s\n" (show err)
    Right (game, score) -> printf "GameID: %s | Score: %d\n" game score

Results
GameID               |  Score
---------------------+-------
fdcbwwxkvhkfskqlpgnh |  7
cdgjnksfnrhgjjsdbnhd |  7
lbjjqgkvfzzprnrxcpsx |  6
rtbngkdlwdfmhdyggnjd |  6
rcphvxzzgblfnzxdqlyh |  6
gyfjbjmplkrfnqjptygl |  7
bkdnbqhsbhwwvgtcfhjb |  6
knjdxdmvttwgltjdpvtv |  7
zqpstnhjgsykkwxnxcbv |  7
rccpmsbfxqvsmzxckhcs |  7

JavaScript, 35 points
Posting ungolfed code does not sit well with me! :D
(async _=>{
    url=`https://crossorigin.me/http://easter_egg_hunt.andrewfaraday.com/`
    promise=await fetch(url+`new_game`)
    json=await promise.json()
    id=json.game_id
    max={x:100,y:100}
    min={x:0,y:0}
    (guess=async (x,y)=>{
        promise=await fetch(url+`guess/${id}/${x|=0}/${y|=0}`)
        json=await promise.json()
        turns=json.turns
        if(turns)
            console.log(`{game:"${id}",turns:${turns},x:${x},y:${y}}`)
        else{
            switch(json.x){
                case`higher`:
                    min.x=x
                    x+=max.x
                    x/=2
                    break
                case`lower`:
                    max.x=x
                    x+=min.x
                    x/=2
            }
            switch(json.y){
                case`higher`:
                    min.y=y
                    y+=max.y
                    y/=2
                    break
                case`lower`:
                    max.y=y
                    y+=min.y
                    y/=2
            }
            guess(x,y)
        }
    })(50,50)
})()

Scoring: 5+6+6+6+6+6=35
Got very lucky, pulling that score of 3 on my last test before posting!
{game:"bjzkjzxwmksmbsbxtdzp",turns:3,x:75,y:12}
{game:"bvmhssnmzhlnykgxdkww",turns:5,x:93,y:71}
{game:"mcydbttxhcxwqymksgbg",turns:5,x:71,y:37}
{game:"xdynxrkxgsyltsfrqzll",turns:6,x:54,y:88}
{game:"wjdkclsqksnvdnwbspxq",turns:6,x:90,y:13}
{game:"mgvlssfgjcgtylwqpvhq",turns:6,x:26,y:68}
{game:"rgjvbkrlzqvpdfphqxtq",turns:6,x:19,y:81}
{game:"hgrscvfzgrkzzjvkjjwb",turns:6,x:41,y:19}
{game:"lrfrblmmkggghntshnkj",turns:7,x:86,y:32}
{game:"ldsndvjsbvgvbhbtfckp",turns:7,x:24,y:7}

Try it
Using a somewhat golfed version of the code above!

(async url=>(
    json=await(await fetch(url+`new_game`)).json(),
    id=json.game_id,
    max={x:100,y:100},
    min={x:0,y:0},
    (g=async x=>(
        json=await(await fetch(url+`guess/${id}/${x|=0}/${y|=0}`)).json(),
        x+=json.x==`higher`?(min.x=x,max.x):json.x==`lower`?(max.x=x,min.x):x,x/=2,
        y+=json.y==`higher`?(min.y=y,max.y):json.y==`lower`?(max.y=y,min.y):y,y/=2,
        json.turns?console.log(`{game:"${id}",turns:${json.turns},x:${x},y:${y}}`):g(x)
    ))(y=50)
))`https://crossorigin.me/http://easter_egg_hunt.andrewfaraday.com/`

This isn't actually code golf, you can expand a bit for clarity if you want to lol

@Cubic, you're right, I probably should! :D I find it incredibly difficult not to crunch bytes 'round here, even when it's not [tag:code-golf]!

Ruby (+JSON, HTTParty) - Score: 40 (6+7+7+7+7+6)
This was a fun challenge. I used binary search to find the egg and got these results:
[{:x=>34, :y=>17, :game_id=>"mgpbmdqbnklcqrdjpyrr", :count=>7},
 {:x=>99, :y=>17, :game_id=>"mhrsqfzmrrlcqxtcfgnw", :count=>7},
 {:x=>23, :y=>86, :game_id=>"zgmsrjpqvdtmqmmglstn", :count=>6},
 {:x=>24, :y=>55, :game_id=>"vkpjffyyltplztwhdsft", :count=>7},
 {:x=>12, :y=>94, :game_id=>"pxrzjvqfjrjsptvtvnfw", :count=>4},
 {:x=>83, :y=>59, :game_id=>"bdxljxkcnqmsqgnvggql", :count=>7},
 {:x=>45, :y=>40, :game_id=>"mqrsbrhbldcqwgbnmymc", :count=>7},
 {:x=>13, :y=> 9, :game_id=>"bphxkdgfcyyrvwxnfvkx", :count=>6},
 {:x=> 8, :y=>80, :game_id=>"qzdstksdwnwrhxqrczpc", :count=>7},
 {:x=>56, :y=>92, :game_id=>"ypqkfvmvwrcvvmjccvxg", :count=>6}]

Here's the code:
require 'rspec/autorun'
require 'json'
require 'httparty'
require 'pp'

GuessResult = Struct.new :x, :y, :count

class FakeGame
  def initialize(x=random_num, y=random_num)
    @x = x
    @y = y
    @count = 0
  end

  @@results = [:right, :higher, :lower]

  def guess(x, y)
    @count += 1
    GuessResult.new(@@results[@x <=> x], @@results[@y <=> y], @count)
  end

  def id
    :fake
  end

  def random_num
    rand(100) + 1
  end
end

class RealGame
  def initialize
    response = HTTParty.get('http://easter_egg_hunt.andrewfaraday.com/new_game')
    j = JSON.parse(response.body)
    @id = j['game_id']
  end

  def guess(x, y)
    response = HTTParty.get("http://easter_egg_hunt.andrewfaraday.com/guess/#{id}/#{x}/#{y}")
    j = JSON.parse(response.body)
    x_result = j['x'].to_sym
    y_result = j['y'].to_sym
    count = (j['turns']||0).to_i
    GuessResult.new(x_result, y_result, count)
  end

  def id
    @id
  end
end

class BinarySearch
  def initialize(min, max)
    @min = min
    @max = max
    @guessed = false
    update_next_guess
  end

  attr_reader :next_guess, :guessed

  def go(result)
    return if @guessed
    case result
    when :right
      @guessed = true
    when :lower
      @max = @next_guess - 1
      update_next_guess
    when :higher
      @min = @next_guess + 1
      update_next_guess
    end
  end

  private

  def update_next_guess
    @next_guess = (@max + @min) / 2
  end

end

def play(game)
  x_search = BinarySearch.new(1, 100)
  y_search = BinarySearch.new(1, 100)

  until x_search.guessed && y_search.guessed
    puts ?.
    result = game.guess(x_search.next_guess, y_search.next_guess)
    x_search.go(result.x)
    y_search.go(result.y)
  end

  {
    x: x_search.next_guess,
    y: y_search.next_guess,
    game_id: game.id,
    count: result.count
  }
end

def game_controller(game_constructor, game_count)
  (1..game_count).map do |i|
    game = game_constructor.call
    puts "Starting game #{game.id}..."
    play(game)
  end
end

def main
  # pp game_controller(->{ FakeGame.new }, 10)
  pp game_controller(->{ RealGame.new }, 10)
end

main

# tests

describe :FakeGame do

  it "returns right results" do
    game = FakeGame.new 4, 4

    result = game.guess(2, 5)
    expect(result.x).to eql :higher
    expect(result.y).to eql :lower
    expect(result.count).to eql 1

    result = game.guess(5, 3)
    expect(result.x).to eql :lower
    expect(result.y).to eql :higher
    expect(result.count).to eql 2

    result = game.guess(4, 4)
    expect(result.x).to eql :right
    expect(result.y).to eql :right
    expect(result.count).to eql 3

  end

end

describe :binary_search do
  let(:search) { BinarySearch.new 1, 100 }

  it "makes optimal guesses" do
    # aiming for 34
    expect(search.next_guess).to eql 50
    expect(search.guessed).to be_falsey
    search.go(:lower)
    expect(search.next_guess).to eql 25
    search.go(:higher)
    expect(search.next_guess).to eql 37
    search.go(:lower)
    expect(search.next_guess).to eql 31
    search.go(:higher)
    expect(search.next_guess).to eql 34
    search.go(:right)
    expect(search.next_guess).to eql 34
    expect(search.guessed).to be_truthy
  end

end

describe :fake_game do

  it "correctly responds to guesses" do
    game = FakeGame.new(34, 77)
    result = play(game)
    expect(result.y).to eql :lower
    expect(result.count).to eql 1

    result = game.guess(5, 3)
    expect(result.x).to eql :lower
    expect(result.y).to eql :higher
    expect(result.count).to eql 2

    result = game.guess(4, 4)
    expect(result.x).to eql :right
    expect(result.y).to eql :right
    expect(result.count).to eql 3

  end

end

describe '#play' do

  it "guesses correctly" do
    game = FakeGame.new(34, 77)
    result = play(game)
    expect(result[:x]).to eql 34
    expect(result[:y]).to eql 77
    expect(result[:count]).to eql 7
    expect(result[:game_id]).to eql :fake
  end

end

Looks like I've messed up, here. http://easter_egg_hunt.andrewfaraday.com/stats states that only 12 games have been completed in the history of the app. I'm sure there was at least 6 completed yesterday. Although 160 is the longest. I'll have a look into it.

The issue appears to be in RealGame#guess, where you've hardcoded the game with game_id "bswtdwfdjypdtfyqxbyz". Replace this with #{@id} to get a more accurate result set.

Actually, I corrected that one line and your result set is pretty good. Rather consistently 6's and 7's. Nice work :D

@AJFaraday Oops. My bad! Thanks for fixing! And thanks for making this fun challenge!

You had me worried for a minute, there ;)

I was just playing around with this one, thought I'd try another algorithm ;) https://gist.github.com/AJFaraday/95539471cf0c8dd3060aae9d89552bf4

Python 3 (+requests), 39 points
http://easter_egg_hunt.andrewfaraday.com/guess/dbxqfgldhryxymljthkx/13/82
{"turns": 7, "url": "http://easter_egg_hunt.andrewfaraday.com/surprise", "x": "right", "y": "right"}
http://easter_egg_hunt.andrewfaraday.com/guess/kfmgrdqlyxfknbgycfwm/6/52
{"turns": 7, "url": "http://easter_egg_hunt.andrewfaraday.com/surprise", "x": "right", "y": "right"}
http://easter_egg_hunt.andrewfaraday.com/guess/gnykwddprlfwwkrybkmc/34/91
{"turns": 6, "url": "http://easter_egg_hunt.andrewfaraday.com/surprise", "x": "right", "y": "right"}
http://easter_egg_hunt.andrewfaraday.com/guess/xhwrqdgtdyrwrvdqqcpk/92/54
{"turns": 7, "url": "http://easter_egg_hunt.andrewfaraday.com/surprise", "x": "right", "y": "right"}
http://easter_egg_hunt.andrewfaraday.com/guess/hmbgrnxjfgqcxhbfkztm/44/48
{"turns": 7, "url": "http://easter_egg_hunt.andrewfaraday.com/surprise", "x": "right", "y": "right"}
http://easter_egg_hunt.andrewfaraday.com/guess/mhbchhbkppqqyxzqvrnb/62/38
{"turns": 7, "url": "http://easter_egg_hunt.andrewfaraday.com/surprise", "x": "right", "y": "right"}
http://easter_egg_hunt.andrewfaraday.com/guess/pbrkghynqybmkmctncmr/73/25
{"turns": 6, "url": "http://easter_egg_hunt.andrewfaraday.com/surprise", "x": "right", "y": "right"}
http://easter_egg_hunt.andrewfaraday.com/guess/sspxcsfblrnmhflgtggn/89/73
{"turns": 6, "url": "http://easter_egg_hunt.andrewfaraday.com/surprise", "x": "right", "y": "right"}
http://easter_egg_hunt.andrewfaraday.com/guess/rlvdstmpsthktzkqbynn/4/71
{"turns": 6, "url": "http://easter_egg_hunt.andrewfaraday.com/surprise", "x": "right", "y": "right"}
http://easter_egg_hunt.andrewfaraday.com/guess/wknwwcrdrmjsqxnqbvhm/50/67
{"turns": 6, "url": "http://easter_egg_hunt.andrewfaraday.com/surprise", "x": "right", "y": "right"}

Score 39 (7+7+7+6+6+6 - 7-7-6-6)
Source:
import requests
import json
url='http://easter_egg_hunt.andrewfaraday.com/guess/{id}/{x}/{y}'
start='http://easter_egg_hunt.andrewfaraday.com/new_game'
gid = requests.get(start).json()['game_id']
x=y=50
step=25
lx=lr=''
def get_new(old,value):
        if value == 'higher':
                return old+step
        elif value == 'lower':
                return old-step
        else:#right
                return old
while True:
        res = requests.get(url.format(id=gid,x=x,y=y)).json()
        if res['x'] == 'right' and res['y'] == 'right':
                print(url.format(id=gid,x=x,y=y))
                print(json.dumps(res, sort_keys=True))
                break
        x=get_new(x,res['x'])
        y=get_new(y,res['y'])
        step=step // 2 or 1

Just noticed there is no gameid in the result, I will rerun it and add the game id's in a bit

You've also over-scored yourself. We're discounting the highest two and the lowest two results. Leaving only 6 to sum... You could always put the score in the title, too.

Oh I misread, I thought only to remove the first and last one. I will modify it then :)

PHP
<?php

error_reporting(E_ALL);

$url = 'http://easter_egg_hunt.andrewfaraday.com';
extract(json_decode(file_get_contents("$url/new_game"), true));

$i = $j = 51;
$step = 50;
$right = false;

while(!$right) {
  extract(json_decode(file_get_contents(sprintf("$url/guess/$game_id/%d/%d", $i, $j)), true));
  $lower = -$higher = $step /= 2;
  $i += $$x;
  $j += $$y;
  $right = !($$x || $$y);
}

printf('{game_id: %s; x: %2d; y: %2d; turns: %d}', $game_id, $i, $j, $turns);

Using file_get_contents and json_decode.
As far as I can tell, an optimal strategy needs at most 7 moves, with an average of 5.8 moves on one axis, and an average of 6.4786 moves on two axes.

Sample of 10
{game_id: pfmyldcsltlbtmcfjtqr; x: 76; y: 51; turns: 6}
{game_id: jnmshsfvstcmksdcdrnj; x: 40; y:  5; turns: 7}
{game_id: wsrptrymycxjfxwvdvlh; x: 55; y: 35; turns: 7}
{game_id: fxpxtqwnxstwcxbsqtwc; x: 73; y: 93; turns: 6}
{game_id: zppntvjxnjpnlmpfzcfj; x: 71; y: 76; turns: 6}
{game_id: fzvlxqgrxcvtbbydgrpj; x: 48; y: 51; turns: 6}
{game_id: hqytpzjxkfhqhhwwfryd; x: 23; y: 87; turns: 6}
{game_id: ldsbfgcqbqpxgdhtkxsm; x: 90; y: 81; turns: 5}
{game_id: shypwsmjljyqdvwcwnxv; x: 19; y: 57; turns: 7}
{game_id: bsfrhhrvmpqfvyhjxcwh; x: 82; y: 85; turns: 6}

Score: 6 + 6 + 6 + 6 + 6 + 7 = 37

Golfed, 245 bytes
<?$e="extract(json_decode(file_get_contents('http://easter_egg_hunt.andrewfaraday.com";eval("$e/new_game".$f="'),1));");
for($i=$j=$h=50;!$url;$l=-$h/=2)eval("$e/guess/$game_id/".-~($i+=$$x[0]).'/'.-~($j+=$$y[0]).$f);
echo$game_id,~$i,~$j,-$turns;

Sample Output
$ php egg-hunt.php
hgzqmqyrznglsdwfwcft-9-86-7

Python 2
Golfed vesrion - 276 bytes
from requests import*
u='http://easter_egg_hunt.andrewfaraday.com'
i=get('%s/new_game'%u).json()['game_id']
x=y=50;s=25;o={}
while not'turns'in o:o=get('%s/guess/%s/%d/%d'%(u,i,x,y)).json();exec("%s+=s*'rh'.rfind(o['%s'][0]);"*2)%tuple('xxyy');s=s%2+s/2
print i,x,y,o['turns']

More readable version + comments
from requests import*
u='http://easter_egg_hunt.andrewfaraday.com'
i=get('%s/new_game'%u).json()['game_id'] # get game id
x=y=50    # initial central position
s=25      # step of binary search
o={}      # initialize o to further store returns
while not'turns'in o:    # cycle until 'turns' occurs in return
    o=get('%s/guess/%s/%d/%d'%(u,i,x,y)).json()
    exec("%s+=s*'rh'.rfind(o['%s'][0]);"*2)%tuple('xxyy');s=s%2+s/2
    # this exec is used to shorten two similar lines for x and y:
    #  x += s * (... o['x'] ...);
    #  s*'rh'.rfind(o['%s'][0]) - look at first letter of return and use its position in string 'rh' to map multipliers for step:
    #                             -1 for lower, +1 for higher and 0 for right
    #                             rfind() will return -1 for not finding l
    s=s%2+s/2    # divide step in two, rounding up
print i,x,y,o['turns']

Results
vjwqvbydwmbvbrhwrxqz 19 95 4
svkdvszghjzfbvqxsprt 5 12 4
dvbpnxjdgrydwffcndnt 81 67 6
qqwgsctqhdcrbywwrcxf 21 49 6
zrgqqtzjjrrsqbgvkbsm 37 12 6
trzjngljbwbwxycxpcbk 91 2 7
kysjwfzsrdjsybrchnzg 76 45 7
kcjtxqfmcgszrwkyhlkm 68 48 7
wykbjvthqmcyzscxnsxt 68 41 7
kldrfccjdphzqnqcmdgz 88 14 7

Summary
Somewhat expected :D
6+6+6+7+7+7 = 39

Golfers gonna golf ;)

Rust
As it happens, Rust has a really nice deserialization library called serde which helped a lot with this program. The algorithm itself is a rather straightforward binary search, except ran twice - once for x and once for y.
The URL macro has a specific case for no format strings because it can be done for pretty much free, and when not formatting the string would be stored in static storage.
Cargo.toml
[package]
name = "easter-egg-hunt"
version = "0.1.0"
authors = ["Konrad Borowski"]

[dependencies]
reqwest = "0.8.5"
serde = "1.0.36"
serde_derive = "1.0.36"

main.rs
extern crate reqwest;
extern crate serde;
#[macro_use]
extern crate serde_derive;

use reqwest::Client;

#[derive(Deserialize)]
struct NewGame {
    game_id: String,
}

#[derive(Deserialize)]
struct Guess {
    x: GuessStatus,
    y: GuessStatus,
    turns: Option<u32>,
}

#[derive(Deserialize)]
#[serde(rename_all = "lowercase")]
enum GuessStatus {
    Lower,
    Right,
    Higher,
}

macro_rules! url {
    ($path:expr) => {
        concat!("http://easter_egg_hunt.andrewfaraday.com", $path)
    };
    ($path:expr $(, $part:expr)*) => {
        &format!(url!($path) $(, $part)*)
    };
}

struct BinarySearch {
    low: u8,
    high: u8,
}

impl BinarySearch {
    fn new() -> Self {
        BinarySearch { low: 1, high: 100 }
    }

    fn current_guess(&self) -> u8 {
        (self.low + self.high) / 2
    }

    fn update(&mut self, guess_status: GuessStatus) {
        let current_guess = self.current_guess();
        match guess_status {
            GuessStatus::Lower => self.high = current_guess - 1,
            GuessStatus::Higher => self.low = current_guess + 1,
            GuessStatus::Right => {
                self.high = current_guess;
                self.low = current_guess;
            }
        }
    }
}

fn run_game(client: &Client) -> reqwest::Result<()> {
    let NewGame { game_id } = client.get(url!("/new_game")).send()?.json()?;
    let mut x_search = BinarySearch::new();
    let mut y_search = BinarySearch::new();
    loop {
        let x_guess = x_search.current_guess();
        let y_guess = y_search.current_guess();
        let response = client
            .get(url!("/guess/{}/{}/{}", game_id, x_guess, y_guess))
            .send()?
            .json()?;
        match response {
            Guess { x, y, turns: None } => {
                x_search.update(x);
                y_search.update(y);
            }
            Guess {
                turns: Some(turns), ..
            } => {
                println!("id:{} x:{} y:{} count:{}", game_id, x_guess, y_guess, turns);
                return Ok(());
            }
        }
    }
}

fn main() {
    let client = Client::new();
    for _ in 0..10 {
        run_game(&client).unwrap();
    }
}

Summary
id:tlxjnjtslnsnbdxyzlvn x:97 y:22 count:7
id:bbzpyhhflrdjzylwxtbr x:21 y:6 count:5
id:kcjdkfvddgxckmprxwtw x:81 y:99 count:6
id:tnzryxpkblqrqbqrqkby x:30 y:25 count:7
id:pbzkdrmjrvwmkgmlvwcb x:79 y:20 count:7
id:qxvcbcslkdmjxnffsxfb x:36 y:94 count:7
id:hqfgpdmktyfwqtbrvvly x:94 y:71 count:5
id:ytgsnssvlpnhzqzgvygw x:1 y:83 count:7
id:gjhglmkbhvswqwgrynft x:65 y:94 count:5
id:rzghpypysxtwkclgpbkx x:55 y:96 count:7

5 + 6 + 7 + 7 + 7 + 7 = 39

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/

sort: votes


text:
Console print a bar graph
The objective is to print a graph from an array of numbers, of the design below. Printing the X and Y scale exactly as in the "design", with padding, is part of the challenge. The input array of numbers can be of virtually any range of integers in X and Y, but not 0 and not negative - though I would suggest keeping it small considering this is ASCII art! (x < 15, y < 50 or so).
Specifics
1) the graph should print the Y scale on the left, padded to the max length of the input, and with a pipe '|' between the number and the first column.
2) the bar should have all empty spaces with periods '.' filled spaces with pipes '|' and the number itself should be an 'o'.
3) there are three "tween" columns between each number that interpolates between the two numbers. These cannot just be a duplication of the previous or next column, but need to interpolate between the values linearly. (Unless two adjacent numbers in the list are only 1 apart or the same.)
4) The bottom of the graph should look: "  +---------" to the length of the graph.
5) There should be an X scale padded to the length of the max number, similar to the Y scale. The last digit of the x scale should align with the value (I guess that means we're limited to two digits...)
6) Lastly, there should be an "empty" column in the beginning of the graph and an "empty" column at the end.
Example
This:
 [5, 3, 7, 8, 10, 7, 8, 7, 9, 2]

Generates:
10|.................o.....................
09|................||...............o.....
08|.............o|||||......o......||.....
07|.........o||||||||||.o|||||..o||||.....
06|........|||||||||||||||||||||||||||....
05|.o.....||||||||||||||||||||||||||||....
04|.||...|||||||||||||||||||||||||||||....
03|.|||.o||||||||||||||||||||||||||||||...
02|.|||||||||||||||||||||||||||||||||||.o.
01|.|||||||||||||||||||||||||||||||||||||.
  +---------------------------------------
   01  02  03  04  05  06  07  08  09  10

Trailing spaces on each line, or trailing newlines at the end are permitted. As long as the output is visually the same.
Here's a working Python3 example, in "long hand" if you wish:
Try it online!

I still don't understand how the graph ends up looking like this.  For example, why is the next to last vertical line shorter than the last one?  Or why is the one on either side of entry 2 shorter than the one for entry 2, given that entry 2 is a low point between entries 1 and 3?

@Xcali Ok I added some further clarification.

I'd strongly suggest posting this in the Sandbox. Your challenge is particularly complicated and needs a lot of care to be specified exactly. Ideally the reader would not need to infer rules from an example, or to read or run any code. As this is your first challenge,  I might also suggest to try writing and posting a simpler challenge first to get the hang of things, or to post some answers, then return to this. Unfortunately, a lot of community expectations of challenges aren't really written down, so a bit of experience helps a lot.

Created an python program in 553 bytes, I found this an interesting challenge. Since it is on hold, I will comment it https://tio.run/##bVLtboMgFP3PU/DHXFBo60ezzYUnYWZxUTu2gkZso82yV3dQ23VbFhK45@Tcw7mBbhpeW5POsxJ7ZQeiy44oMzBlusNA6Mp2ezUQYEApRVrociShosiKfW2IHXqiHd8ICIJNUFUQWLS7gavGn8obVEJKWEERXqgwiyxt2h4/Y2VwX5pdTXSU0AJ5cmSTp2tz0HVfDjWpaD7J3BaiCYjmI32cpAPwAaiSPClk7gCG0EbgF4fbNTymXhM7jY2SRUZcdWVd6ZolBDyzEJBdwD9His8hbskuYxSoqhvcE8MmNrITa2mOztKjl1ZScxMRwycantbrLIpzXeRHOfpZo3aJ@@90yvv49qm4qH3QFv6YT78dk8URqwaPQiwReZy/9HX5jrARSo5RXKDvvClL6Q0lLPuBYralqOvd@xN4MrB6a5U5/whYala5R5znLcMpw3cM3zMcb66V2x8YTr4A

@RickRongen Although a nice answer (and you can golf 4 bytes like this), it's actually slightly different: his graph has a line after the last o, but yours does not. And rule 3 (having three "tween" heights in between) is a bit vague. Can they all 3 be the same as the o column before or after it like in this pastebin, or do they need to have a flowing line? This was one of the reasons it's closed as unclear. It's probably better to have a single distinguished height-calculation of the "tweens" instead of "logic is up to you".

Having said that, I like the overall challenge, so I hope it will be clearer for everyone and people start to open-vote it. Welcome to PPCG! And as suggested, next time I would use the Sandbox to get feedback on your challenges. :)

If "the logic is up to you", which "logic" are valid? We need a objective validity criteria. Should we do linear interpolation?

Related: https://codegolf.stackexchange.com/questions/99412/plot-a-list-of-numbers

"(x > 15, y > 50 or so)" I think you mean < instead of >. :) A few more small questions, although it's already more clear than it was. The input list only cannot contain 0 or negative numbers, right? And I'm still unsure why there is a column column next to the last number (This column I mean.) Also, for the sentence "These cannot just be a duplication of the previous or next column, but need to interpolate between the values linearly." I would add something like unless two adjacent numbers in the list are only 1 apart (or the same).

@Spencer Looking much better now in my opinion. You've got my vote to re-open. Unfortunately you need 4 more votes, but I personally think the challenge is a lot better now. Maybe other people have different feedback than me to improve it further. For your next challenges I would use the Sandbox, but first challenges are always tough to get right. Hopefully it will be re-opened soon, because it seems like an interesting challenge.

One more points. If "the column values interpolate linearly", how can the column right before the "02" column be 2 units tall, while the "01" column is 5 units tall and "02" column is 3 units tall?

@RickRongen I've reopened it, so if you'd like to post that answer you can now.

Your "reference implementation" 1 only work if len(values) >= height and 2 the third column is always as tall as the column right after it, except for rounding issues. That's definitely not counted as "linear interpolation".

@DJMcMayhem But it's still unclear. The reference implementation is broken. :\

Considering that there are always 3 tween lines, x should not become larger than three digits. That would pretty much destroy the layout.

@Titus That is guaranteed.

Python 3, 505, 484, 480 bytes
i=list(map(int,input().split(',')))
l=len(i)
r=range
e=enumerate
m=max(*i)
s=len(str(m))
t='%%0%dd'
f=t%s
g=t%len(str(l))
d=[['.']*(l*4+s)for _ in r(m+2)]
for x,y in e(d):y[:s]=f%(m-x);y[s]='|'
d[-2][:]=' '*s+'+'+'-'*(l*4-1)
d[-1][:s+2]=' '*(s+2)
d[-1][s+1:]=['%-4s'%(g%-~x)for x in r(l)]
for x,y in e(i):
 n=y
 def r(z,o):
  for v in d[m-n+(n-y)*z//4+1:m]:v[x*4+s+o]='|'
 d[m-y][x*4+s+2]='o';r(0,2)
 if x==l-1:break
 n=i[x+1];r(3,3);r(2,4);r(1,5)
print('\n'.join(map(''.join,d)))

Try it online!
With some help of @kevin-cruijssen
-25 with some cleanup in newlines etc. by me
Could probably be compacted a bit more

You can save 3 bytes with list splat in parsing input, and another 3 bytes by removing a unnecessary list clone.

You can switch == by > and do some modifications to get a -1 byte.

PHP, 231 bytes
for($e=strlen($y=max($argv));$y>$x=0;$y-=print".
")for(printf("%{$e}d|.",$y);$n=$argv[++$x];print"o.|"[$y<=>$n])while($x>1&&++$k%4)echo".|"[$y<$p+=$n/4-$p/4];echo str_pad("  +",$argc*4-1,"-"),"
 ";while(++$x<$argc)printf("%4d",$x);

fixed width (y<100), 219 bytes
for($y=max($argv)+1;--$y>$x=0;print".
")for(printf("%2d|.",$y);$n=$argv[++$x];print"o.|"[$y<=>$n])while($x>1&&++$k%4)echo".|"[$y<$p+=$n/4-$p/4];echo str_pad("  +",$argc*4-1,"-"),"
 ";while(++$x<$argc)printf("%4d",$x);

requires PHP 7.1 for negative string indexing. Run with -nr or try them online.

Jelly, 68 bytes
J+ȷ2DḊ€
x4S4Ƥ:4;00;”|ẋ”o0¦€2¦4ÐƤẎz”.µÇ,"j€”|ṚY⁷⁶⁶”+³Çj⁾  ;©⁶”-ṁ⁷⁶⁶⁶®

Try it online!

JavaScript (Node.js), 316 bytes
a=>a.map((x,i)=>{d=Math.abs(x-~-(n=a[i+1]))/3
for(i in n?"    ":s=" ")for(j in o="|o"[+!+i].padEnd(x>n?x-d*i|0:x+d*i|0,"|")[S="padStart"](m,"."))A[j]+=o[j]},A=Array((m=Math.max(...a))+2).fill(""))&&A.map((x,i)=>x?(m-i+"|.")[S](4,0)+x+".":i>m?s+s+a.map((_,I)=>s+(-~I+s)[S](3,0)).join``:"  +".padEnd(a.length*4+2,"-"))

Try it online!

Python 2, 261 246 bytes
lambda a:[["   0","  +-","%02d|."%~-i][min(i,2)]+"".join(s)[3:]+" -."[min(i,2)]for i,s in enumerate(zip(*[list(("  %02d"%-~j)[i]+"-"+"o|"[i<3].rjust(a[j-1]+(v-a[j-1])*-~i/4,"|").ljust(max(a),"."))for j,v in enumerate(a)for i in range(4)]))][::-1]

Try it online!
Anonymous lambda returning the list of strings comprising the chart. Performs  linear interpolation between points with floor rounding, in 4 steps from a[i-1] to a[i].
Python 2, 271 256 bytes
lambda a:[["   0","  +-","%02d|."%~-i][min(i,2)]+"".join(s)[3:]+" -."[min(i,2)]for i,s in enumerate(zip(*[list(("  %02d"%-~j)[i]+"-"+["o".rjust(v,"|"),"|"*(a[j-1]+(v+~a[j-1])*-~i/3)][i<3].ljust(max(a),"."))for j,v in enumerate(a)for i in range(4)]))][::-1]

Try it online!
Alternative version that interpolates in the same manner as defined in the OP's reference code. Interpolation occurs in 3 steps from a[i-1] to a[i]-1. This way, the value of the third 'tween' column is always 1 below the actual data point, and these two columns always have the same number of pipes. This matches the reference code except for zero values, which we are not required to support.
Probably the longest lambda I've ever written to date. Will try to revisit and golf a bit more when I have time.

Wow, intense use of lambda! I would have never imagined you could do this with one line of python. I do not require that the in-between columns are always 1 below the data point, the idea was to use linear interpolation. Sorry if my sample code made this unclear!

Well, that's even better for me, as it saves bytes. But I'll keep both versions for reference.

Charcoal, 110 106 103 bytes
ＡθＵＢ.⮌Ｅ⌈θ⁺⁺×0⁻Ｌ⌈θＬ⊕κκ|Ｇ↓²→Ｌ⌈θ↑² ↓Ｐ⁺⪫Ｅθ◧⁺×0⁻ＬＬθＬ⊕κκ⁴ω ↗≔Ｅ⁻×⁴Ｌθ³§θ÷κ⁴θ+Ｐ⁺²Ｌθ↗↑Ｅθ⎇﹪κ⁴⁺ι÷×﹪κ⁴⁻§θ⁺⁴κι⁴⁺×|⊖ιo

Try it online! Link is to verbose version of code. Edit: Saved 3 bytes thanks to @ASCII-only. Explanation:
Ａθ

Input the array.
ＵＢ.

Set the background of the output to ..
⮌Ｅ⌈θ⁺⁺×0⁻Ｌ⌈θＬ⊕κκ|

Print the Y-axis with its labels left padded with zeros.
Ｇ↓²→Ｌ⌈θ↑² ↓

Blank out the bottom left corner so that it isn't filled with .s.
Ｐ⁺⪫Ｅθ◧⁺×0⁻ＬＬθＬ⊕κκ⁴ω ↗

Print the X labels.
≔Ｅ⁻×⁴Ｌθ³§θ÷κ⁴θ

Repeat the values in the array 4 times (except for the last value).
+Ｐ⁺²Ｌθ↗↑

Print the X-axis.
Ｅθ⎇﹪κ⁴⁺ι÷×﹪κ⁴⁻§θ⁺⁴κι⁴⁺×|⊖ιo

Print the graph itself, repeating |s with a final o for multiples of 4 and interpolating for intermediate values.

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/3.0/


text:
Ice Golf Challenge
The goal of this challenge is to write a program or function that returns the least amount of strikes needed to complete a given course.
Input

The layout of the course can be passed in any suitable way and format you prefer.
(read from the console, passed as an input parameter, read from a file or any other, multiline-string, string array, two-dimensional character/byte array).
The start position of the ball and the hole can be passed as input too, it doesn't have to be parsed from the input. In the test-cases they are included in the course to make sure there is no confusion about the actual position.
You can remap the input characters to something else, as long as they are still recognisable as distinct characters (e.g. printable ASCII characters).

Output

The program must return the lowest possible score (least amount of strikes needed to reach the hole) for any course passed as input in a sensible format (string, integer, float or a haiku describing the result)
If the course is impossible to beat, return -1 (or any other falsy value of your choice that wouldn't be returned for a beatable course).

Example:
In this example positions are notated 0-based, X/Y, left-to-right, top-down - but you can use any format you like since the result is completely format-independent anyways.
Input:
###########
#     ....#
#      ...#
#  ~    . #
# ~~~   . #
# ~~~~    #
# ~~~~    #
# ~~~~  o #
# ~~~~    #
#@~~~~    #
###########

Ball (Start-Position): 1/9
Hole (End-Position):   8/7

Output:
8

Rules and fields
The course can consist of the following fields:

'@' Ball - The start of the course
'o' Hole - The goal of the course
'#' Wall - Ball will stop when it hits a wall
'~' Water - Must be avoided
'.' Sand - Ball will stop on sand immediately
' ' Ice - Ball will continue to slide until it hits something

The basic rules and restrictions of the game:

The ball can't move diagonally, only left, right, up and down.
The ball will not stop in front of water, only in front of walls, on sand and in the hole.

Shots into the water are invalid/impossible
The ball will stay in the hole, not skip over it like it would on ice

The course is always rectangular.
The course is always bordered by water or walls (no boundary checks required).
There is always exactly one ball and one hole.
Not all courses are possible to beat.
There might be multiple paths that result in the same (lowest) score.

Loopholes and Winning Condition

Standard loopholes are forbidden
Programs must terminate
You can't make up additional rules (hitting the ball so hard it skips over water, rebounds off a wall, jumps over sand fields, curves around corners, etc.)
This is code-golf, so the solution with the least amount of characters wins.
Solutions must be able to handle all provided test-cases, if this is impossible due to restrictions of the used language please specify that in your answer.

Test cases
Course #1 (2 strikes)
####
# @#
#o~#
####

Course #2 (not possible)
#####
#@  #
# o #
#   #
#####

Course #3 (3 strikes)
~~~
~@~
~.~
~ ~
~ ~
~ ~
~ ~
~.~
~o~
~~~

Course #4 (2 strikes)
#########
#~~~~~~~#
#~~~@~~~#
##  .  ##
#~ ~ ~ ~#
#~. o .~#
#~~~ ~~~#
#~~~~~~~#
#########

Course #5 (not possible)
~~~~~~~
~...  ~
~.@.~.~
~...  ~
~ ~ ~.~
~ . .o~
~~~~~~~

More Test cases:
https://pastebin.com/Azdyym00

Related: One, Two.

If we use a two-dimensional byte array as input, are we allowed to use a custom mapping for the symbols?

@Arnauld Not sure what the usual consensus regarding that is here, but I'd say it's ok as long as the input is still be recognisable. I've updated the Input section.

If input the destination directly, can we require the place of destination be 'sand' symbol?

@l4m2 Sure, that way it would stay consistent with all the other rules.

JavaScript (ES6), 174 bytes
Takes input in curling currying syntax ([x, y])(a), where x and y are the 0-indexed coordinates of the starting position and a[ ] is a matrix of integers, with 0 = ice, 1 = wall, 2 = sand, 3 = hole and 4 = water
Returns 0 if there's no solution.
p=>a=>(r=F=([x,y],n,R=a[y],c=R[x])=>R[c&(R[x]=4)|n>=r||[-1,0,1,2].map(d=>(g=_=>(k=a[v=Y,Y+=d%2][h=X,X+=~-d%2])||g())(X=x,Y=y)>3?0:k>2?r=-~n:F(k>1?[X,Y]:[h,v],-~n)),x]=c)(p)|r

Try it online!
Commented
p => a => (                       // given the starting position p[] and the matrix a[]
  r =                             // r = best result, initialized to a non-numeric value
  F = (                           // F = recursive function taking:
    [x, y],                       //   (x, y) = current position
    n,                            //   n = number of shots, initially undefined
    R = a[y],                     //   R = current row in the matrix
    c = R[x]                      //   c = value of the current cell
  ) =>                            //
    R[                            // this will update R[x] once the inner code is executed
      c & (R[x] = 4) |            //   set the current cell to 4 (water); abort if it was
      n >= r ||                   //   already set to 4 or n is greater than or equal to r
      [-1, 0, 1, 2].map(d =>      //   otherwise, for each direction d:
        (g = _ => (               //     g = recursive function performing the shot by
          k = a[                  //         saving a backup (h, v) of (X, Y)
            v = Y, Y += d % 2][   //         and updating (X, Y) until we reach a cell
            h = X, X += ~-d % 2]) //         whose value k is not 0 (ice)
          || g()                  //
        )(X = x, Y = y)           //     initial call to g() with (X, Y) = (x, y)
        > 3 ?                     //     if k = 4 (water -> fail):
          0                       //       abort immediately
        :                         //     else:
          k > 2 ?                 //       if k = 3 (hole -> success):
            r = -~n               //         set r to n + 1
          :                       //       else:
            F(                    //         do a recursive call to F():
              k > 1 ?             //           if k = 2 (sand):
                [X, Y]            //             start the next shots from the last cell
              :                   //           else (wall):
                [h, v],           //             start from the last ice cell
              -~n                 //           increment the number of shots
            )                     //         end of recursive call
      ), x                        //   end of map(); x = actual index used to access R[]
    ] = c                         // restore the value of the current cell to c
)(p) | r                          // initial call to F() at the starting position; return r

Python 3, 273 bytes
def p(g,c,d,k=0):
	while 1>k:c+=d;k=g.get(c,9)
	return-(k==2)or c-d*(k==3)
def f(g):
	c={q for q in g if g.get(q,9)>4};I=0;s=[c]
	while all(g.get(q,9)-4for q in c):
		c={k for k in{p(g,k,1j**q)for k in c for q in range(4)}if-~k}
		if c in s:return-1
		s+=[c];I+=1
	return I

Try it online!
-41 bytes thanks to ovs
-1 byte thanks to Jonathan Frech

Could if k+1 not be if-~k?

@JonathanFrech yes, thanks

C#, 461 418 bytes
This is just a non-competitive reference implementation to (hopefully) revive this challenge:
Golfed by Kevin Cruijssen
int P(string[]C){int w=C[0].Length,i=0,l=c.Length;var c=string.Join("",C);var h=new int[l];for(var n=new List<int>();i<l;n.Add(i++))h[i]=c[i]!='@'?int.MaxValue:0;for(i=1;;i++){var t=n;n=new List<int>();foreach(int x in t){foreach(int d in new[]{-1,1,-w,w}){for(int j=x+d;c[j]==' ';j+=d);if(c[j]=='#'&h[j-d]>s){h[j-d]=s;n.Add(j-d);}if(c[j]=='.'&h[j]>s){h[j]=s;n.Add(j);}if(c[j]=='o')return s;}}if(n.Count<1)return -1;}}

Ungolfed
int IceGolf(string[] course)
{
    // Width of the course
    int w = course[0].Length;

    // Course as single string
    var c = string.Join("", course);

    // Array of hits per field
    var hits = new int[c.Length];

    // Fields to continue from
    var nextRound = new List<int>();

    // Initialize hits
    for (int i = 0; i < hits.Length; i++)
    {
        if (c[i] != '@')
            // All fields start with a high value
            hits[i] = Int32.MaxValue;
        else
        {
            // Puck field starts with 0
            hits[i] = 0;
            nextRound.Add(i);
        }
    }

    for (int s = 1; ; s++)
    {
        // clear the fields that will be used in the next iteration
        var thisRound = nextRound;
        nextRound = new List<int>();

        foreach (int i in thisRound)
        {
            // test all 4 directions
            foreach (int d in new[] { -1, 1, -w, w })
            {
                int j = i+d;

                // ICE - slide along
                while (c[j] == ' ')
                    j += d;

                // WALL - stop on previous field
                if (c[j] == '#' && hits[j-d] > s)
                {
                    hits[j-d] = s;
                    nextRound.Add(j-d);
                }

                // SAND - stop
                if (c[j] == '.' && hits[j] > s)
                {
                    hits[j] = s;
                    nextRound.Add(j);
                }

                // HOLE return strikes
                if (c[j] == 'o')
                    return s;
            }
        }

        // No possible path found
        if (nextRound.Count == 0)
            return -1;
    }
}

Try it online

Golfed a bit more: int P(string[]C){int w=C[0].Length,i=0,l=c.Length;var c=string.Join("",C);var h=new int[l];for(var n=new List<int>();i<l;n.Add(i++))h[i]=c[i]!='@'?int.MaxValue:0;for(i=1;;i++){var t=n;n=new List<int>();foreach(int x in t){foreach(int d in new[]{-1,1,-w,w}){for(int j=x+d;c[j]==' ';j+=d);if(c[j]=='#'&h[j-d]>s){h[j-d]=s;n.Add(j-d);}if(c[j]=='.'&h[j]>s){h[j]=s;n.Add(j);}if(c[j]=='o')return s;}}if(n.Count<1)return -1;}} (418 bytes). Also, could you perhaps add a TIO-link with test code?

Thanks for the TIO link. The code I provided above didn't work, so I fixed it, and golfed three more bytes. Try it online 415 bytes. (You'll have to re-add your huge test case again from your current TIO. I couldn't paste the link in this comment because the link was too big with that test case.. ;p)


text:
Output numbers, more or less
The Challenge
Given an input string (or array) consisting of < and >, output a sequence (array or string) of integers such that:

the operators are all correct when applied in order between consecutive numbers in the output
all integers are positive (1 or greater)
the sum of the integers is as small as is mathematically possible

Inputs can vary to match "greater than" and "less than" in your chosen language.
As an alternative output, just specify the sum of the numbers in the output. State which version you're solving in your Answer title.
Usual exclusions and rules apply, smallest bytes wins.
You can assume that the input string will never lead to an integer overflow in your language, if that helps.
Examples

> gives 2 1 which sums to 3
>>> gives 4 3 2 1 which sums to 10
>< gives 2 1 2 which sums to 5
 gives 1 which sums to 1
>>>>>>>>> gives 10 9 8 7  6 5 4 3 2 1 which sums to 55
>><<>><>>> gives 3 2 1 2 3 2 1 4 3 2 1 which sums to 24
><>><>><> gives 2 1 3 2 1 3 2 1 2 1 which sums to 18
<<<<> gives 1 2 3 4 5 1 which sums to 16
<<<<><<> gives 1 2 3 4 5 1 2 3 1 which sums to 22
>><< gives 3 2 1 2 3 which sums to 11

Can we use symbols other than > and <?

@JonathanAllan I think it's the examples that are wrong, and you should assume that when answering, not that the spec is wrong. EDIT: Well, then I'm afraid they're invalid, since it's the spec that defines a challenge, not the test cases.

@JonathanAllan I meant that, well, there's probably an incoming "bloodbath", so better take action quick.

Just waitin' for an answer in <><.

Massive apologies to everyone for messing up the examples! As for other characters, yes provided they have the same meaning in your language

I have hopefully fixed the examples now. Perhaps I'll ask a follow up question where all numbers have to be consecutive.....

@Scrooble You spelled it wrong. It's ><>

@simonalexander2005 Uh, maybe you expect us to solve the challenge using eval and such and no other approach? Otherwise I don't see any reason for the chars to have the same meaning in our languages.

@Erik if you're not using it like that, why would it help if different characters were allowed?

@simonalexander2005: The character codes could be used directly in arithmetic presumably.

Jelly, 19 bytes
0;+×¥@\
=”<µCṚÇṚ»Ç‘

Try it online!
The value of each number is max( number of > immediately to the right of it , number of < immediately to the left of it ) + 1 .

Alternatively...
Try it online!

I don't like languages requiring a program to transpile like Stax... well, Jelly is borderline. (require a program to compress strings) At least, Jelly still wins.

except Dennis, who compresses strings by hand.

Aesthetically, I don't really like it either.  But the thing I like most of all in a golfing language is whatever allows its programs to be smallest.  I still have a few ideas for stax about this one...

><>, 40 38 bytes
1v!rnr~<oa
?\i:0(?^3%\+$
{/?:-{:}-1/1:

Try it online!
An appropriate language. For reference ><> itself yields 2,1,2,1.
How it Works:
1v   Initialise the stack as 1 and enter loop
 \i:0(?^  If we're out of input, go to the first line
        3%\ Otherwise mod the input by 3, yielding 0 for < and 2 for >
        -1/Subtract 1 to get -1 and 1 respectively
    -{:}   Copy the previous number and subtract the above from it

 /?:    If the number is not 0, repeat the loop

?\        \+$  Otherwise:
                Increment each number until we reach the original 0
{/        /1:   And enter the first loop again

      ~<    When we're out of input, pop the extra -1 from EOF
   rnr      Output the first number
1v!         Push a 1
        oa  Print a newline and repeat, popping the extra 1 each time

+1 for stating what value the language itself holds. :) (And because it's just a good answer as well, otherwise I wouldn't have +1-ed it.)

Python 3, 93 bytes
k=0
for r in input().split('<'):p=len(r);print(max(k,p)+1,*range(p,0,-1),end=' ');k=1+(p<1)*k

Try it online!
Unscrambled:
# offset, will be explained later
k = 0
for run in input().split('<'):
    # p = length of sequence of '>'s, which will produce p+1 decreasing integers
    p = len(run)
    # will print:
    # p+1 p p-1 ... 1    or    k+1 p p-1 ... 1
    print(max(k, p) + 1, *range(p, 0, -1), end=' ')
    # offset of the next sequence: (i.e. -1 + the minimal value of the first integer)
    k = 1 + (k if p > 0 else 0)

This is my first golf!

Haskell, 119 bytes
n%">"=r[1..n]
n%"<"=[1..n]
n%(c:b)|c==b!!0=(n+1)%b|a:s<-2%b,e:z<-r$n%[c]=r z++last(max:[min|c>'<'])a e:s
r=reverse
(2%)

Try it online!
Explanation
The idea here is that we have runs of either >s or <s, which each map to ascending and descending ranges.  So we use group to split the string into groups of consecutive characters.  Our job is to then stitch these together in the proper fashion.
When we have <> we want to stitch the two lists together taking the larger end value  for example
<<<<<<>>

is split
<<<<<<  >>

mapped to ranges
[1,2,3,4,5,6,7] [3,2,1]

Then when we stitch we drop 3 because it is smaller (3 isn't larger than 7).
 [1,2,3,4,5,6,7,2,1]

When we have >< we do the opposite, we drop the larger value.
The actual code attains this by making an operator %.  The definition of % is quite complex, but basically it reads from left to right keeping track of how many consecutive characters are the same.  It does this in the left had value of the operator.  When we reach a place where the characters change we perform the stitching as I described.

What's the purpose of the last line (2%)?

@siracusa That is the function itself.  It is a pointfree function, so it basically says call % with 2 as the first argument.

Is that a common practice here to just put the final function call on the last line instead of adding a full main implementation?

@siracusa Yes.  Submissions are allowed as named functions, anonymous functions or as complete programs.  This is an anonymous function.  I choose anonymous simply because it is the shortest.

@siracusa See our Guide to Golfing Rules in Haskell.

I think your example with <<<<<<>>  results in [1,2,3,4,5,6,7,2,1]
TIO

@GalenIvanov Thanks! I've fixed it.

Retina 0.8.2, 36 bytes

1
{`\b(1+)>\1
1$&
}`(1+)<\1\b
$&1
1

Try it online! Link includes test cases. Explanation:

1

Insert 1s before, between and after the <s and >s.
{`\b(1+)>\1
1$&
}`(1+)<\1\b
$&1

Repeatedly increment integers until all the comparisons are satisfied.
1

Sum the integers and convert to decimal.

Java 10, 198 181 180 bytes
s->{var p=s.split("(?<=(.))(?!\\1)");int l=p.length,L[]=new int[l],i=l,r=0,a,b;for(;i-->0;r-=a*~a/2+(i<l-1?p[i].charAt(0)<61?a<(b=L[i+1])?a:b:1:0))a=L[i]=p[i].length()+1;return r;}

-1 byte thanks to @ceilingcat.
Try it online.
Explanation:
s->{                     // Method with String parameter and integer return-type
  var p=s.split("(?<=(.))(?!\\1)");
                         //  Split the String into parts
                         //  (i.e. ">><<>><>>>" becomes [>>, <<, >>, <, >>>])
  int l=p.length,        //  Get the amount of parts
      L[]=new int[l],    //  Create an integer-array of the same size
      i=l,               //  Index-integer, starting at this size
      r=0,               //  Result-integer, starting at 0
      a,b;               //  Two temp integers to reduce the byte-count
  for(;i-->0;            //  Loop downwards over the array; range: (`l`,0]
      ;r-=               //    After every iteration: decrease the result with:
          a*~a/2         //     The negative triangle number of the current item
        +                //     And add to that negative triangle number before subtracting:
         (i<l-1?         //      If it's not the last item:
           p[i].charAt(0)<61?
                         //       And the order of the current and previous is "<>":
            a<(b=L[i+1])?//        If the current item in `L` is smaller than the previous:
             a           //         Add the current item
            :            //        Else (the current is equal or larger than the previous):
             b           //         Add the previous item
           :             //       Else (the order of the two parts is "><" instead):
            1            //        Add 1
          :              //      Else (it's the last item in `L`):
           0))           //       Leave the result `r` unchanged by adding 0
    a=L[i]=              //   Set both `a` and the current item in `L` to:
     p[i].length()+1;    //    The length of the part + 1
  return r;}             //  Return the result

Haskell, 87 bytes
r=reverse
s#c=(+1).length.takeWhile(==c)<$>scanr(:)[]s
f s=zipWith max(s#'>')$r$r s#'<'

Try it online!
A port of my Jelly answer.

You can take of 3 bytes

@user56656 Thanks!

Perl 5 -p, 53 bytes
#!/usr/bin/perl -p
s//1/g;1while s/(?=\b(1+)>\1)|(1+)<\2\b\K/1/;$_=y/1//

Try it online!

This answer seems to have been implemented based off of the test cases instead of the challenge specification. Unfortunately, they have been identified as wrong.

@EriktheOutgolfer Fixed

Stax, 21 bytes
éda╓~/└↨☺∟╒←║ç Γφ5←9h

Run and debug it
It works by run-length encoding the input, and then concatenating generated ranges together.  Unpacked, ungolfed, and commented, it looks like this.
|R      run-length encode
{       begin block
  H^R   range from [1 .. run length]
  _hh|1 -1 ** (character code / 2)
  *     multiply run; this will reverse it iff character is '>'
m       map runs using preceding block
O       push a 1 under the top of stack
{       begin block
  h|M   get the start of the generated range, and take max of it and top of stack
  _DE   push the rest (tail) of the generated range to the stack
F       foreach generated range
L|+     sum of all values on the stack

Run this one

Red, 185 bytes
func[s][repeat n 1 + length? s[l: 0 i: n - 1 while[i > 0 and(s/(i) = #"<")][i:  i - 1 l: l + 1]r: 0 i: n while[(i <= length? s)and(s/(i) = #">")][i: i + 1 r:
r + 1]prin[1 + max l r""]]]

After user202729's explanation...
Try it online!
f: func[s][
   repeat n 1 + length? s[
       l: 0
       i: n - 1
       while [i > 0 and (s/(i) = #"<")][
           i: i - 1
           l: l + 1
        ]
        r: 0
        i: n
        while [(i <= length? s) and (s/(i) = #">")][
            i: i + 1
            r: r + 1
        ]
        prin[1 + max l r ""]
    ]
]

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/