Skip to content

Instantly share code, notes, and snippets.

@danbst
Created February 22, 2021 13:46
Show Gist options
  • Save danbst/7d1841fc9653c6c2a33ed4bd1915aa43 to your computer and use it in GitHub Desktop.
Save danbst/7d1841fc9653c6c2a33ed4bd1915aa43 to your computer and use it in GitHub Desktop.
Trainer for powers of 2, inverse powers of two and indexof in Python
import time
import random
from datetime import datetime
from pprint import pprint
import pickle
import math
class PowerTwo:
"""
Trainer for powers of two
"""
def __init__(self, stats):
self.value = 0
self.complexity = 1
self.stats = stats
def make_prompt(self):
selection = [0,1,2,3,4]
prompts = ["2**{0}"]
if self.complexity >= 2:
selection.extend([5,6,7,8]*3)
prompts.append("2 to power of {0}")
if self.complexity >= 3:
selection.extend([9,10,11,12]*5)
prompts.append("{0} nth power of 2")
self.value = random.choice(selection)
return random.choice(prompts).format(self.value), self.value
def check_result(self, result):
try:
result = int(result.strip())
except:
return False
if result == 2**self.value:
return True
else:
return False
def update_complexity(self, avgduration, corrects, wrongs):
if avgduration < 3000 and len(wrongs) == 0:
self.complexity += 1
return True
return False
class InversePowerTwo:
"""
Trainer for guessing which power of two gives a number
"""
def __init__(self, stats):
self.value = 0
self.complexity = 1
self.stats = stats
def make_prompt(self):
selection = [2**x for x in range(5)]
prompts = ["which power of 2 gives {0}"]
if self.complexity >= 2:
selection.extend([2**x for x in range(5, 11)]*3)
prompts.append("integer part of log2({0})")
if self.complexity >= 3:
selection.extend([2**x for x in range(11, 17)]*5)
prompts.append("int(math.log({0}, 2))")
self.value = random.choice(selection)
return random.choice(prompts).format(self.value), self.value
def check_result(self, result):
try:
result = int(result.strip())
except:
return False
if result == int(math.log2(self.value)):
return True
else:
return False
def update_complexity(self, avgduration, corrects, wrongs):
if avgduration < 3000 and len(wrongs) == 0:
self.complexity += 1
return True
return False
class IndexCounter:
"""
Trainer for fast searching of a number's index. Negative indexes are accepted
"""
def __init__(self, stats):
self.value = 0
self.complexity = 1
self.stats = stats
def make_prompt(self):
listsize = 5
maxnumber = 10
if self.complexity >= 2:
listsize = 10
maxnumber = 10
if self.complexity >= 3:
listsize = 13
maxnumber = 99
self.value_list = random.sample(range(maxnumber), k=listsize)
self.value = self.value_list[random.randrange(0, len(self.value_list))]
return "List: {}\nIndex of {}".format(self.value_list, self.value), (self.value_list, self.value)
def check_result(self, result):
try:
result = int(result.strip())
except:
return False
#print(self.value, self.value_list, result)
if self.value == self.value_list[result]:
return True
else:
return False
def update_complexity(self, avgduration, corrects, wrongs):
if avgduration < 3000 and len(wrongs) == 0:
self.complexity += 1
return True
return False
def clearscr():
print('\n'*50)
class GamePlay:
def __init__(self):
self.filename = 'stats.txt'
self.stats = []
try:
with open(self.filename, 'rb') as f:
self.stats = pickle.load(f)
except OSError:
pass
except EOFError:
pass
def save_stats(self):
with open(self.filename, 'wb') as f:
pickle.dump(self.stats, file=f)
def play(self, class_):
self.current_stats = [x for x in self.stats if x.get('game_class', None) == class_.__name__]
game = class_(self.current_stats)
count = 0
checkpoint = 10
while True:
clearscr()
prompt, value = game.make_prompt()
start_time = time.time()
result = input(f'[{count}/{checkpoint}] ' + prompt + ": ")
duration = int((time.time() - start_time)*1000)
check = game.check_result(result)
stat = {'game_class': class_.__name__,
'time': datetime.now(),
'duration': duration,
'prompt': prompt,
'value': value,
'answer': result,
'correct': check,
}
self.current_stats.append(stat)
self.stats.append(stat)
self.save_stats()
if check:
print("Correct!")
time.sleep(1)
else:
input("Wrong!\n")
count += 1
if count >= checkpoint:
count = 0
print(".... STATS .....")
checkstats = self.current_stats[-checkpoint:]
correctstats = [x for x in checkstats if x['correct']]
avgduration = sum([x['duration'] for x in correctstats])/len(correctstats)
print(f"Average duration for correct stats: {int(avgduration)} ms")
wrongstats = [x for x in checkstats if not x['correct']]
if wrongstats:
print("WRONGS:")
for x in [x for x in checkstats if not x['correct']]:
print(x['prompt'], x['answer'])
if game.update_complexity(avgduration, correctstats, wrongstats):
print()
print(f"CONGRATULATIONS! Complexity upgraded to {game.complexity}")
input()
def main():
gameplay = GamePlay()
games = [PowerTwo, InversePowerTwo, IndexCounter]
while True:
clearscr()
# Ask which game, Ctrl-C will exit
for i, game in enumerate(games):
print(f"{i+1}) {game.__doc__}")
try:
game_class = games[int(input())-1]
except KeyboardInterrupt:
break
# Actually play, Ctrl-C will finish play and ask which game again
try:
gameplay.play(game_class)
except KeyboardInterrupt:
pass
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment