java-如何处理数字猜谜游戏(带有扭曲)算法?

我正在学习编程(Python和算法),并试图从事一个我觉得很有趣的项目。 我已经创建了一些基本的Python脚本,但是不确定如何为我尝试构建的游戏找到解决方案。

游戏的运作方式如下:

将为用户提供带有值的项目。 例如,

Apple = 1
Pears = 2
Oranges  = 3

然后,他们将有机会选择自己喜欢的任何组合(即100个苹果,20个梨和一个橙子)。 计算机获得的唯一输出是总价值(在此示例中,当前价值为143美元)。 计算机将尝试猜测它们所拥有的。 显然,第一轮将无法正确获得。

         Value    quantity(day1)    value(day1)
Apple      1        100                100
Pears      2         20                 40
Orange     3          1                  3
Total               121                143

下一轮用户可以修改其号码,但不能超过总数的5%(或我们可以选择的其他百分比。例如,我将使用5%)。 水果的价格可以(随机)变化,因此总价值也可以基于此变化(为简单起见,在此示例中,我不更改水果的价格)。 使用上面的示例,在游戏的第2天,用户在第3天返回了$ 152和$ 164的值。这是一个示例:

Quantity (day2)   %change (day2)    Value (day2)   Quantity (day3)   %change (day3)   Value(day3)
 104                                 104            106                                106
  21                                  42             23                                 46
   2                                   6              4                                 12
 127               4.96%             152            133               4.72%            164

*(我希望表格能正确显示,我必须手动将它们隔开,所以希望它不仅可以在屏幕上显示,如果无法正常工作,请告诉我,我将尝试上传屏幕截图。)

我正在尝试查看是否可以确定一段时间后的数量(假设用户将有耐心继续输入数字)。 我现在知道,我唯一的限制是总值不能超过5%,所以现在我的精度不能超过5%,因此用户将永远输入该值。

到目前为止我做了什么

