previndexinfo

code guessing, round #95, stage 2 (guessing)

started at ; stage 2 since . guess by

specification

too long have programs been made that make user guess some number. it's time to switch the roles up - now the user will think of an integer between 1 and 100 (inclusive), and your program will guess the number!

while any language is allowed, a number of standard interfaces are proposed. in functional languages, such as C and Python, one could define a procedure that accepts a closure as an argument, which the procedure calls with an integer to submit its guesses, and the closure returns, as an integer, the result: -1 if the guess is too low, 1 if the guess is too high, or 0 if the guess is spot on. closure can be called multiple times, until a guess is found. the sigmature would look like this in C:

void entry(int (*submit)(int, void*), void *data) {
  int result = submit(42, data);
  // ...
}

or in Python:

def entry(submit):
  result = submit(42)
  // ...

similar pattern should be adaptable to other languages. if not, there is an alternate interface. instead, you can communicate with the user via the standard IO streams. simply print the guess on its own line using ASCII digits to stdout, then read a line from stdin: it will spell "LOW" (no quotes) if your guess is too low, "HIGH" if your guess is too high, "WIN" if your guess is spot on. rinse and repeat until WIN.

if neither standard interface works for your language or you just don't like to implement it, you are free to invent your own interface.

your challenge, given a procedure, write a program that guesses a number between 1 and 100. any language is allowed, there is an API.

players

  1. Dolphy
  2. essaie
  3. Indigo
  4. kimapr
  5. lychee
  6. Makefile_dot_in
  7. oleander

entries

you can download all the entries

entry #1

comments 0

post a comment


sh.final_draft_v3_final_complete_GTM.sh ASCII text
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# the actual value the program is looking for (we pretend that the guess function is unaware of this variable)
TRUE_VALUE=$(($(dd if=/dev/urandom count=1 2> /dev/null | cksum | cut -d' ' -f1) % 100))



# $1 should be the guess
# using echo as return is for little skibidi toilets, hence im using error codes
# (this function is implemented for testing purposes)
submit() {
    echo "guess: $1"
    # Too big
    if (( $1 < TRUE_VALUE )); then
        return -1 # overflows to 255

    elif (( $1 > TRUE_VALUE )); then
        return 1

    elif [[ $1 -eq $TRUE_VALUE ]]; then
        return 0

    else
        while true; do
            printf "crazy? i was crazy once. they put me in a room. a rubber room. a rubber room with rats. the rats made me ..."
        done
    fi

}

guess() {
  # I was initially planning to do a perfectly suboptimal search (binary search, but guessing all values in the wrong direction before proceeding), but then it occurred to me... i couldn't be bothered
  for i in {0..100}; do

    submit $i

    if [[ $? -eq "0" ]]; then
        echo "welp that was fun, im off"

        return 0
    fi
  done
}

guess

entry #2

comments 0

post a comment


code.c ASCII text
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
// guesser

#include <limits.h>
#include <stddef.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>

#include "code.h"


static unsigned char randbyte();
static void memrand(void* buf, size_t size);
static int limrand(int min, int max);

struct guesser_data {
  int min;
  int max;

  struct {
    guess_submit_closure fn;
    void* data;
  } submit;

  void (*print)(const char*);
};

static void
default_print(const char* msg) {}

static void
init_guesser_data(struct guesser_data* data, guess_submit_closure submit, void* submit_data)
{
  data->min = INT_MIN;
  data->max = INT_MAX;
  data->submit.fn = submit;
  data->submit.data = submit_data;
  data->print = default_print;
}

static void guesser_basic(struct guesser_data* data);
static void guesser_extended(struct guesser_data* data);
static void whoppenheimer(struct guesser_data* data);


void
entry(guess_submit_closure submit, void* data)
{
  struct guesser_data guesser_data;
  init_guesser_data(&guesser_data, submit, data);

  guesser_basic(&guesser_data);
}

void
guesser_basic(struct guesser_data* data)
{
  while (1) {
    int min = data->min < 1 ? 1 : data->min;
    int max = data->max > 100 ? 100 : data->max;
    int num = limrand(min, max);
    int result = data->submit.fn(num, data->submit.data);

    if (result == 0) {
      return;
    }

    if (((num == data->min) && result > 0) || (num == data->max && result < 0)) {
      return whoppenheimer(data);
    }

    if (result < 0) {
      data->min = num + 1;
    } else if (result > 0) {
      data->max = num - 1;
    }

    if ((num == 1 && result > 0) || (num == 100 && result < 0)) {
      data->print("Hmm, that's not right. Are you sure the number is between 1 and 100?");
      return guesser_extended(data);
    }
  }
}

void
guesser_extended(struct guesser_data* data)
{
  while (1) {
    int min = data->min;
    int max = data->max;
    int num = limrand(min, max);
    int result = data->submit.fn(num, data->submit.data);

    if (result == 0) {
      return;
    }

    if (((num == data->min) && result > 0) || (num == data->max && result < 0)) {
      return whoppenheimer(data);
    }

    if (result < 0) {
      data->min = num + 1;
    } else if (result > 0) {
      data->max = num - 1;
    }
  }
}

#if (__GNUC__ > 4)
typedef unsigned __int128 whoppentype;
#else
typedef struct { long long a, b; } whoppentype;
#endif

void
whoppenheimer(struct guesser_data* data)
{
  whoppentype guess;
  memrand(&guess, sizeof(guess));
  data->print("There is no number that satisfies all this, you must be messing with me. Goodbye.");

  // lets see how you like THAT, huh
  ((int (*)(whoppentype, void*))data->submit.fn)(guess, data->submit.data);
  abort();
}


unsigned char
randbyte()
{
  static unsigned char bytes[256];
  static int pos = sizeof(bytes);
  static int randfd = -1;

  if (randfd == -1) {
    randfd = open("/dev/urandom", O_RDONLY);
  }

  if (randfd == -1) {
    abort();
  }

  if (pos >= sizeof(bytes)) {
    if (read(randfd, bytes, sizeof(bytes)) != sizeof(bytes)) {
      abort();
    }

    pos = 0;
  }

  return bytes[pos++];
}

void
memrand(void* buf, size_t size)
{
  unsigned char* p = buf;
  unsigned char* pend = buf + size;

  for (; p < pend; ++p) {
    *p = randbyte();
  }
}

int
limrand(int min, int max)
{
  unsigned int limit = (unsigned int)max - (unsigned int)min;
  unsigned int limit2;
  unsigned int num = 0;

  if (limit == UINT_MAX) {
    memrand(&num, sizeof(num));
    return min + num;
  }

  if (limit == 0) {
    return min;
  }

  limit2 = limit;
  limit2 |= limit2 >> 1;
  limit2 |= limit2 >> 2;
  limit2 |= limit2 >> 4;
  limit2 |= limit2 >> 8;
#if (UINT_WIDTH > 16)
  limit2 |= limit2 >> 16;
#endif
#if (UINT_WIDTH > 32)
#error int type is too big
#endif
  limit2++;

  do {
    num = 0;
    unsigned int limit3 = limit2 - 1;

    while (limit3) {
      limit3 >>= 8;
      num <<= 8;
      num ^= randbyte();
    }

    num &= limit2 - 1;
  } while(num > limit);

  return min + num;
}
code.h ASCII text
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#ifndef CODE_GUESSER_H
#define CODE_GUESSER_H

// guesser

typedef int (*guess_submit_closure)(int, void*);

void entry(guess_submit_closure submit, void* data);

#endif
main.c ASCII text
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <stdio.h>
#include <string.h>

#include "code.c"

void
real_print(const char* msg)
{
  fprintf(stderr, "%s\n", msg);
}

int
submit_io_guess(int num, void* data)
{
  if (*((int*)data) != 42) {
    abort();
  }

  fprintf(stderr, "\nMy guess is: ");
  fflush(stderr);
  fprintf(stdout, "%d\n", num);
  fflush(stdout);

  while (1) {
    char buf[64];
    fprintf(stderr, "? ");
    fflush(stderr);

    if (!fgets(buf, sizeof(buf), stdin)) {
      exit(1);
    }

    if (buf[strlen(buf) - 1] == '\n') {
      buf[strlen(buf) - 1] = '\0';
    }

    if (strcmp(buf, "HIGH") == 0) {
      return 1;
    } else if (strcmp(buf, "LOW") == 0) {
      return -1;
    } else if (strcmp(buf, "WIN") == 0) {
      return 0;
    }

    fprintf(stderr, "My guess is %d. Type \"LOW\" if too LOW, \"HIGH\" if too high, \"WIN\" if correct. No quotes or spaces.\n", num);
  }
}

int
main()
{
  if (!isatty(STDOUT_FILENO)) {
    if (!freopen("/dev/null", "w", stderr)) {
      return 1;
    }
  }

  fprintf(stderr, "Think of a number between 1 and 100.\n");
  fprintf(stderr, "I will guess the number.\n");
  fprintf(stderr, "If my guess is too low, type \"LOW\".\n");
  fprintf(stderr, "If my guess is too high, type \"HIGH\".\n");
  fprintf(stderr, "If my guess is correct, type \"WIN\", and the game will end.\n");

  struct guesser_data guesser_data;
  int cookie = 42;
  init_guesser_data(&guesser_data, submit_io_guess, (void*)&cookie);
  guesser_data.print = real_print;

  guesser_basic(&guesser_data);
}

entry #3

comments 0

post a comment


geoguessr.py ASCII text
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# hello world
def entry(submit):
  yinmn = 1
  guess = 0
  trout = 0
  while submit(guess) - 1:
    guess += yinmn
    yinmn += yinmn
    # print(guess)
  while trout := submit(guess):
    yinmn /= 2
    guess -= yinmn * trout
    # print(guess)
  return guess

# challenge = lambda N: lambda n: -1 if n < N else 1 if n > N else 0

entry #4

comments 0

post a comment


entry.hs ASCII text
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
submit :: Int -> Int -> Int
submit n x
  | x > n = 1
  | x < n = -1
  | otherwise = 0

entry :: (Int -> Int) -> Int
entry f = helper f 1 101
  where
    helper :: (Int -> Int) -> Int -> Int -> Int
    helper f low upp = let mid = (low + upp) `div` 2; a = f mid in
      if a == -1 then helper f mid upp
      else if a == 1 then helper f low mid
      else mid

entry #5

comments 0

post a comment


GUESR.LOL ASCII text
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
HAI 1.2
I HAS A MAX ITZ 101
I HAS A MIN ITZ 0
I HAS A USERIN
I HAS A GUESS
IM IN YR GAMELOOP
    GUESS R QUOSHUNT OF SUM OF MAX AN MIN AN 2
    VISIBLE GUESS
    GIMMEH USERIN
    BOTH SAEM USERIN AN "WIN"
    O RLY?
        YA RLY
            GTFO
        MEBBE BOTH SAEM USERIN AN "LOW"
            MIN R GUESS
        MEBBE BOTH SAEM USERIN AN "HIGH"
            MAX R GUESS
    OIC
IM OUTTA YR GAMELOOP
KTHXBYE

entry #6

comments 0

post a comment


driver.c ASCII text
1
2
3
#include <stdio.h>
#include <string.h>
void entry(int(*)(int,void*),void*);int s(int v,void*){printf("Computer guessed: %d\n> ",v);char b[5];for(;;){scanf("%s",b);if(!strcmp(b,"LOW"))return-1;else if(!strcmp(b,"HIGH"))return 1;else if(!strcmp(b,"WIN"))return 0;}}int main(){entry(s,0);}
entry.c ASCII text, with no line terminators
1
void entry(int(*s)(int,void*),void*d){int l=0;int u=100;for(;;){int g=(l+u)/2;switch (s(g,d)){case-1:l=g;break;case 1:u=g;break;case 0:return;}}}

entry #7

comments 0

post a comment


cg95.py ASCII text
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
def entry(submit):
    min = 1
    max = 100
    guess = 50
    while True:
        match submit(guess):
            case -1:
                min = guess
                guess = (min+max)//2
            case 1:
                max = guess
                guess = (min+max)//2
            case 0:
                return guess

        if max - min <= 2:
            return (min+max)//2

if __name__ == '__main__':
    print(entry(lambda guess: [print(guess), {'HIGH': 1, 'LOW': -1, 'WIN': 0}[input('HIGH/LOW/WIN:')]][1]))