From 5a532e0ddf0bdfcfbb68c03d51fced01968f8055 Mon Sep 17 00:00:00 2001 From: Leonid Belyaev Date: Fri, 3 Dec 2021 10:46:50 -0500 Subject: [PATCH] class refactor --- code/bot/__pycache__/game.cpython-39.pyc | Bin 2443 -> 5534 bytes code/bot/game.py | 173 +++++++++++++++-------- code/bot/tests.py | 20 +-- 3 files changed, 116 insertions(+), 77 deletions(-) diff --git a/code/bot/__pycache__/game.cpython-39.pyc b/code/bot/__pycache__/game.cpython-39.pyc index 0e2109288f4342111cf6988a41b9b72dbed1c750..b841025547a48c2839daa5a31eed6eac2bda991e 100644 GIT binary patch literal 5534 zcmcIoO>ZPe8LsND>FN1c$MM?U&1Td2-hs_}6BZIkKuH#7KeBN`yb@6p)EQ5;$KxGO z+tux?$Lc;H2Z<90q+CFV%>`-U4guPS z_kEw9cBA1jTz`M{5ADtKjQx`;(^mzR*KsF*Mk1KteHQ4P2V59|Ad9f z_NiPC!-KVltRNR4ys#LOG1m({Zd#+o=HYeTb6y*V9! zt5!I&JrMC;;Q-cNCn}uxZmnNm-z;pjccY^A=AAb--VX1)@#gxS!fEgCM*~sV>EV7q zD$IT~DC*a5uCH&dk4Dszo!)jD?)M@rRlB|uMMU_zNYZ%ud zTPrW(5|K?&=OzjuikY$$-8HzpSMVeG4H{?n+gnjTP@P*a-g|S9$)_>uHtwX3gc%lJ04j^XL-lm1 zarz>Ty^cG%ie%Pf2ot{467ciL;ps&Mxg%UrMP3me-nu5~ERG+WqR|WfUVG?o;l2C) zsN3#$2=DTuGCfh@zl;KmkA*BVkira+8iEm;8*o-mdjQ5ug^z4uFg%o%MEz~~GAfhi zIRway^#;8(41bJa2{~@Y9sG`$rnY&d95llZa@1pfdyhD>O3Txr?* zt?2mls}ZvLwJY)!D!)j{OGpA&PY;jArD5O^T}Fs~i$;#Uvo@s~J$N+WL-Z%)Vwm9> z#E;{ZX=tWKb||8h7dhRrfJUPK993cYL8`fWyUX)t6ar9Q-=C{Rz)LBeyp(iy(FDG0K^4}gKBvSeME(5zc4WB zo0uTK;w%bV1((9!>c{`()X1ct1WRa3bDfuoX-=pMJO4ccvSdc1FL{k3lE((esq*+|s#iiP3TwMc$$ek!Q ze2zj!j>O7su)gHz9pRh%HsV;O2WZiQlV^95W)#^YSShK zZBy!$->2pSOV8AOTCZfDU|H?wV3D9u2JIqDs;%gmmeMd=Y8Re*`t8h0;nYr)a+#FD z2z#VbzK_?^T2^twnc{#7aQM7nl0vo)b&bMSK|E-5+j6VjjY1vF##KcD`8-V+8*$*0 zV*x+UqBMn%2l8&g<$|s3%ZG;b_9oFgCe>gmD)EatTu5JgBn( z*|5wnfI4*wmp9PgpBWZPr+cL$ZR-h_n<4vl9ZFqm*?WZ_0`;G`{BskZG!C_(Fi z4NHR#Rrp?pQ*<(m@CBw&e&?{JmVX2+Ol*Q5?Y3x2Xf|?wBeA4h-b6__@>yEoIZ6n= zLWKl9LtCrzd=pkHWSU+23V=`v6>y(oVnPa=DIB!KTHx|FT4vB7@jmu;N2p{R{Koqe z76<@}>lyEIV!Kf8AKpvr>k1@RMFj~ruY$L3X01X;XZ9-8L0-%2Sxw2UdS-qMaZldFBEQ3(khcNlKrRPfi&Po?RR2sMA^$Xn_LrzA z*Fk{<;Y2}8dPJ20uRVenG*j^2%^mIfpN8n&1omapH{`B}st>0>QndLK>JJy>Tgav@cMQ8bDt$ey@@<++ zR;ACV1bL=5l<&}}4NB%{T$3?<#Ug%hr+-9$Lj4+SZv?gmT>c2{GjNl{p<8)sQh)02 z1LOGSJ5Wr1x)b@GLn&c+TB`XXzCZBsA=K;pz0~it2hXQ|H`dMV!Ei5@(Pf%8@F|pG z%!b-*i)(!5HeTInOA!hg@BaypPL#tj$n@826H~0(fi*R9Zka83G%+CJrYz0?qO9)v18(ZbO z*syX7@;xfe!CxQoM)tZp>0dG6>xpxB{>>@8j{^c}#_~*HkrbLsi@Zs~k5n!!5&{7B zX$b?`_X7k~*pwD_(8M1gnCo^30Z2D|g$fgzco~}5f+k)THp#K$pKKD<{a#XjW05!} zo~o}!YX1tQ?D@EE#L&z>Xf4(FG~TDtgBVnax6}xw?j}J9(%P6rb%dl@6aOkDH;1s& zQ~w}fiM7mfl{H?48&o}z=ky&YS12JBAy<)X;Hl&0)~X7Gh1H4ohehRXsQ&*5DtF4l z?XvK0S=cNKL0Pz^3z7n<`Yw>9BGn&G>Td$|b*xmJ3j8YGDbK9@g|bIQeMv0P8garT xRZ`K^eNF#u_5-rlgha^#6vougShP?xn-%t@x8{1y7u+S!bL(ycI?{0){{gdxf)xM& literal 2443 zcmZWr%Z?jG6s@X$y8W2R#LCQs0EQ5VLlTE50u~Vp3Ly$YBSf-lCA2)QwqwQP_Eh%} zJE~qeY>|)<>&XTwJHCJq=`E}I0;Fu<+-iGXDXDKgZoT@Pdrx<_UJn?`rQd(+{##+} zAL<-07CLwEq+2kONj_pBlOp6XAMjAzXVQ}POD65P2rcPI_azH$=}8~8BhSdHti9x+ zE95l^njRn)%Z4_SNd0DH2nw$m1hqh(CnGS$Iy>piAuId@lGqvx>>vvkF!=k zQLSz(GqbLZhR@>G0CTt6cHu|S7|kduf+*Tay8#4FN$Q+i=x*|5!S}M zxz%}^?8Kc>oQ#LEllGn_$*9vyZ+&*-MyIzo%2a~kULxbpc9M1Ixa*UdaKkigUKx%(xVp(0tD4 z|5I3M2Kkb7qQ87Wu0j=qCIKT zNZG&5c5iA6XEbpGTRPfVXVP6~U$ETX{X^Rz#M>&Eq8BVVCi>rS{X*yfT)ExJBp%Dc zQQh$%F04^JZU=>9xGJ2&r@M*zkg){1I$D<=AR2BOd zHM7CZ6mc*foW)4G0mC?9Y{S<08gKBA_!YF*xOxY^9$j%+YG`+R>gC>ui%57A_p0SFSK@^mAWZ;DFPZ)N; zX4bx4t}K0X{)*>S9e{}{;VyB44s=yoB@1Sy{UysQyW8d#fjRvl=e$oz;cOZ3 z-|$wMe)O(wS5fRK$|BW(DO`{slbymv_znTQlkH7Lal59@z#G;FUA5gE#F0V#sM|~S z##tCVO^_?5t=4EqLOt}y@$-o2Q|oj9AB0|(L^L(5F1G`ni`B!ijHho?iTH>XlRw8U z>3JAXDQw>4O>rKCt_q)@;}>`UV$}!m9#GmGG+}xaZ_7f7L^)?@{T_{s?IRHYu+Y%L z^8mLmax1g6(AHd-B(pP{5(zY~QHbw5($cJ1QhZg5%+>Y+WP9u2NZT%8_qM0rMWx<@ zDcm0(+`D`4VbM^C>2VgT$V7L^0l}}{rzLJ!okns9ol1wvIIPZ&ItJGwAV|v{4904c z)*dQR8UKwzJdPFgE;5Pm08>&rgBgedKvv_cTwTV<34kad4%KFgj^XTCjB6d`4%|IQpY96&js6gp@U;v_AAEHthsa-KC8G4T* zlaJ~Wc}Nq?N5F`ONejc2qUFak8RkdCcWmK04couypA9O0^?%bR B1e*W= diff --git a/code/bot/game.py b/code/bot/game.py index 77acbcd..8ba2994 100644 --- a/code/bot/game.py +++ b/code/bot/game.py @@ -1,78 +1,127 @@ #!/usr/bin/env python3 -import random +import random, copy -T_PIECE = ((0, 0), (0, -1, "b"), (-1, 0, "b"), (0, 0, "b"), (1, 0, "b")) -L_PIECE = ((0, 0), (0, 0, "b"), (1, 0, "b"), (0, -1, "b"), (0, -2, "b")) -J_PIECE = ((0, 0), (0, 0, "b"), (-1, 0, "b"), (0, -1, "b"), (0, -2, "b")) -O_PIECE = ((0, 0), (0, 0, "b"), (1, 0, "b"), (0, -1, "b"), (1, -1, "b")) -S_PIECE = ((0, 0), (0, 0, "b"), (-1, 0, "b"), (0, -1, "b"), (1, -1, "b")) -Z_PIECE = ((0, 0), (0, 0, "b"), (-1, 0, "b"), (0, -1, "b"), (1, -1, "b")) -I_PIECE = ((0, 0), (0, 0, "b"), (0, -1, "b"), (0, -2, "b"), (0, -3, "b")) +T_PIECE = ((0, -1, "b"), (-1, 0, "b"), (0, 0, "b"), (1, 0, "b")) +L_PIECE = ((0, 0, "b"), (1, 0, "b"), (0, -1, "b"), (0, -2, "b")) +J_PIECE = ((0, 0, "b"), (-1, 0, "b"), (0, -1, "b"), (0, -2, "b")) +O_PIECE = ((0, 0, "b"), (1, 0, "b"), (0, -1, "b"), (1, -1, "b")) +S_PIECE = ((0, 0, "b"), (-1, 0, "b"), (0, -1, "b"), (1, -1, "b")) +Z_PIECE = ((0, 0, "b"), (-1, 0, "b"), (0, -1, "b"), (1, -1, "b")) +I_PIECE = ((0, 0, "b"), (0, -1, "b"), (0, -2, "b"), (0, -3, "b")) PIECES = [T_PIECE, L_PIECE, J_PIECE, O_PIECE, S_PIECE, Z_PIECE, I_PIECE] # TODO set up gamestate/successor +# +BLANK_LABEL = "_" +CHEESE_LABEL = "c" -class TetrisGame: - """A problem statement for a tetris-like game""" + +class TetrisState: + """Generic state""" pass -class CheeseGame(TetrisGame): - def get_successors(state): - """ - You can: - + Move down - + Move right - + Move left - + Rotate - Each is "one state". - """ - piece, grid = state - center_x, center_y = piece[0] - # compute all states: only return valid ones - go_down_state = (recenter_piece(piece, (center_x, center_y - 1)), grid) - go_right_state = (recenter_piece(piece, (center_x + 1, center_y)), grid) - go_left_state = (recenter_piece(piece, (center_x - 1, center_y)), grid) - rotate_left_state = rotate_left(state) - rotate_right_state = rotate_right(state) - # TODO: "lock in state" - # TODO: "hard drop" state - states = [ - go_down_state, - go_right_state, - go_left_state, - rotate_left_state, - rotate_right_state, - ] - return list(filter(is_legal), states) - - def get_initial_state(self): - return send_garbage(generate_state(), "c", 9, 1) - - def is_terminal(state): - piece, grid = state - return grid[len(grid) - 1][0] != "c" - - -"Note: It might not be a bad idea to have the state/grid as an object" "We would just have to have it be immutable after initalization and we could use it like tuples " "(and have all functions which change it just retrun the succesor object without mutation)" "It may be more effor than it's worth but that way if we need to make any changes it won't have" "to be so hard coded" - - -def state2string(state): - piece, grid = state - rep = [] - st = "" - for row in grid: - rep.append(row) - for i in range(1, len(piece)): +def new_cheese_state( + x_dimension=10, y_dimension=20, hole_count=1, cheese_count=9, piece=None +): + # TODO init garbage - 9 rows of 1 hole + + if piece is None: + piece = random.choice(PIECES) + grid = [] + for y in range(y_dimension): + row = [BLANK_LABEL] * x_dimension + grid.append(tuple(row)) + + for g in range(y_dimension - cheese_count, len(grid)): + to_hole = hole_count + cheese_row = [CHEESE_LABEL] * x_dimension + + while to_hole != 0: + hole_index = random.choice(range(x_dimension)) + cheese_row[hole_index] = BLANK_LABEL + to_hole -= 1 + grid[g] = tuple(cheese_row) + + grid = tuple(grid) + spawn = (x_dimension // 2, 0) + mapped_piece = shift_piece(piece, spawn[0], spawn[1]) + + return CheeseState(spawn, mapped_piece, grid) + + # piece, grid = state + + # new_grid = [] + # for i in range(len(grid) - garbage_count): + # new_grid.append(grid[i + garbage_count]) + + # for g in range(len(grid) - garbage_count, len(grid)): + # to_hole = hole_count + # garbage_row = garbage_label * len(grid[0]) + + # while to_hole != 0: + # hole_index = random.choice(range(len(grid[0]))) + # garbage_row = garbage_row[:hole_index] + " " + garbage_row[hole_index:-1] + # to_hole -= 1 + # new_grid.append(garbage_row) + # new_state = (piece, tuple(new_grid)) + # return (piece, tuple(new_grid)) + + +def shift_piece(piece, x_shift, y_shift): + """Shift every coordinate in piece""" + new_piece = [] + for i in range(len(piece)): x, y, label = piece[i] - if x in range(len(grid[0])) and y in range(len(grid)): - rep[y] = rep[y][:x] + label + rep[y][x:-1] - for row in rep: - st += "|" + row + "|\n" - return st + new_brick = (x + x_shift, y + y_shift, label) + new_piece.append(new_brick) + return tuple(new_piece) + + +class CheeseState: + """CheeseState- may be illegal""" + + def __init__(self, anchor, piece, grid): + self.anchor = anchor # one position + self.piece = piece # list of positions + self.grid = grid # list of list of one-char strings + + def move_anchor(self, x_shift, y_shift): + """Return a new state with moved anchor and piece.""" + anchor_x, anchor_y = self.anchor + # tuple addition? + new_anchor = (anchor_x + x_shift, anchor_y + y_shift) + new_piece = shift_piece(self.piece, x_shift, y_shift) + return CheeseState(new_anchor, new_piece, self.grid) + + def is_legal(self): + """Illegal if oob or intersecting""" + for i in range(len(self.piece)): + x, y, label = self.piece[i] + if x < 0 or x >= len(self.grid[0]) or y < 0 or grid[y][x] != BLANK_LABEL: + return False + return True + + def __repr__(self): + rep = [] + st = "" + + for row in self.grid: + rep.append(list(row)) + for i in range(len(self.piece)): + x, y, label = self.piece[i] + if x in range(len(self.grid[0])) and y in range(len(self.grid)): + rep[y][x] = label + count = 0 + for row in rep: + for block in row: + st += block + st += f" {count}\n" + count += 1 + return st def send_garbage(state, garbage_label, garbage_count, hole_count): diff --git a/code/bot/tests.py b/code/bot/tests.py index 4bd4965..e01abc3 100644 --- a/code/bot/tests.py +++ b/code/bot/tests.py @@ -3,23 +3,13 @@ import unittest import game -class TestState(unittest.TestCase): - +class TestState(unittest.TestCase): def test_repr(self): - state = game.generate_state() - print("Behold a tetris state:") - print(game.state2string(state)) - state = game.rotate_right(state) - print("Behold a rotation:") - print(game.state2string(state)) - state = game.send_garbage(state, "c", 9, 3) - print("Behold some trash:") - print(game.state2string(state)) - - - - + state = game.new_cheese_state(piece=game.T_PIECE) + print(state) + state = state.move_anchor(0, 1) + print(state) if __name__ == "__main__":