到目前为止,这是我的解决方案(不多)。 基本上,我采用所有值并找出它们的所有可能组合(本部分已完成)。 然后,我将所有可能的组合作为字典放入数据库(例如,对于$ 143,可能会有一个字典条目{apple:143,Pears:0,Oranges:0} ..一直到{apple :0,Pears:1,Oranges:47}。每当我得到一个新号码时,我都会这样做,因此我会列出所有可能性。

这是我被困的地方。 在使用上述规则时,如何找出最佳解决方案? 我认为我需要一个适应度函数,该函数可以自动比较两天的数据并删除与前几天的数据相差5%以上的所有可能性。

问题:

因此,我的问题是用户更改了总数,并获得了所有概率的列表,我该如何处理呢? 我需要学习什么? 是否有适用的算法或可以使用的理论? 或者,为了帮助我理解我的错误,您能否建议我可以添加哪些规则以使该目标变得可行(如果它不处于当前状态。我正在考虑添加更多水果并说他们必须选择至少3个,等等。)? 另外,我对遗传算法只有一个模糊的理解,但是我想如果可以使用的话我可以在这里使用它们?

我非常渴望学习,因此任何建议或技巧都将不胜感激(只是请不要告诉我这个游戏是不可能的)。

更新:获得很难解决的反馈。 因此,我想我会在游戏中添加另一个条件,即不会干扰玩家的行为(游戏对他们而言保持不变),但是每天水果的价值都会改变价格(随机)。 这样会更容易解决吗? 因为在5%的移动范围内,并且某些水果值发生了变化,所以随着时间的推移,只有少数几种组合是可能的。

第1天,一切皆有可能,并且达到足够近的范围几乎是不可能的,但是由于水果价格会发生变化,并且用户只能选择5%的变化,因此(随着时间的推移)不应将范围缩小。 在上面的示例中,如果价格波动足够大,我想我可以蛮力提出一个可以让我猜出一个范围的解决方案,但我试图找出是否有更优雅的解决方案或其他解决方案来将范围缩小 时间。

UPDATE2:在阅读并询问后,我相信这是一个隐含的马尔可夫/维特比问题,可以追踪水果价格以及总金额的变化(对最后一个数据点加权最重)。 我不确定如何应用这种关系。 我认为是这种情况,可能是错误的,但至少我开始怀疑这是某种类型的机器学习问题。

更新3:我创建了一个测试用例(具有较小的数字)和一个生成器,以帮助自动执行用户生成的数据,并且我试图从中创建图形以查看更可能的情况。

这是代码,以及总值和关于用户实际收获数量的注释。

#!/usr/bin/env python
import itertools

# Fruit price data
fruitPriceDay1 = {'Apple':1, 'Pears':2, 'Oranges':3}
fruitPriceDay2 = {'Apple':2, 'Pears':3, 'Oranges':4}
fruitPriceDay3 = {'Apple':2, 'Pears':4, 'Oranges':5}

# Generate possibilities for testing (warning...will not scale with large numbers)
def possibilityGenerator(target_sum, apple, pears, oranges):
    allDayPossible = {}
    counter = 1
    apple_range = range(0, target_sum + 1, apple)
    pears_range = range(0, target_sum + 1, pears)
    oranges_range = range(0, target_sum + 1, oranges)
    for i, j, k in itertools.product(apple_range, pears_range, oranges_range):
        if i + j + k == target_sum:
            currentPossible = {}

            #print counter
            #print 'Apple', ':', i/apple, ',', 'Pears', ':', j/pears, ',', 'Oranges', ':', k/oranges
            currentPossible['apple'] = i/apple
            currentPossible['pears'] = j/pears
            currentPossible['oranges'] = k/oranges

            #print currentPossible
            allDayPossible[counter] = currentPossible
            counter = counter +1
    return allDayPossible

# Total sum being returned by user for value of fruits
totalSumDay1=26 # Computer does not know this but users quantities are apple: 20, pears 3, oranges 0 at the current prices of the day
totalSumDay2=51 # Computer does not know this but users quantities are apple: 21, pears 3, oranges 0 at the current prices of the day
totalSumDay3=61 # Computer does not know this but users quantities are apple: 20, pears 4, oranges 1 at the current prices of the day
graph = {}
graph['day1'] = possibilityGenerator(totalSumDay1, fruitPriceDay1['Apple'], fruitPriceDay1['Pears'], fruitPriceDay1['Oranges'] )
graph['day2'] = possibilityGenerator(totalSumDay2, fruitPriceDay2['Apple'], fruitPriceDay2['Pears'], fruitPriceDay2['Oranges'] )
graph['day3'] = possibilityGenerator(totalSumDay3, fruitPriceDay3['Apple'], fruitPriceDay3['Pears'], fruitPriceDay3['Oranges'] )

# Sample of dict = 1 : {'oranges': 0, 'apple': 0, 'pears': 0}..70 : {'oranges': 8, 'apple': 26, 'pears': 13}
print graph
5个解决方案
12 votes

我们将图论和概率结合起来:

在第一天,构建一套所有可行的解决方案。 让我们表示设置为A1 = {a1(1),a1(2),...,a1(n)}的解。

在第二天,您可以再次构建解决方案集A2。

现在,对于A2中的每个元素,您需要检查是否可以从A1的每个元素中达到(给定的x%公差)。 如果是这样-将A2(n)连接到A1(m)。 如果无法从A1(m)中的任何节点访问它-您可以删除此节点。

基本上,我们正在建立一个连通的有向无环图。

图中所有路径的可能性均等。 仅当从Am到Am + 1有一条边(从Am的节点到Am + 1的节点)时,您才能找到确切的解决方案。

当然,某些节点出现在比其他节点更多的路径中。 每个节点的概率可以根据包含该节点的路径数直接得出。

通过为每个节点分配权重,该权重等于通向该节点的路径数,则无需保留所有历史记录,而仅保留前一天。

另外,请看一下非负线性线性二项方程方程式-我刚才问过一个问题。 可接受的答案是枚举每个步骤中所有组合的好方法。

Lior Kogan answered 2020-01-14T15:04:53Z
7 votes

这个问题是无法解决的。

假设您确切知道增加了多少项目,而不只是知道最大比率是多少。

用户有N个水果,而您有D天的猜测时间。

在每一天中,您将获得N个新变量,然后共有D * N个变量。

对于每一天,您只能生成两个方程式。 一个方程是n_item * price的总和,另一个方程是基于已知比率的。 如果它们都是独立的,则总共最多有2 * D个方程。

所有N> 2的2 * D <N * D

Luka Rahne answered 2020-01-14T15:05:35Z
6 votes

免责声明:由于我误读了问题的某些关键部分,因此暂时删除了我的答案并仔细阅读了该问题后,我的答案有了很大的改变。 虽然仍然引用相似的主题和算法,但在我尝试自己解决C#中的某些问题后,答案得到了很大的改善。

好莱坞版

  • 该问题是动态约束满足问题(DCSP),是约束满足问题(CSP)的变体。
  • 如果值和数量范围不是很小,请使用Monte Carlo查找给定日期的潜在解决方案。 否则,请使用蛮力找到所有可能的解决方案。
  • 使用约束记录(与DCSP相关),该记录已与前几天级联应用,以限制潜在的解决方案集。
  • 交叉手指,根据概率瞄准并射击(猜测)。
  • (可选)Bruce Willis获胜。

原始版本

首先,我想说明一下我在这里看到的两个主要问题:

  1. 数量众多的可能解决方案。 仅知道项目数量和总价值,例如说3和143,将产生许多可能的解决方案。 此外,要让算法选择有效的解决方案而又不可避免地尝试使用无效的解决方案(总数不等于143),并非易事。

  2. 当找到给定日期Di的可能解时,必须找到一种方法,用{Di + 1 .. Di + n}给出的附加信息消除潜在的解。

让我们为即将出现的示例奠定一些基础:

  • 让整个游戏保持相同的物品价值。 它可以是随机的,也可以由用户选择。
  • 可能的项目值限制在[1-10]的非常有限的范围内,在该范围内,没有两个项目可以具有相同的值。
  • 数量不能大于100。这表示:[0-100]。

为了更轻松地解决此问题,我自由更改了一个约束,这使算法收敛速度更快:

  • 该规则将覆盖“总数”规则:您可以在一天之内添加或删除总数在[1-10]范围内的任意数量的项目。 但是,您不能添加或删除总数相同的项目,但不能超过两次。 这也使游戏的最大生命周期为20天。

此规则使我们能够更轻松地排除解决方案。 而且,对于非微小范围,渲染回溯算法仍然无效,就像您的原始问题和规则一样。

以我的拙见,该规则不是游戏的本质,而只是促进者,使计算机能够解决问题。

问题1:寻找潜在的解决方案

首先,可以使用蒙特卡洛算法解决问题1.找到一组潜在的解决方案。 该技术很简单:为项目值和数量(在它们各自的可接受范围内)生成随机数。 对所需数量的项目重复该过程。 验证解决方案是否可接受。 这意味着验证项目是否具有不同的值,并且总数等于我们的目标总数(例如143)。

尽管此技术具有易于实现的优点,但它也有一些缺点:

  • 不能保证用户的解决方案会出现在我们的结果中。
  • 有很多“遗漏”。 例如,在我们的限制下,大约需要3,000,000次尝试才能找到1,000个潜在的解决方案。
  • 这需要很多时间:在我的懒惰笔记本电脑上大约需要4到5秒钟。

如何克服这些缺点? 好...

  • 将范围限制为较小的值,然后
  • 找到足够数量的潜在解决方案,以便用户解决方案很有可能出现在您的解决方案集中。
  • 使用启发式方法更轻松地找到解决方案(稍后再介绍)。

请注意,限制范围的次数越多,蒙特卡洛算法的作用就越小,因为将没有足够的有效解决方案在合理的时间内对它们进行迭代。 对于约束{3,[1-10],[0-100]},大约有741,000,000个有效解(不限于目标总值)。在那里可以使用Monte Carlo。 对于{3,[1-5],[0-10]},大约只有80,000。 无需使用蒙特卡洛; 蛮力for循环就可以了。

我相信问题1是您所说的约束满意度问题(或CSP)。

问题2:限制一组可能的解决方案

鉴于问题1是CSP,我将继续讨论问题2,而通常将问题称为动态CSP(或DCSP)。

[DCSP]在原始形式的   问题以某种方式改变,通常是因为   考虑因素的限制因环境而变化。 DCSPs   被视为一系列静态CSP,每个CSP都是   可以添加变量和约束的前一个   (限制)或删除(放松)。

与CSP一起使用的一种可能对这个问题有用的技术称为约束记录:

  • 随着环境中的每次更改(用户为Di + 1输入的值),查找有关新约束的信息:加减约束可能使用的数量是多少。
  • 将约束应用于级联的每个前一天。 涟漪效应可能会大大减少可能的解决方案。

为此,您每天需要获得一套新的可能的解决方案。 使用蛮力或蒙特卡洛。 然后,将Di的解决方案与Di-1进行比较,并仅保留能够在不违反约束的情况下继承前几天解决方案的解决方案。

您可能必须保留什么解决方案导致其他什么解决方案的历史记录(可能在有向图中)。约束记录使您能够记住可能的添加-删除数量并基于此拒绝溶液。

还有许多其他步骤可用来进一步改善您的解决方案。 这里有一些想法:

  • 记录在前几天解决方案中找到的项-值组合的约束。 立即拒绝其他解决方案(因为项目值不得更改。)您甚至可以使用解决方案特定的约束为每个现有解决方案找到更小的解决方案集,以更早地拒绝无效解决方案。
  • 每天生成一些“突变的”完整历史记录的解决方案,以“修复” D1解决方案集不包含用户解决方案的情况。 您可以使用遗传算法根据现有的解决方案集找到突变种群。)
  • 使用启发式方法轻松找到解决方案(例如,找到有效解决方案时,尝试通过替换周围的量来尝试找到该解决方案的变体。)
  • 使用行为启发法来预测某些用户操作(例如,每项的数量相同,极端模式等)
  • 用户输入新数量时,请继续进行一些计算。

鉴于所有这些,请尝试根据解决方案和启发式方法的出现来确定排名系统,以确定候选解决方案。

Bryan Menard answered 2020-01-14T15:09:20Z
3 votes

我写了一个玩游戏的程序。 当然,我必须使人的一面自动化,但是我相信我做到了这一点,以至于当我与一个真实的人对战时,我的方法不会失效。

我从机器学习的角度解决了这个问题,并将该问题视为隐藏的马尔可夫模型,其中总价格为观察值。 我的解决方案是使用粒子过滤器。 该解决方案使用NumPy和SciPy用Python 2.7编写。

我在注释中明确提出或在代码中隐含做出的任何假设。 为了使代码以自动化方式运行,我还设置了一些其他约束。 它并不是特别优化的,因为我尝试着从侧面理解而不是速度。

每次迭代输出当前的真实数量和猜测值。 我只是将输出通过管道传输到文件中,这样我就可以轻松对其进行查看。 一个有趣的扩展是将输出绘制在2D(对于2个水果)或3D(对于3个水果)图上。 然后,您将可以看到解决方案中的粒子过滤器已磨合。

更新:

调整后,编辑了代码以包含更新的参数。 包括使用matplotlib(通过pylab)进行的绘图调用。 绘图可在Linux-Gnome上进行,您的工作量可能会有所不同。 默认的NUM_FRUITS为2,以支持绘图。 只需注释掉所有pylab调用即可删除绘图,并能够将NUM_FRUITS更改为任何内容。

