Skip to content

Instantly share code, notes, and snippets.

@flubstep
Created April 4, 2020 23:27
Show Gist options
  • Save flubstep/2f76e1cf1e53f83d8439df8d46fdf967 to your computer and use it in GitHub Desktop.
Save flubstep/2f76e1cf1e53f83d8439df8d46fdf967 to your computer and use it in GitHub Desktop.
import sys
import logging
logging.basicConfig(filename='esab.log', filemode='w', level=logging.INFO, format='%(message)s')
def invert(b):
return 1 - b
def read_bit(b):
print(b + 1)
line = input()
logging.info(f'bits[{b}] = {line}')
return int(line)
class Chunk(object):
def __init__(self, start_index, end_index, forward_bits, reverse_bits):
self.start_index = start_index
self.end_index = end_index
self.forward_bits = forward_bits
self.reverse_bits = reverse_bits
# Pre-calculate match_index and diff_index
self.calculate_alignment_indices()
def calculate_alignment_indices(self):
self.match_index = None
self.match_value = None
self.diff_index = None
self.diff_value = None
# Get one match_index and one diff_index
zip_bits = zip(self.forward_bits, self.reverse_bits)
for index, (bit, bit_) in enumerate(zip_bits):
if bit == bit_ and self.match_index is None:
self.match_index = self.start_index + index
self.match_value = bit
if bit != bit_ and self.diff_index is None:
self.diff_index = self.start_index + index
self.diff_value = bit
def get_current_value_from_reads(self, match_index_value, diff_index_value):
is_inverted = self.match_index != None and (match_index_value != self.match_value)
is_reversed = (
(is_inverted and diff_index_value == self.diff_value) or
(not is_inverted and diff_index_value != self.diff_value)
)
ret = self.copy()
if is_inverted:
ret = ret.invert()
if is_reversed:
ret = ret.reverse()
logging.info(f'Inv: {is_inverted} Rev: {is_reversed} Aligning: {str(self)} -> {str(ret)}')
return ret
def __str__(self):
return (
''.join(str(b) for b in self.forward_bits) +
''.join(str(b) for b in reversed(self.reverse_bits))
)
def copy(self):
return Chunk(
start_index=self.start_index,
end_index=self.end_index,
forward_bits=self.forward_bits[:],
reverse_bits=self.reverse_bits[:],
)
def invert(self):
return Chunk(
start_index=self.start_index,
end_index=self.end_index,
forward_bits=[invert(b) for b in self.forward_bits],
reverse_bits=[invert(b) for b in self.reverse_bits],
)
def reverse(self):
return Chunk(
start_index=self.start_index,
end_index=self.end_index,
forward_bits=self.reverse_bits[:],
reverse_bits=self.forward_bits[:],
)
def read_chunk(start_index, end_index, num_bits):
logging.info(f'Reading chunk {start_index}:{end_index}')
forward_bits = []
reverse_bits = []
for index in range(start_index, end_index):
forward_bits.append(read_bit(index))
reverse_bits.append(read_bit(num_bits - index - 1))
return Chunk(
start_index=start_index,
end_index=end_index,
forward_bits=forward_bits,
reverse_bits=reverse_bits,
)
def align_chunk(chunk):
logging.info(f'Aligning chunk {chunk.start_index}:{chunk.end_index}')
match_index_value = None
diff_index_value = None
match_index_value = read_bit(chunk.match_index or 0)
diff_index_value = read_bit(chunk.diff_index or 0)
return chunk.get_current_value_from_reads(match_index_value, diff_index_value)
def concat_chunks(chunk1, chunk2):
# Invariant: chunk1 and chunk2 are present-aligned
logging.info(f'Concating chunks {chunk1.start_index}:{chunk2.end_index}')
if chunk1.end_index != chunk2.start_index:
raise Exception("cannot concat two non-adjacent chunks")
return Chunk(
start_index=chunk1.start_index,
end_index=chunk2.end_index,
forward_bits=chunk1.forward_bits + chunk2.forward_bits,
reverse_bits=chunk1.reverse_bits + chunk2.reverse_bits,
)
def submit_chunk(chunk):
logging.info("Final answer: " + str(chunk))
print(str(chunk))
correct = input().strip()
if correct == 'Y':
logging.info("Correct!")
return True
else:
logging.info("Nay.")
return False
def align_and_concat_chunks(chunks):
chunks = [align_chunk(c) for c in chunks]
merged = chunks[0]
for c in chunks[1:]:
merged = concat_chunks(merged, c)
return merged
def play10():
chunk = read_chunk(0, 5, 10) # 10 reads
final = align_chunk(chunk)
return submit_chunk(final)
def play20():
chunk1 = read_chunk(0, 5, 20) # 10 reads
chunk2 = read_chunk(5, 10, 20) # 10 reads
final = align_and_concat_chunks([chunk1, chunk2])
return submit_chunk(final)
def play100():
chunks = []
# 100 reads
for i in range(10):
start_index = i * 5
chunks.append(read_chunk(start_index, start_index + 5, 100))
half1 = align_and_concat_chunks(chunks[0:5]) # 10 reads
half2 = align_and_concat_chunks(chunks[5:10]) # 10 reads
final = align_and_concat_chunks([half1, half2])
return submit_chunk(final)
if __name__ == '__main__':
sol = int(sys.argv[1])
T, B = sys.stdin.readline().split()
T = int(T)
B = int(B)
for _ in range(T):
if sol == 0:
if not play10():
break
elif sol == 1:
if not play20():
break
elif sol == 2:
if not play100():
break
else:
raise Exception("Not a valid input number")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment