|
from __future__ import absolute_import |
|
from __future__ import division |
|
from __future__ import print_function |
|
|
|
"""Tasks for RL.""" |
|
|
|
import abc |
|
import copy |
|
import itertools |
|
import random |
|
|
|
from absl import logging |
|
import numpy as np |
|
from six.moves import xrange |
|
|
|
from common import bf |
|
from common import reward as r |
|
from single_task import misc |
|
from single_task import test_tasks |
|
|
|
|
|
MAX_EXECUTION_STEPS = 5000 |
|
|
|
|
|
def make_task(task_name, override_kwargs=None, max_code_length=100, |
|
require_correct_syntax=False, |
|
do_code_simplification=False, |
|
correct_bonus=2.0, code_length_bonus=1.0): |
|
"""Make tasks with setting from paper.""" |
|
logging.info('Making paper-config task.') |
|
n = 16 |
|
task_mapping = { |
|
'print-hello': ( |
|
PrintTask, dict(base=27, fixed_string=[8, 5, 12, 12, 15])), |
|
'print': (PrintIntTask, dict(base=256, fixed_string=[1, 2, 3, 4, 5])), |
|
'echo': (EchoTask, dict(base=27, min_length=1, max_length=6)), |
|
'remove-char': ( |
|
RemoveCharTask, dict(base=256, n=n, min_len=1, max_len=6)), |
|
'reverse': ( |
|
ReverseTask, dict(base=256, n=n, min_len=1, max_len=6)), |
|
'reverse-tune': ( |
|
ReverseTaskV2, dict(base=256, reward_type='static-bylen')), |
|
'remove-char-tune': (RemoveCharTaskV2, dict(base=27)), |
|
'prefix': (CommonPrefixTask, dict(base=27)), |
|
'find': (FindSubStrTask, dict(base=27)), |
|
'sort3': (SortFixedTaskV2, dict(base=27, n=150, length=3)), |
|
'count-char': (CountCharTaskV2, dict(n=n, max_len=6)), |
|
'bool-logic': (BooleanLogicTask, dict()), |
|
'add': (AddTask, dict(n=9)), |
|
'echo-twice': (EchoTwiceTask, dict(n=n)), |
|
'echo-thrice': (EchoThriceTask, dict(n=n)), |
|
'copy-reverse': (CopyReverseTask, dict(n=n)), |
|
'zero-cascade': (EchoZeroCascadeTask, dict(n=n)), |
|
'cascade': (EchoCascadeTask, dict(n=n)), |
|
'shift-left': (ShiftLeftTask, dict(n=n)), |
|
'shift-right': (ShiftRightTask, dict(n=n)), |
|
'riffle': (RiffleTask, dict(n=n)), |
|
'unriffle': (UnriffleTask, dict(n=n)), |
|
'middle-char': (MiddleCharTask, dict(n=n)), |
|
'remove-last': (RemoveLastTask, dict(n=n)), |
|
'remove-last-two': (RemoveLastTwoTask, dict(n=n)), |
|
'echo-alternating': (EchoAlternatingTask, dict(n=n)), |
|
'echo-half': (EchoHalfTask, dict(n=n)), |
|
'length': (LengthTask, dict(n=n)), |
|
'echo-second-seq': (EchoSecondSequenceTask, dict(n=n)), |
|
'echo-nth-seq': (EchoNthSequenceTask, dict(n=n)), |
|
'substring': (SubstringTask, dict(n=n)), |
|
'divide-2': (Divide2Task, dict(n=n)), |
|
'dedup': (DedupTask, dict(n=n)), |
|
'remove-target-char': (RemoveTargetCharTask, dict(n=n)), |
|
'list-index': (ListIndexTask, dict(n=n)), |
|
'fib': (FibonacciTask, dict()), |
|
'count-down': (BottlesOfBeerTask, dict()), |
|
'split': (SplitTask, dict()), |
|
'trim-left': (TrimLeftTask, dict()), |
|
'circle-route': ( |
|
JudgeRouteCircleTask, dict(n=100, max_len=32)), |
|
'multiply': (MultiplyTask, dict(n=100)), |
|
'divmod': (DivModTask, dict(n=100)), |
|
} |
|
|
|
if task_name not in task_mapping: |
|
|
|
if task_name == 'test-hill-climb': |
|
return test_tasks.BasicTaskManager(test_tasks.HillClimbingTask()) |
|
raise ValueError('Unknown task type "%s"' % task_name) |
|
task_cls, kwargs = task_mapping[task_name] |
|
|
|
if override_kwargs: |
|
if not isinstance(override_kwargs, dict): |
|
raise ValueError( |
|
'override_kwargs must be a dict, got: %s', override_kwargs) |
|
kwargs.update(override_kwargs) |
|
|
|
task = task_cls(**kwargs) |
|
|
|
reward_fn = r.absolute_distance_reward |
|
|
|
|
|
logging.info('Using reward function: %s', reward_fn.__name__) |
|
|
|
|
|
|
|
|
|
min_code_length = 0.0 if do_code_simplification else max_code_length |
|
|
|
return MultiIOTaskManager( |
|
task=task, correct_bonus=correct_bonus, |
|
code_length_bonus=code_length_bonus, |
|
max_code_length=max_code_length, min_code_length=min_code_length, |
|
reward_fn=reward_fn, require_correct_syntax=require_correct_syntax) |
|
|
|
|
|
def concat(lists): |
|
if not lists: |
|
return [] |
|
l = lists[0] |
|
for k in lists[1:]: |
|
l += k |
|
return l |
|
|
|
|
|
def concat_join(lists, sep): |
|
if not lists: |
|
return [] |
|
l = lists[0] |
|
for k in lists[1:]: |
|
l += [sep] + k |
|
return l |
|
|
|
|
|
def clipped_linear(x, x0, y0, slope, y_range): |
|
min_y, max_y = y_range |
|
return min(max(slope * (x - x0) + y0, min_y), max_y) |
|
|
|
|
|
class MultiIOTaskManager(object): |
|
"""Supports tasks which test the code with multiple I/O examples.""" |
|
|
|
def __init__(self, task, max_code_length=32, min_code_length=0, |
|
max_execution_steps=MAX_EXECUTION_STEPS, correct_bonus=1.0, |
|
code_length_bonus=1.0, failure_reward=-2.0, reward_fn=None, |
|
require_correct_syntax=False): |
|
assert isinstance(task, BaseTask) |
|
self.task = task |
|
self.max_code_length = max_code_length |
|
self.min_code_length = min_code_length |
|
self.max_execution_steps = max_execution_steps |
|
self.require_correct_syntax = require_correct_syntax |
|
self.correct_bonus = correct_bonus |
|
self.code_length_bonus = code_length_bonus |
|
self.failure_reward = failure_reward |
|
self.time_penalty = ( |
|
1.0 / (max_code_length - min_code_length) |
|
if max_code_length > min_code_length else 0.0) |
|
if reward_fn is None: |
|
self.reward_fn = r.absolute_distance_reward |
|
else: |
|
self.reward_fn = reward_fn |
|
self.input_type = ( |
|
task.input_type if hasattr(task, 'input_type') else misc.IOType.integer) |
|
self.output_type = ( |
|
task.output_type if hasattr(task, 'output_type') |
|
else misc.IOType.integer) |
|
self._compute_best_reward() |
|
|
|
def _compute_best_reward(self): |
|
io_seqs = self.task.make_io_set() |
|
reward = 0.0 |
|
for _, output_seq in io_seqs: |
|
reward += self.reward_fn(output_seq, output_seq, self.task.base) |
|
reward += self.correct_bonus |
|
reward += self.code_length_bonus |
|
self.best_reward = reward |
|
self.good_reward = 0.75 * reward |
|
logging.info('Known best reward: %.4f', self.best_reward) |
|
|
|
def _score_batch(self, code_strings): |
|
return [self._score_code(code) for code in code_strings] |
|
|
|
def _score_code(self, code): |
|
"""Run test cases on code and compute reward. |
|
|
|
Args: |
|
code: A single BF code string. |
|
|
|
Returns: |
|
misc.RewardInfo namedtuple instance containing reward and code execution |
|
information, including inputs, expected outputs, code outputs, input |
|
and output types, and reason for the reward obtained. |
|
""" |
|
|
|
|
|
io_seqs = self.task.make_io_set() |
|
terminal_reward = 0.0 |
|
results = [] |
|
reason = 'correct' |
|
for input_seq, output_seq in io_seqs: |
|
eval_result = bf.evaluate( |
|
code, input_buffer=input_seq, timeout=0.1, |
|
max_steps=self.max_execution_steps, |
|
base=self.task.base, |
|
require_correct_syntax=self.require_correct_syntax) |
|
result, success = eval_result.output, eval_result.success |
|
if not success: |
|
|
|
terminal_reward = self.failure_reward |
|
results = [] |
|
reason = eval_result.failure_reason |
|
break |
|
else: |
|
terminal_reward += self.reward_fn(result, output_seq, self.task.base) |
|
if result == output_seq: |
|
terminal_reward += self.correct_bonus |
|
|
|
|
|
|
|
|
|
if self.min_code_length == self.max_code_length: |
|
terminal_reward += self.code_length_bonus |
|
else: |
|
terminal_reward += self.code_length_bonus * clipped_linear( |
|
x=len(code), x0=self.min_code_length, y0=1.0, |
|
slope=-self.time_penalty, y_range=(0.0, 1.0)) |
|
|
|
|
|
elif reason == 'correct': |
|
reason = 'wrong' |
|
results.append(result) |
|
|
|
|
|
|
|
terminal_reward /= self.best_reward |
|
return misc.RewardInfo( |
|
episode_rewards=[0.0] * (len(code) - 1) + [terminal_reward], |
|
input_case=misc.IOTuple(i for i, o in io_seqs), |
|
correct_output=misc.IOTuple(o for i, o in io_seqs), |
|
code_output=misc.IOTuple(results), |
|
input_type=self.input_type, |
|
output_type=self.output_type, |
|
reason=reason) |
|
|
|
def rl_batch(self, batch_size): |
|
"""Produces list of reward functions. One for each program in the batch.""" |
|
return [self._score_code] * batch_size |
|
|
|
|
|
def conditional_overwrite(current_value, new_value, allowed_overwrite_values): |
|
if current_value in allowed_overwrite_values: |
|
return new_value |
|
return current_value |
|
|
|
|
|
class BaseTask(object): |
|
"""A coding task. |
|
|
|
All coding tasks should inherit this class. |
|
""" |
|
__metaclass__ = abc.ABCMeta |
|
|
|
def __init__(self, base=256): |
|
self.base = base |
|
|
|
@abc.abstractmethod |
|
def make_io_set(self): |
|
"""Generate a set of test cases for the task. |
|
|
|
Returns: |
|
List of tuples, where each tuple is (input_case, output_case). |
|
input_case and output_case are lists of integers. |
|
""" |
|
pass |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PrintTask(BaseTask): |
|
"""Print string coding task. |
|
|
|
Code needs to output a fixed string (given as a hyperparameter to the |
|
task constructor). Program input is ignored. |
|
""" |
|
|
|
def __init__(self, base, fixed_string=None): |
|
super(type(self), self).__init__() |
|
self.base = base |
|
self.eos = 0 |
|
if fixed_string: |
|
self.fixed_string = fixed_string |
|
else: |
|
self.fixed_string = [1, 2, 3, 0] |
|
self.min_length = self.max_length = len(self.fixed_string) |
|
|
|
def make_io_set(self): |
|
return [(list(), list(self.fixed_string))] |
|
|
|
|
|
class RemoveCharTaskV2(BaseTask): |
|
"""Remove character coding task (version 2). |
|
|
|
Code needs to pipe input to output, but with all the 'A' (value 1) chars |
|
removed. 'A' appears exactly once in each input. |
|
|
|
Test cases are hard-coded. |
|
""" |
|
|
|
def __init__(self, base): |
|
super(type(self), self).__init__() |
|
self.base = base |
|
self.eos = 0 |
|
self.remove_char = 1 |
|
assert base >= 27 |
|
|
|
def make_io_set(self): |
|
rm = self.remove_char |
|
return [ |
|
([rm, 0], [0]), |
|
([20, rm, 0], [20, 0]), |
|
([rm, 13, 0], [13, 0]), |
|
([6, rm, 17, 0], [6, 17, 0]), |
|
([rm, 11, 24, 0], [11, 24, 0]), |
|
([2, 16, 21, rm, 0], [2, 16, 21, 0]), |
|
([18, rm, 12, 26, 7, 0], [18, 12, 26, 7, 0]), |
|
([9, 10, 22, rm, 4, 0], [9, 10, 22, 4, 0])] |
|
|
|
|
|
class RemoveCharTask(BaseTask): |
|
"""Remove character coding task. |
|
|
|
Code needs to pipe input to output, but with all the 'A' (value 1) chars |
|
removed. 'A' appears at least once in each input. |
|
|
|
Test cases are dynamically generated, allowing for the number of test cases |
|
to be a hyperparameter. |
|
""" |
|
|
|
def __init__(self, base, n, min_len, max_len): |
|
super(type(self), self).__init__() |
|
self.base = base |
|
self.eos = 0 |
|
self.remove_char = 1 |
|
assert base >= 27 |
|
self._io_pairs = self._make_io_examples(n, min_len, max_len) |
|
|
|
def _make_io_examples(self, n, min_len, max_len): |
|
"""Generate test cases for the task.""" |
|
rand = random.Random(6849275409234) |
|
io_examples = [] |
|
for _ in xrange(n): |
|
length = rand.randrange(min_len, max_len + 1) |
|
rm_char_pos = rand.randrange(0, length) |
|
input_seq = [rand.randrange(1, self.base) for _ in xrange(length)] |
|
input_seq[rm_char_pos] = self.remove_char |
|
output_seq = list(input_seq) |
|
del output_seq[rm_char_pos] |
|
output_seq.append(0) |
|
io_examples.append((input_seq, output_seq)) |
|
return io_examples |
|
|
|
def make_io_set(self): |
|
return copy.deepcopy(self._io_pairs) |
|
|
|
|
|
class ReverseTaskV2(BaseTask): |
|
"""Reverse string coding task (version 2). |
|
|
|
Code needs to pipe input to output, but in reverse order. |
|
|
|
Stochastic test case = new test case randomly generated for every run of |
|
`make_io_set`, i.e. different test cases every time code is scored. |
|
|
|
Task supports different types of test cases: |
|
rand-one: Code is scored on one stochastic test case. |
|
rand-many: Code is scored on 5 stochastic test cases. |
|
static-bylen: Code is scored on 5 static test cases. There is one test |
|
case for string lengths 1 through 5. |
|
rand-bylen: Code is scored on 5 stochastic test cases, where there is one |
|
test case for string lengths 1 through 5. |
|
""" |
|
|
|
def __init__(self, base, reward_type): |
|
super(type(self), self).__init__() |
|
self.base = base |
|
assert base >= 27 |
|
self.eos = 0 |
|
self.io_pair_fn = { |
|
|
|
'rand-one': lambda: self._io_rand(1), |
|
|
|
'rand-many': lambda: self._io_rand(5), |
|
|
|
'static-bylen': self._io_static_by_len, |
|
|
|
'rand-bylen': self._io_rand_by_len}[reward_type] |
|
|
|
def _make_io_examples(self, sequences): |
|
outputs = [list(i) for i in sequences] |
|
for o in outputs: |
|
o.reverse() |
|
o.append(0) |
|
inputs = [i + [0] for i in sequences] |
|
return zip(inputs, outputs) |
|
|
|
def _io_rand(self, k): |
|
inputs = [(np.random.choice(26, random.randrange(1, 6)) + 1).tolist() |
|
for _ in xrange(k)] |
|
return self._make_io_examples(inputs) |
|
|
|
def _io_rand_by_len(self, k=5): |
|
inputs = [(np.random.choice(26, length) + 1).tolist() |
|
for length in xrange(1, k + 1)] |
|
return self._make_io_examples(inputs) |
|
|
|
def _io_static_by_len(self): |
|
return [ |
|
([7, 0], [7, 0]), |
|
([6, 2, 0], [2, 6, 0]), |
|
([5, 1, 10, 0], [10, 1, 5, 0]), |
|
([8, 6, 5, 15, 0], [15, 5, 6, 8, 0]), |
|
([10, 12, 5, 2, 7, 0], [7, 2, 5, 12, 10, 0])] |
|
|
|
def make_io_set(self): |
|
return self.io_pair_fn() |
|
|
|
|
|
class ReverseTask(BaseTask): |
|
"""Reverse string coding task. |
|
|
|
Code needs to pipe input to output, but in reverse order. |
|
|
|
Test cases are dynamically generated, allowing for the number of test cases |
|
to be a hyperparameter. |
|
""" |
|
|
|
def __init__(self, base, n, min_len, max_len): |
|
super(type(self), self).__init__() |
|
self.base = base |
|
assert base >= 27 |
|
self.eos = 0 |
|
self._io_pairs = self._make_io_examples(n, min_len, max_len) |
|
|
|
def _make_io_examples(self, n, min_len, max_len): |
|
"""Generate test cases for the task.""" |
|
rand = random.Random(6849275409234) |
|
io_examples = [] |
|
for _ in xrange(n): |
|
length = rand.randrange(min_len, max_len + 1) |
|
input_seq = [rand.randrange(1, self.base) for _ in xrange(length)] |
|
output_seq = list(input_seq) |
|
output_seq.reverse() |
|
output_seq.append(0) |
|
io_examples.append((input_seq, output_seq)) |
|
return io_examples |
|
|
|
def make_io_set(self): |
|
return copy.deepcopy(self._io_pairs) |
|
|
|
|
|
class CommonPrefixTask(BaseTask): |
|
"""Common prefix coding task. |
|
|
|
Code needs to output the common prefix between two input lists. Input lists |
|
are variable length, where each list ends with a 0. A common prefix is a |
|
sequence which both lists start with. |
|
""" |
|
|
|
def __init__(self, base): |
|
super(type(self), self).__init__() |
|
assert base >= 27 |
|
self.base = base |
|
self.eos = 0 |
|
|
|
def make_io_set(self): |
|
return [ |
|
([12, 24, 18, 0, 12, 5, 0], [12, 0]), |
|
([1, 2, 3, 0, 1, 2, 17, 14, 0], [1, 2, 0]), |
|
([15, 2, 1, 9, 2, 0, 15, 2, 1, 25, 8, 14, 0], [15, 2, 1, 0]), |
|
([14, 9, 7, 8, 6, 16, 0, 14, 9, 7, 8, 8, 6, 8, 26, 0], |
|
[14, 9, 7, 8, 0]), |
|
([12, 4, 16, 22, 1, 17, 0, 12, 4, 16, 22, 1, 8, 10, 0], |
|
[12, 4, 16, 22, 1, 0])] |
|
|
|
|
|
class CountCharTask(BaseTask): |
|
|
|
def __init__(self): |
|
super(type(self), self).__init__() |
|
self.base = 27 |
|
self.eos = 0 |
|
self.char = 1 |
|
self.input_type = misc.IOType.string |
|
self.output_type = misc.IOType.integer |
|
|
|
def make_io_set(self): |
|
return [ |
|
([10, 0], [0]), |
|
([1, 0], [1]), |
|
([1, 1, 0], [2]), |
|
([11, 1, 0], [1]), |
|
([1, 24, 0], [1]), |
|
([13, 6, 0], [0]), |
|
([9, 2, 7, 0], [0]), |
|
([1, 24, 11, 0], [1]), |
|
([19, 1, 1, 0], [2]), |
|
([1, 6, 1, 0], [2]), |
|
([22, 16, 17, 9, 0], [0]), |
|
([1, 1, 1, 19, 0], [3]), |
|
([1, 1, 1, 1, 0], [4]), |
|
([9, 4, 19, 11, 5, 0], [0]), |
|
([24, 11, 26, 1, 15, 0], [1]), |
|
([1, 1, 20, 1, 1, 0], [4]), |
|
([1, 1, 1, 1, 1, 0], [5])] |
|
|
|
|
|
class CountCharTaskV2(BaseTask): |
|
"""Count char coding task (version 2). |
|
|
|
Code must output the number of occurances of character 'A' (value 1) in an |
|
input string. |
|
|
|
Test cases are dynamically generated, allowing for the number of test cases |
|
to be a hyperparameter. |
|
""" |
|
|
|
def __init__(self, n, max_len): |
|
super(type(self), self).__init__() |
|
self.base = 27 |
|
self.eos = 0 |
|
self.char = 1 |
|
self.other_chars = [c for c in xrange(self.base) |
|
if c not in (self.eos, self.char)] |
|
self.input_type = misc.IOType.string |
|
self.output_type = misc.IOType.integer |
|
self._io_pairs = self._make_io_examples(n, max_len) |
|
|
|
def _make_io_examples(self, n, max_len): |
|
"""Generate test cases for the task.""" |
|
rand = random.Random(6849275409234) |
|
io_examples = [] |
|
io_examples.append(([10, 0], [0])) |
|
io_examples.append(([1, 0], [1])) |
|
io_examples.append(([1, 1, 0], [2])) |
|
io_examples.append(([9, 4, 19, 11, 5, 0], [0])) |
|
io_examples.append(([24, 11, 26, 1, 15, 0], [1])) |
|
for _ in xrange(n - 5): |
|
length = rand.randrange(2, max_len + 1) |
|
num_chars = rand.randrange(0, max_len + 1) |
|
input_seq = [self.char] * num_chars + [0] * (length - num_chars) |
|
rand.shuffle(input_seq) |
|
for i in xrange(len(input_seq)): |
|
if not input_seq[i]: |
|
input_seq[i] = self.other_chars[rand.randrange(len(self.other_chars))] |
|
output_seq = [num_chars] |
|
io_examples.append((input_seq, output_seq)) |
|
return io_examples |
|
|
|
def make_io_set(self): |
|
return copy.deepcopy(self._io_pairs) |
|
|
|
|
|
class AddTask(BaseTask): |
|
"""Addition coding task. |
|
|
|
Code needs to read in two integers and output their sum mod the BF base, |
|
followed by a terminating 0. |
|
""" |
|
|
|
def __init__(self, n=16): |
|
super(type(self), self).__init__() |
|
self.base = 256 |
|
self.input_type = misc.IOType.integer |
|
self.output_type = misc.IOType.integer |
|
self._io_pairs = self._make_io_examples(n) |
|
|
|
def _make_io_examples(self, n): |
|
"""Generate test cases for the task.""" |
|
rand = random.Random(6849275409234) |
|
io_examples = [ |
|
([4, 0], [4, 0]), |
|
([0, 5], [5, 0]), |
|
([1, 2], [3, 0]), |
|
([67, 21], [88, 0]), |
|
([55, 56], [111, 0]), |
|
([128, 33], [161, 0]), |
|
([221, 251], [216, 0]), |
|
([130, 127], [1, 0]), |
|
([255, 1], [0, 0])] |
|
extra_examples = max(n - len(io_examples), 0) |
|
for _ in xrange(extra_examples): |
|
a = rand.randrange(256) |
|
b = rand.randrange(256) |
|
input_seq = [a, b] |
|
output_seq = [(a + b) % 256, 0] |
|
io_examples.append((input_seq, output_seq)) |
|
return io_examples |
|
|
|
def make_io_set(self): |
|
return copy.deepcopy(self._io_pairs) |
|
|
|
|
|
class BooleanLogicTask(BaseTask): |
|
"""Boolean logic (truth table) coding task. |
|
|
|
Code needs to memorize a boolean truth table. Specifically, it must encode a |
|
mapping from triple of bools to a single bool. |
|
""" |
|
|
|
def __init__(self): |
|
super(type(self), self).__init__() |
|
self.base = 2 |
|
self.input_type = misc.IOType.boolean |
|
self.output_type = misc.IOType.boolean |
|
|
|
self._truth_fn = ( |
|
lambda x, y, z: |
|
(x and not z) or (not y and not z) or (not x and y and z)) |
|
self._test_cases = [ |
|
([x, y, z], [int(self._truth_fn(x, y, z))]) |
|
for x, y, z in itertools.product(range(2), range(2), range(2))] |
|
|
|
def make_io_set(self): |
|
return copy.deepcopy(self._test_cases) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def default_input_fn_factory(min_length=1, max_length=6, base=256): |
|
def _input_gen(rand): |
|
l = rand.randrange(min_length, max_length + 1) |
|
return [rand.randrange(base) for _ in xrange(l)] |
|
return _input_gen |
|
|
|
|
|
class KnownCodeBaseTask(BaseTask): |
|
"""These tasks generate their test cases from a known BF solution. |
|
|
|
This ensures that each task has a solution which is under the max character |
|
length, and that it solves the test cases under the max number of execution |
|
steps. |
|
""" |
|
|
|
def __init__(self, code_solution, make_input_fn, n=100, base=256, |
|
max_steps=5000, seed=6849275409234): |
|
super(KnownCodeBaseTask, self).__init__() |
|
|
|
assert len(code_solution) < 100 |
|
self.code_solution = code_solution |
|
self.make_input_fn = make_input_fn |
|
self.n = n |
|
self.base = base |
|
self.max_steps = max_steps |
|
self.seed = seed |
|
self._test_cases = list(self._test_case_generator(code_solution)) |
|
|
|
def _test_case_generator(self, code_solution): |
|
rand = random.Random(self.seed) |
|
for _ in xrange(self.n): |
|
input_case = self.make_input_fn(rand) |
|
result = bf.evaluate( |
|
code_solution, input_buffer=input_case, max_steps=self.max_steps, |
|
base=self.base, require_correct_syntax=False) |
|
if not result.success: |
|
raise RuntimeError( |
|
'Program must succeed. Failed on input: %s' % input_case) |
|
yield input_case, result.output |
|
|
|
def make_io_set(self): |
|
return copy.deepcopy(self._test_cases) |
|
|
|
|
|
class EchoTwiceTask(KnownCodeBaseTask): |
|
"""Echo twice.""" |
|
|
|
def __init__(self, **kwargs): |
|
super(type(self), self).__init__( |
|
'>,.[>,.]<[<]>[.>].', |
|
default_input_fn_factory(), |
|
**kwargs) |
|
|
|
|
|
class EchoThriceTask(KnownCodeBaseTask): |
|
"""Echo three times.""" |
|
|
|
def __init__(self, **kwargs): |
|
super(type(self), self).__init__( |
|
'>,.[>,.]<[<]>[.>].<[<]>[.>].', |
|
default_input_fn_factory(), |
|
**kwargs) |
|
|
|
|
|
class CopyReverseTask(KnownCodeBaseTask): |
|
"""Echo forwards, backwards, and then forwards again.""" |
|
|
|
def __init__(self, **kwargs): |
|
super(type(self), self).__init__( |
|
'>,.[>,.]<[.<].>[.>].', |
|
default_input_fn_factory(), |
|
**kwargs) |
|
|
|
|
|
class EchoZeroCascadeTask(KnownCodeBaseTask): |
|
"""Print k-th char with k zeros inbetween (1-indexed).""" |
|
|
|
def __init__(self, **kwargs): |
|
super(type(self), self).__init__( |
|
',[.>[->+>.<<]>+[-<+>]<<,]', |
|
default_input_fn_factory(), |
|
**kwargs) |
|
|
|
|
|
class EchoCascadeTask(KnownCodeBaseTask): |
|
"""Print k-th char k times (1-indexed).""" |
|
|
|
def __init__(self, **kwargs): |
|
super(type(self), self).__init__( |
|
',>>+<<[>>[-<+>]<[->+<<.>]>+<<,].', |
|
default_input_fn_factory(base=20), |
|
**kwargs) |
|
|
|
|
|
class ShiftLeftTask(KnownCodeBaseTask): |
|
"""Circulate shift input left.""" |
|
|
|
def __init__(self, **kwargs): |
|
super(type(self), self).__init__( |
|
',>,[.,]<.,.', |
|
default_input_fn_factory(), |
|
**kwargs) |
|
|
|
|
|
class ShiftRightTask(KnownCodeBaseTask): |
|
"""Circular shift input right.""" |
|
|
|
def __init__(self, **kwargs): |
|
super(type(self), self).__init__( |
|
'>,[>,]<.[-]<[<]>[.>].', |
|
default_input_fn_factory(), |
|
**kwargs) |
|
|
|
|
|
class RiffleTask(KnownCodeBaseTask): |
|
"""Shuffle like a deck of cards. |
|
|
|
For input of length N, output values in the following index order: |
|
N-1, 0, N-2, 1, N-3, 2, ... |
|
""" |
|
|
|
def __init__(self, **kwargs): |
|
super(type(self), self).__init__( |
|
'>,[>,]<[.[-]<[<]>.[-]>[>]<]', |
|
default_input_fn_factory(base=20, max_length=8), |
|
**kwargs) |
|
|
|
|
|
class UnriffleTask(KnownCodeBaseTask): |
|
"""Inverse of riffle.""" |
|
|
|
def __init__(self, **kwargs): |
|
super(type(self), self).__init__( |
|
'>,[>,[.[-]],]<[.<].', |
|
default_input_fn_factory(base=20, max_length=8), |
|
**kwargs) |
|
|
|
|
|
class MiddleCharTask(KnownCodeBaseTask): |
|
"""Print middle char if length is odd, or 0 if even.""" |
|
|
|
def __init__(self, **kwargs): |
|
super(type(self), self).__init__( |
|
'>,[>,]<<[[>]<[,<[<]>,>[>]][>]<<]>.', |
|
default_input_fn_factory(max_length=10), |
|
**kwargs) |
|
|
|
|
|
class RemoveLastTask(KnownCodeBaseTask): |
|
"""Remove last character.""" |
|
|
|
def __init__(self, **kwargs): |
|
super(type(self), self).__init__( |
|
',>,[[<.[-]>[-<+>]],].', |
|
default_input_fn_factory(base=20), |
|
**kwargs) |
|
|
|
|
|
class RemoveLastTwoTask(KnownCodeBaseTask): |
|
"""Remove last two characters.""" |
|
|
|
def __init__(self, **kwargs): |
|
super(type(self), self).__init__( |
|
',>,>,[[<<.[-]>[-<+>]>[-<+>]],].', |
|
default_input_fn_factory(base=10), |
|
**kwargs) |
|
|
|
|
|
class EchoAlternatingTask(KnownCodeBaseTask): |
|
|
|
|
|
def __init__(self, **kwargs): |
|
super(type(self), self).__init__( |
|
'>,[.,>,]<<[<]>[.>].', |
|
default_input_fn_factory(base=20, max_length=8), |
|
**kwargs) |
|
|
|
|
|
class EchoHalfTask(KnownCodeBaseTask): |
|
"""Echo only first half of the input (round down when odd lengthed).""" |
|
|
|
def __init__(self, **kwargs): |
|
super(type(self), self).__init__( |
|
'>>+>,[[<]>+[>],]<[<]>-[-[-<<+>]<[>]>]<<[->+<]>[[>]>.,<+[<]>-].', |
|
default_input_fn_factory(base=20, max_length=9), |
|
**kwargs) |
|
|
|
|
|
class LengthTask(KnownCodeBaseTask): |
|
"""Print length of the input sequence.""" |
|
|
|
def __init__(self, **kwargs): |
|
super(type(self), self).__init__( |
|
'>+>,[[<]>+[>],]<[<]>-.', |
|
default_input_fn_factory(max_length=14), |
|
**kwargs) |
|
|
|
|
|
class EchoSecondSequenceTask(KnownCodeBaseTask): |
|
"""Echo second sequence. Sequences are separated by 0.""" |
|
|
|
def __init__(self, **kwargs): |
|
def echo_second_gen(rand): |
|
l = rand.randrange(1, 6) |
|
x = [rand.randrange(256) for _ in xrange(l)] |
|
l = rand.randrange(1, 6) |
|
y = [rand.randrange(256) for _ in xrange(l)] |
|
return x + [0] + y + [0] |
|
super(type(self), self).__init__( |
|
',[,],[.,].', |
|
echo_second_gen, |
|
**kwargs) |
|
|
|
|
|
class EchoNthSequenceTask(KnownCodeBaseTask): |
|
"""Echo n-th sequence (1-indexed). Sequences are separated by 0.""" |
|
|
|
def __init__(self, **kwargs): |
|
def echo_nth_gen(rand): |
|
k = rand.randrange(1, 7) |
|
n = rand.randrange(1, k + 1) |
|
x = [] |
|
for _ in xrange(k): |
|
l = rand.randrange(0, 4) |
|
x += [rand.randrange(256) for _ in xrange(l)] + [0] |
|
return [n] + x |
|
super(type(self), self).__init__( |
|
',-[->,[,]<],[.,].', |
|
echo_nth_gen, |
|
**kwargs) |
|
|
|
|
|
class SubstringTask(KnownCodeBaseTask): |
|
"""Echo substring. |
|
|
|
First two inputs are i and l, where i is the starting index (0-indexed) |
|
and l is the length of the substring. |
|
""" |
|
|
|
def __init__(self, **kwargs): |
|
def substring_gen(rand): |
|
l = rand.randrange(2, 16) |
|
i, j = sorted([rand.randrange(l), rand.randrange(l)]) |
|
n = j - i |
|
x = [rand.randrange(256) for _ in xrange(l)] + [0] |
|
return [i, n] + x |
|
super(type(self), self).__init__( |
|
'>,<,>[->,<]>,<<[->>.,<<]', |
|
substring_gen, |
|
**kwargs) |
|
|
|
|
|
class Divide2Task(KnownCodeBaseTask): |
|
"""Divide by 2 (integer floor division).""" |
|
|
|
def __init__(self, **kwargs): |
|
def int_input_gen(rand): |
|
return [rand.randrange(256)] |
|
super(type(self), self).__init__( |
|
',[-[->>+<]>[<]<]>>.', |
|
int_input_gen, |
|
**kwargs) |
|
|
|
|
|
class DedupTask(KnownCodeBaseTask): |
|
"""Deduplicate adjacent duplicate chars.""" |
|
|
|
def __init__(self, **kwargs): |
|
def dedup_input_gen(rand): |
|
np_random = np.random.RandomState(rand.randrange(2147483647)) |
|
num_unique = rand.randrange(1, 5) |
|
unique = np_random.choice(6, num_unique, replace=False) + 1 |
|
return [v for v in unique for _ in xrange(rand.randrange(1, 5))] + [0] |
|
super(type(self), self).__init__( |
|
'>>,.[[-<+<+>>],[-<->]<[[-<->]<.>]<[->>+<<]>>]', |
|
dedup_input_gen, |
|
**kwargs) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class PrintIntTask(BaseTask): |
|
"""Print integer coding task. |
|
|
|
Code needs to output a fixed single value (given as a hyperparameter to the |
|
task constructor). Program input is ignored. |
|
""" |
|
|
|
def __init__(self, base, fixed_string): |
|
super(type(self), self).__init__() |
|
self.base = base |
|
self.eos = 0 |
|
self.fixed_string = fixed_string |
|
self.input_type = misc.IOType.integer |
|
self.output_type = misc.IOType.integer |
|
|
|
def make_io_set(self): |
|
return [(list(), list(self.fixed_string))] |
|
|
|
|
|
class EchoTask(BaseTask): |
|
"""Echo string coding task. |
|
|
|
Code needs to pipe input to putput (without any modifications). |
|
""" |
|
|
|
def __init__(self, base, min_length=1, max_length=5): |
|
super(type(self), self).__init__() |
|
self.base = base |
|
self.eos = 0 |
|
self.min_length = min_length |
|
self.max_length = max_length |
|
self._io_pairs = self._make_io_examples(25) |
|
|
|
def _make_io_examples(self, n): |
|
|
|
np_random = np.random.RandomState(1234567890) |
|
io_pairs = [] |
|
for _ in xrange(n): |
|
length = np_random.randint(self.min_length, self.max_length + 1) |
|
input_seq = np_random.randint(1, self.base, length).tolist() + [self.eos] |
|
output_seq = list(input_seq) |
|
io_pairs.append((input_seq, output_seq)) |
|
return io_pairs |
|
|
|
def make_io_set(self): |
|
return copy.deepcopy(self._io_pairs) |
|
|
|
|
|
class JudgeRouteCircleTask(BaseTask): |
|
"""Judge route circle coding task. |
|
|
|
Code needs to determine if the given route makes a closed loop. |
|
Encoding: U = 1, R = 2, D = 3, L = 4. |
|
|
|
Based on |
|
https://leetcode.com/problems/judge-route-circle/description/ |
|
""" |
|
base = 256 |
|
input_type = misc.IOType.integer |
|
output_type = misc.IOType.integer |
|
|
|
def __init__(self, n, max_len=12): |
|
super(type(self), self).__init__() |
|
self.eos = 0 |
|
self._io_pairs = self._make_io_examples(n, max_len) |
|
self.input_type = misc.IOType.integer |
|
self.output_type = misc.IOType.integer |
|
|
|
def _solve(self, input_seq): |
|
assert input_seq[-1] == 0 |
|
pos = [0, 0] |
|
for move in input_seq[:-1]: |
|
assert 0 < move <= 4 |
|
if move & 1 == 0: |
|
pos[0] += 3 - move |
|
else: |
|
pos[1] += 2 - move |
|
return [int(not pos[0] and not pos[1])] |
|
|
|
def _make_io_examples(self, n, max_len): |
|
"""Generate test cases for the task.""" |
|
rand = random.Random(6849275409234) |
|
io_examples = [] |
|
io_examples.append(([0], [1])) |
|
io_examples.append(([4, 2, 0], [1])) |
|
io_examples.append(([2, 4, 0], [1])) |
|
io_examples.append(([3, 1, 0], [1])) |
|
io_examples.append(([1, 3, 0], [1])) |
|
io_examples.append(([1, 0], [0])) |
|
io_examples.append(([2, 0], [0])) |
|
io_examples.append(([3, 0], [0])) |
|
io_examples.append(([4, 0], [0])) |
|
for _ in xrange(n): |
|
is_true = rand.randrange(2) |
|
length = rand.randrange(1, max_len + 1) |
|
if is_true: |
|
|
|
length = (length >> 1) << 1 |
|
partition = (rand.randrange(length + 1) >> 1) << 1 |
|
a = partition >> 1 |
|
b = (length - partition) >> 1 |
|
counts = {1: a, 2: b, 3: a, 4: b} |
|
else: |
|
|
|
partitions = ( |
|
[0] |
|
+ sorted([rand.randrange(length + 1) for _ in range(3)]) |
|
+ [length]) |
|
counts = {n: partitions[n] - partitions[n - 1] for n in range(1, 5)} |
|
if counts[1] == counts[3] and counts[2] == counts[4]: |
|
|
|
|
|
base = 1 + 2 * rand.randrange(2) |
|
a, b = (base, base + 1) if rand.randrange(2) else (base + 1, base) |
|
if counts[a] == length or counts[b] == 0: |
|
|
|
|
|
a, b = b, a |
|
counts[a] += 1 |
|
counts[b] -= 1 |
|
assert counts[a] <= length and counts[b] >= 0 |
|
assert sum(counts.values()) == length |
|
input_seq = [n for n in xrange(1, 5) for _ in xrange(counts[n])] |
|
rand.shuffle(input_seq) |
|
input_seq += [0] |
|
output_seq = self._solve(input_seq) |
|
assert output_seq[0] == is_true |
|
io_examples.append((input_seq, output_seq)) |
|
return io_examples |
|
|
|
def make_io_set(self): |
|
return copy.deepcopy(self._io_pairs) |
|
|
|
|
|
class MultiplyTask(BaseTask): |
|
"""Multiply coding task. |
|
|
|
Code needs to multiple two ints. |
|
|
|
Solution: |
|
http://robl.co/brief-look-at-brainfuck/ |
|
,>,><<[->[->+>+<<]>>[-<<+>>]<<<]>>. |
|
""" |
|
base = 512 |
|
input_type = misc.IOType.integer |
|
output_type = misc.IOType.integer |
|
|
|
def __init__(self, n): |
|
super(type(self), self).__init__() |
|
self.eos = 0 |
|
self._io_pairs = self._make_io_examples(n) |
|
self.input_type = misc.IOType.integer |
|
self.output_type = misc.IOType.integer |
|
|
|
def _factors(self, n): |
|
return set(i for i in range(1, int(n**0.5) + 1) if n % i == 0) |
|
|
|
def _make_io_examples(self, n): |
|
"""Generate test cases for the task.""" |
|
rand = random.Random(6849275409234) |
|
io_examples = [] |
|
for _ in xrange(n): |
|
n = rand.randrange(self.base) |
|
if n == 0: |
|
a, b = 0, rand.randrange(self.base) |
|
else: |
|
f = list(self._factors(n)) |
|
a = f[rand.randrange(len(f))] |
|
b = n // a |
|
if rand.randrange(2): |
|
a, b = b, a |
|
io_examples.append(([a, b], [n])) |
|
return io_examples |
|
|
|
def make_io_set(self): |
|
return copy.deepcopy(self._io_pairs) |
|
|
|
|
|
class DivModTask(BaseTask): |
|
"""Divmod coding task. |
|
|
|
Code needs to take the quotient and remainder of two ints. |
|
|
|
Solution: |
|
http://robl.co/brief-look-at-brainfuck/ |
|
,>,><<[>[->+>+<<]>[-<<-[>]>>>[<[-<->]<[>]>>[[-]>>+<]>-<]<<]>>>+<<[-<<+>>]<<<]> |
|
>>>>[-<<<<<+>>>>>]<<<<<.>.> |
|
""" |
|
base = 512 |
|
input_type = misc.IOType.integer |
|
output_type = misc.IOType.integer |
|
|
|
def __init__(self, n): |
|
super(type(self), self).__init__() |
|
self.eos = 0 |
|
self._io_pairs = self._make_io_examples(n) |
|
self.input_type = misc.IOType.integer |
|
self.output_type = misc.IOType.integer |
|
|
|
def _make_io_examples(self, n): |
|
rand = random.Random(6849275409234) |
|
io_examples = [] |
|
for _ in xrange(n): |
|
n = rand.randrange(0, self.base) |
|
k = rand.randrange(1, self.base) |
|
io_examples.append(([n, k], list(divmod(n, k)))) |
|
return io_examples |
|
|
|
def make_io_set(self): |
|
return copy.deepcopy(self._io_pairs) |
|
|
|
|
|
class FibonacciTask(BaseTask): |
|
|
|
def __init__(self): |
|
super(type(self), self).__init__() |
|
self.base = 256 |
|
self.input_type = misc.IOType.integer |
|
self.output_type = misc.IOType.integer |
|
|
|
def make_io_set(self): |
|
return [ |
|
([0], [0, 1]), |
|
([1], [1, 1]), |
|
([2], [1, 2]), |
|
([3], [2, 3]), |
|
([4], [3, 5]), |
|
([5], [5, 8]), |
|
([6], [8, 13]), |
|
([7], [13, 21]), |
|
([8], [21, 34]), |
|
([9], [34, 55]), |
|
([10], [55, 89]), |
|
([11], [89, 144]), |
|
([12], [144, 233]), |
|
([13], [233, 121])] |
|
|
|
|
|
class FindSubStrTask(BaseTask): |
|
"""Find sub-string coding task. |
|
|
|
Code needs to output a bool: True if the input string contains a hard-coded |
|
substring, 'AB' (values [1, 2]). |
|
""" |
|
|
|
def __init__(self, base): |
|
super(type(self), self).__init__() |
|
assert base >= 27 |
|
self.base = base |
|
self.eos = 0 |
|
self.find_str = [1, 2] |
|
self.input_type = misc.IOType.string |
|
self.output_type = misc.IOType.boolean |
|
|
|
def make_io_set(self): |
|
return [ |
|
([1, 1, 23, 0], [0]), |
|
([21, 3, 2, 0], [0]), |
|
([2, 1, 19, 0], [0]), |
|
([2, 24, 15, 3, 0], [0]), |
|
([24, 6, 10, 16, 4, 0], [0]), |
|
([1, 2, 12, 0], [1]), |
|
([7, 1, 2, 0], [1]), |
|
([1, 2, 11, 3, 0], [1]), |
|
([1, 1, 2, 18, 0], [1]), |
|
([7, 25, 1, 2, 0], [1]), |
|
([3, 1, 2, 11, 8, 0], [1]), |
|
([15, 16, 20, 1, 2, 0], [1])] |
|
|
|
|
|
class SortFixedTask(BaseTask): |
|
"""Sort list coding task. |
|
|
|
Code needs to output a sorted input list. The task consists of lists of the |
|
same length L, where L is provided to this task's constructor as a |
|
hyperparameter. |
|
""" |
|
|
|
def __init__(self, base, length=3): |
|
super(type(self), self).__init__() |
|
assert base >= 27 |
|
self.base = base |
|
self.eos = 0 |
|
self.length = length |
|
assert length == 3 |
|
|
|
def make_io_set(self): |
|
if self.length == 3: |
|
return [ |
|
([1, 20, 6], [1, 6, 20]), |
|
([13, 6, 7], [6, 7, 13]), |
|
([24, 2, 23], [2, 23, 24]), |
|
([16, 12, 3], [3, 12, 16]), |
|
([11, 24, 4], [4, 11, 24]), |
|
([10, 1, 19], [1, 10, 19])] |
|
|
|
|
|
class SortFixedTaskV2(BaseTask): |
|
"""Sort list coding task (version 2). |
|
|
|
Code needs to output a sorted input list. The task consists of lists of the |
|
same length L, where L is provided to this task's constructor as a |
|
hyperparameter. |
|
|
|
Test cases are dynamically generated, allowing for the number of test cases |
|
to be a hyperparameter. |
|
""" |
|
|
|
def __init__(self, base, n, length=3): |
|
super(type(self), self).__init__() |
|
assert base >= 27 |
|
self.base = base |
|
self.eos = 0 |
|
self._io_pairs = self._make_io_examples(n, length) |
|
self.input_type = misc.IOType.integer |
|
self.output_type = misc.IOType.integer |
|
|
|
def _make_io_examples(self, n, length): |
|
rand = random.Random(6849275409234) |
|
io_examples = [] |
|
for _ in xrange(n): |
|
input_seq = [rand.randrange(1, self.base) for _ in xrange(length)] |
|
output_seq = sorted(input_seq) |
|
io_examples.append((input_seq, output_seq)) |
|
return io_examples |
|
|
|
def make_io_set(self): |
|
return copy.deepcopy(self._io_pairs) |
|
|
|
|
|
class RemoveTargetCharTask(KnownCodeBaseTask): |
|
"""Remove target character from string, where first input is the target. |
|
|
|
Target can appear multiple times. |
|
""" |
|
|
|
def __init__(self, **kwargs): |
|
def randrange_hole(rand, a, hole, b): |
|
x = rand.randrange(a, b - 1) |
|
if x >= hole: |
|
return x + 1 |
|
return x |
|
def remove_target_char_gen(rand): |
|
char = rand.randrange(1, 6) |
|
l = rand.randrange(1, 8) |
|
input_seq = [randrange_hole(rand, 1, char, 256) for _ in xrange(l)] |
|
idx = range(l) |
|
rand.shuffle(idx) |
|
num_targets = rand.randrange(0, l) |
|
for pos in idx[:num_targets]: |
|
input_seq[pos] = char |
|
return [char] + input_seq + [0] |
|
super(type(self), self).__init__( |
|
',>>>,[<<<[->+>+<<]>>[->->+<<]>[>[-<+>]<.[-]]>[-]<<<[-<+>]>>,].', |
|
remove_target_char_gen, |
|
**kwargs) |
|
|
|
|
|
class ListIndexTask(KnownCodeBaseTask): |
|
"""Echo i-th value in the given list.""" |
|
|
|
def __init__(self, **kwargs): |
|
def array_index_gen(rand): |
|
l = rand.randrange(1, 16) |
|
i = rand.randrange(l) |
|
return [i] + [rand.randrange(256) for _ in xrange(l)] + [0] |
|
super(type(self), self).__init__( |
|
',[->,<]>,.', |
|
array_index_gen, |
|
**kwargs) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def string2tokens(string): |
|
return [ord(c) for c in string] |
|
|
|
|
|
def stringlist2tokens(strings): |
|
return [string2tokens(string) for string in strings] |
|
|
|
|
|
def string2tokens_b27(string): |
|
return [ord(c.lower()) - ord('a') + 1 for c in string] |
|
|
|
|
|
def stringlist2tokens_b27(strings): |
|
return [string2tokens_b27(string) for string in strings] |
|
|
|
|
|
class BottlesOfBeerTask(BaseTask): |
|
"""Bottles of beer coding task. |
|
|
|
This is a counting task. Code needs to read in an int N and then output |
|
every int from N to 0, each separated by a 0. |
|
""" |
|
base = 256 |
|
input_type = misc.IOType.integer |
|
output_type = misc.IOType.integer |
|
|
|
def make_io_set(self): |
|
return [ |
|
([1], [1, 0]), |
|
([2], [2, 0, 1, 0]), |
|
([3], [3, 0, 2, 0, 1, 0]), |
|
([4], [4, 0, 3, 0, 2, 0, 1, 0]), |
|
([5], [5, 0, 4, 0, 3, 0, 2, 0, 1, 0]), |
|
([6], [6, 0, 5, 0, 4, 0, 3, 0, 2, 0, 1, 0])] |
|
|
|
|
|
class SplitTask(BaseTask): |
|
"""Split coding task. |
|
|
|
Code needs to pipe input strings to output, but insert a 0 after every 3 |
|
characters. This is in essence splitting the string into intervals of length |
|
3. |
|
""" |
|
base = 28 |
|
input_type = misc.IOType.string |
|
output_type = misc.IOType.integer |
|
|
|
def _splicer(self, lst, insert, interval=3): |
|
for i, item in enumerate(lst): |
|
yield item |
|
if (i + 1) % interval == 0 and i < len(lst) - 1: |
|
yield insert |
|
|
|
def __init__(self): |
|
super(type(self), self).__init__() |
|
inputs = stringlist2tokens_b27( |
|
['hello', 'orange', 'spaghetti', 'wins', 'one']) |
|
targets = [list(self._splicer(i, 27)) for i in inputs] |
|
self._test_cases = list(zip(inputs, targets)) |
|
|
|
def make_io_set(self): |
|
return copy.deepcopy(self._test_cases) |
|
|
|
|
|
class TrimLeftTask(BaseTask): |
|
"""Trim left coding task. |
|
|
|
Code needs to pipe input strings to output, but remove everything before the |
|
first quotation char ("). |
|
""" |
|
base = 256 |
|
input_type = misc.IOType.integer |
|
output_type = misc.IOType.integer |
|
|
|
def __init__(self): |
|
super(type(self), self).__init__() |
|
inputs = stringlist2tokens( |
|
['a "inside" over', 'xy "test" rights', 'ca6 "foresting" service', |
|
'abc"def"yz.', 'A"B"']) |
|
targets = stringlist2tokens( |
|
['"inside" over', '"test" rights', '"foresting" service', '"def"yz.', |
|
'"B"']) |
|
self._test_cases = list(zip(inputs, targets)) |
|
|
|
def make_io_set(self): |
|
return copy.deepcopy(self._test_cases) |
|
|