很好地估计由UnknownQuantities X Price = TotalPrice表示的当前fxn。 在2D(2个水果)中,这是一条线;在3D(3个水果)中,这是一条平面。 似乎数据太少,以至于粒子过滤器无法可靠地修正正确的数量。 在粒子过滤器的顶部还需要一些智能工具,以将历史信息真正整合到一起。 您可以尝试将粒子过滤器转换为2阶或3阶。

更新2:

我一直在玩我的代码。 我尝试了很多事情,现在介绍了我将要编写的最终程序(开始厌倦这个想法)。

变化:

粒子现在使用浮点而不是整数。 不知道这是否会产生任何有意义的效果,但这是一个更通用的解决方案。 仅在进行猜测时才舍入到整数。

绘图将真实数量显示为绿色正方形,而当前猜测则显示为红色正方形。 当前认为的粒子显示为蓝点(大小取决于我们对它们的相信程度)。 这真的很容易看到算法的运行情况。 (绘图也经过测试,可以在Win 7 64位上运行)。

添加了用于关闭/打开数量更改和价格更改的参数。 当然,两个“关闭”都不有趣。

它做得很好,但是,正如已经指出的,这是一个非常棘手的问题,因此很难找到确切的答案。 关闭CHANGE_QUANTITIES会产生最简单的情况。 您可以通过关闭CHANGE_QUANTITIES的2个水果来解决问题的难度。 查看它以正确的答案进行磨合的速度,然后查看随着增加水果数量的难度。

您还可以通过保持CHANGE_QUANTITIES的状态,但将MAX_QUANTITY_CHANGE从很小的值(.001)调整为“大”值(.05),可以对难度有所了解。

挣扎的一种情况是维数(一种水果的数量)接近于零。 因为它使用平均粒子来猜测,所以它总是会偏离诸如零的硬边界。

总的来说,这是一个很棒的粒子过滤器教程。


from __future__ import division
import random
import numpy
import scipy.stats
import pylab

# Assume Guesser knows prices and total
# Guesser must determine the quantities

# All of pylab is just for graphing, comment out if undesired
#   Graphing only graphs first 2 FRUITS (first 2 dimensions)

NUM_FRUITS = 3
MAX_QUANTITY_CHANGE = .01 # Maximum percentage change that total quantity of fruit can change per iteration
MAX_QUANTITY = 100 # Bound for the sake of instantiating variables
MIN_QUANTITY_TOTAL = 10 # Prevent degenerate conditions where quantities all hit 0
MAX_FRUIT_PRICE = 1000 # Bound for the sake of instantiating variables
NUM_PARTICLES = 5000
NEW_PARTICLES = 500 # Num new particles to introduce each iteration after guessing
NUM_ITERATIONS = 20 # Max iterations to run
CHANGE_QUANTITIES = True
CHANGE_PRICES = True

'''
  Change individual fruit quantities for a random amount of time
  Never exceed changing fruit quantity by more than MAX_QUANTITY_CHANGE
'''
def updateQuantities(quantities):
  old_total = max(sum(quantities), MIN_QUANTITY_TOTAL)
  new_total = old_total
  max_change = int(old_total * MAX_QUANTITY_CHANGE)

  while random.random() > .005: # Stop Randomly    
    change_index = random.randint(0, len(quantities)-1)
    change_val = random.randint(-1*max_change,max_change)

    if quantities[change_index] + change_val >= 0: # Prevent negative quantities
      quantities[change_index] += change_val
      new_total += change_val

      if abs((new_total / old_total) - 1) > MAX_QUANTITY_CHANGE:
        quantities[change_index] -= change_val # Reverse the change

def totalPrice(prices, quantities):
  return sum(prices*quantities)

def sampleParticleSet(particles, fruit_prices, current_total, num_to_sample):
  # Assign weight to each particle using observation (observation is current_total)
  # Weight is the probability of that particle (guess) given the current observation
  # Determined by looking up the distance from the hyperplane (line, plane, hyperplane) in a
  #   probability density fxn for a normal distribution centered at 0 
  variance = 2
  distances_to_current_hyperplane = [abs(numpy.dot(particle, fruit_prices)-current_total)/numpy.linalg.norm(fruit_prices) for particle in particles]
  weights = numpy.array([scipy.stats.norm.pdf(distances_to_current_hyperplane[p], 0, variance) for p in range(0,NUM_PARTICLES)])

  weight_sum = sum(weights) # No need to normalize, as relative weights are fine, so just sample un-normalized

  # Create new particle set weighted by weights
  belief_particles = []
  belief_weights = []
  for p in range(0, num_to_sample):
    sample = random.uniform(0, weight_sum)
    # sum across weights until we exceed our sample, the weight we just summed is the index of the particle we'll use
    p_sum = 0
    p_i = -1
    while p_sum < sample:
      p_i += 1
      p_sum += weights[p_i]
    belief_particles.append(particles[p_i])
    belief_weights.append(weights[p_i])

  return belief_particles, numpy.array(belief_weights)

'''
  Generates new particles around the equation of the current prices and total (better particle generation than uniformly random)
'''
def generateNewParticles(current_total, fruit_prices, num_to_generate):
  new_particles = []
  max_values = [int(current_total/fruit_prices[n]) for n in range(0,NUM_FRUITS)]
  for p in range(0, num_to_generate):
    new_particle = numpy.array([random.uniform(1,max_values[n]) for n in range(0,NUM_FRUITS)])
    new_particle[-1] = (current_total - sum([new_particle[i]*fruit_prices[i] for i in range(0, NUM_FRUITS-1)])) / fruit_prices[-1]
    new_particles.append(new_particle)
  return new_particles


