When we connect to the server, we receive the following :
```Rules:() + () = ()()                                      => [combine]((())) + () = ((())())                              => [absorb-right]() + ((())) = (()(()))                              => [absorb-left](())(()) + () = (())(()())                          => [combined-absorb-right]() + (())(()) = (()())(())                          => [combined-absorb-left](())(()) + ((())) = ((())(())(()))                  => [absorb-combined-right]((())) + (())(()) = ((())(())(()))                  => [absorb-combined-left]() + (()) + ((())) = (()()) + ((())) = ((()())(())) => [left-associative]
Example:(()) + () = () + (()) = (()())
Let's start with a warmup.(()(())) + (()()()) = ???```
We need to understand and implement those rules in order to answer the server'sprompts and get the flag. After some trial and error, I ended up with thefollowing script :
```pythonimport osimport socket
class Pars:
    def __init__(self, value):        self.value = value
    def __repr__(self):        return self.value
    def __eq__(self, other):        if not isinstance(other, Pars):            raise ValueError('can only compare with Pars instance')        return self.value == other.value
    def __len__(self):        # returns the "depth" of nested parentheses:        depths = []        cur_depth = 0        for char_ in self.value:            if char_ == '(':                cur_depth += 1            else:                depths.append(cur_depth)                cur_depth -= 1        return max(depths)
    def __add__(self, other):        if not isinstance(other, Pars):            raise ValueError('can only add with Pars instance')        if self == other or len(self) == len(other):            val = self.value + other.value        elif (len(self) < len(other) and not other.is_combined()) or self.is_combined():  # absorb left            val = f'({self.value}{other.value[1:]}'        else:  # absorb right            val = f'{self.value[:-1]}{other.value})'        return Pars(val)
    def is_combined(self):        half1 = self.value[:len(self.value)//2]        half2 = self.value[len(self.value)//2:]        return half1 == half2
def solve(query):    operands = [Pars(o.strip()) for o in query.split('+')]    while len(operands) > 1:        left = operands.pop(0)        right = operands.pop(0)        operands.insert(0, left + right)    return operands[0]
def netsolve(timeout=5.0):    import socket    hostname = '2018shell3.picoctf.com'    port = 61344    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)    s.connect((hostname, port))    s.settimeout(timeout)
    databuf = b''    while 1:        data = s.recv(1024)        databuf += data        if b'>' in databuf:            break    datastring = databuf.decode('ascii')    send_solution(s, datastring)
    s.shutdown(socket.SHUT_WR)    s.close()
def send_solution(sock, datastring):    for line in datastring.split('\n'):        if '= ???' in line:            query = line.split('=')[0]            solution = solve(query)            sock.sendall((str(solution) + '\n').encode('ascii'))            databuf = b''            while 1:                data = sock.recv(1024)                databuf += data                if b'>' in databuf:                    break                elif b'picoCTF{' in databuf:                    exit(databuf.decode('ascii'))            ds = databuf.decode('ascii')            send_solution(sock, ds)
if __name__ == '__main__':    netsolve()
```
This is using a class and python "magic methods" to overload the `+` and `=`operators as well the `len()` function. If we run the script, we get our flag :`picoCTF{5cr1pt1nG_l1k3_4_pRo_cde4078d}`.