# Initialize our data structures:
# Represents users first round of quantity selection
fruit_prices = numpy.array([random.randint(1,MAX_FRUIT_PRICE) for n in range(0,NUM_FRUITS)])
fruit_quantities = numpy.array([random.randint(1,MAX_QUANTITY) for n in range(0,NUM_FRUITS)])
current_total = totalPrice(fruit_prices, fruit_quantities)
success = False

particles = generateNewParticles(current_total, fruit_prices, NUM_PARTICLES) #[numpy.array([random.randint(1,MAX_QUANTITY) for n in range(0,NUM_FRUITS)]) for p in range(0,NUM_PARTICLES)]
guess = numpy.average(particles, axis=0)
guess = numpy.array([int(round(guess[n])) for n in range(0,NUM_FRUITS)])

print "Truth:", str(fruit_quantities)
print "Guess:", str(guess)

pylab.ion()
pylab.draw()
pylab.scatter([p[0] for p in particles], [p[1] for p in particles])
pylab.scatter([fruit_quantities[0]], [fruit_quantities[1]], s=150, c='g', marker='s')
pylab.scatter([guess[0]], [guess[1]], s=150, c='r', marker='s')
pylab.xlim(0, MAX_QUANTITY)
pylab.ylim(0, MAX_QUANTITY)
pylab.draw()

if not (guess == fruit_quantities).all():
  for i in range(0,NUM_ITERATIONS):
    print "------------------------", i

    if CHANGE_PRICES:
      fruit_prices = numpy.array([random.randint(1,MAX_FRUIT_PRICE) for n in range(0,NUM_FRUITS)])

    if CHANGE_QUANTITIES:
      updateQuantities(fruit_quantities)
      map(updateQuantities, particles) # Particle Filter Prediction

    print "Truth:", str(fruit_quantities)
    current_total = totalPrice(fruit_prices, fruit_quantities)

    # Guesser's Turn - Particle Filter:
    # Prediction done above if CHANGE_QUANTITIES is True

    # Update
    belief_particles, belief_weights = sampleParticleSet(particles, fruit_prices, current_total, NUM_PARTICLES-NEW_PARTICLES)
    new_particles = generateNewParticles(current_total, fruit_prices, NEW_PARTICLES)

    # Make a guess:
    guess = numpy.average(belief_particles, axis=0, weights=belief_weights) # Could optimize here by removing outliers or try using median
    guess = numpy.array([int(round(guess[n])) for n in range(0,NUM_FRUITS)]) # convert to integers
    print "Guess:", str(guess)

    pylab.cla()
    #pylab.scatter([p[0] for p in new_particles], [p[1] for p in new_particles], c='y') # Plot new particles
    pylab.scatter([p[0] for p in belief_particles], [p[1] for p in belief_particles], s=belief_weights*50) # Plot current particles
    pylab.scatter([fruit_quantities[0]], [fruit_quantities[1]], s=150, c='g', marker='s') # Plot truth
    pylab.scatter([guess[0]], [guess[1]], s=150, c='r', marker='s') # Plot current guess
    pylab.xlim(0, MAX_QUANTITY)
    pylab.ylim(0, MAX_QUANTITY)
    pylab.draw()

    if (guess == fruit_quantities).all():
      success = True
      break

    # Attach new particles to existing particles for next run:
    belief_particles.extend(new_particles)
    particles = belief_particles
else:
  success = True

if success:
  print "Correct Quantities guessed"
else:
  print "Unable to get correct answer within", NUM_ITERATIONS, "iterations"

pylab.ioff()
pylab.show()
Kyle answered 2020-01-14T15:10:57Z
1 votes

对于您的初始规则:

从我的学年开始,我想说,如果我们对5%的变化进行抽象,那么我们每天都有一个方程,该方程具有三个未知值(对不起,我不知道英语中的数学词汇),这些值与以前的值相同 天。在第3天,您拥有三个方程式,三个未知值,并且解应该是直接的。

如果三个元素的值足够不同,我想每天可能会忘记5%的变化,因为正如您所说,我们将使用近似值并将这些数字四舍五入。

对于您适应的规则:

在这种情况下,未知数过多且不断变化,因此我不知道直接解决方案。 我会相信Lior; 他的方法看起来不错! (如果价格和数量的范围有限。)

Pierre Sevrain answered 2020-01-14T15:11:37Z
translate from https://stackoverflow.com:/questions/7694978/how-to-approach-a-number-guessing-game-with-a-twist-algorithm