-
Notifications
You must be signed in to change notification settings - Fork 0
/
per.py
355 lines (288 loc) · 11.8 KB
/
per.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Solve the 2048 puzzle without using any look ahead
# ie no wondering what it would be like to make a particular move
# especially we do not want to virtually take moves and then select the best move based on the virtual results
# the approach we want is similar to a closed form solution, but is actually rule based
from __future__ import print_function
import time
import os
def print_board(m):
for row in m:
for c in row:
print('%8d' % c, end=' ')
print()
def movename(move):
return ['up', 'down', 'left', 'right'][move]
def col(l, c):
return [l[r][c] for r in 0, 1, 2, 3]
def transpose(board):
return [col(board, r) for r in 3, 2, 1, 0]
ROW3, ROW2, ROW1, ROW0 = 3, 2, 1, 0
COL3, COL2, COL1, COL0 = 7, 6, 5, 4
def match(i1, i2):
return any(map(lambda ( x, y ): ( x ) and ( x == y ), zip(i1, i2)))
class BoardEvaluator(object):
def __init__(self, board):
"""
:rtype : BoardEvaluator
"""
self.b = board
def set_board(self, board):
self.b = board
def get_board( self, board ):
return self.b
def equals( self, board ):
return ( self.b == board )
def print_board( self ):
print_board( self.b )
# fence fixer jose ramirez cib construction 310 384 9352
def get(self, selector):
d = {
ROW0: self.b[0],
ROW1: self.b[1],
ROW2: self.b[2],
ROW3: self.b[3],
COL0: col(self.b, 0),
COL1: col(self.b, 1),
COL2: col(self.b, 2),
COL3: col(self.b, 3)
}
return d[selector]
def is_full(self, selector):
# temp = self.get( selector )
# print ( "@@@@ ", temp, all( temp ) )
return all(self.get(selector))
def num_open(self):
return sum(map(lambda i: sum(map(lambda x: not x, i)), self.b))
def is_compressible(self, selector):
test = self.get(selector)
return match(test[0:3], test[1:4])
# highfalutin way of saying
# return ( ( test[0] == test[1] ) or ( test[1] == test[2] ) or ( test[2] == test[3] ) )
# yes! I wrote this comment just to use "highfalutin". highfalutin, highfalutin, highfalutin
def is_sorted(self, selector):
test = self.get(selector)
return sorted(test) == test
def first_empty(self, selector):
test = self.get(selector)
return ( not ( test[0] ) )
def br_is_biggest(self):
br = self.b[3][3]
biggest = max(map(max, self.b))
return br == biggest
# needs a lot more tests
def lap_helper(self, index):
this_row = index
next_row = ( index + 1 )
return ( ( self.is_full(next_row) ) and
( ( not self.is_compressible(next_row) ) and ( not self.is_compressible(this_row) ) ) and
(
( not ( any(self.b[this_row][0:1]) ) and match(self.b[next_row][0:3], self.b[this_row][1:4]) ) or
( not ( any(self.b[this_row][0:2]) ) and match(self.b[next_row][0:2], self.b[this_row][2:4]) ) or
( not ( any(self.b[this_row][0:3]) ) and match(self.b[next_row][0:1], self.b[this_row][3:4]) )
)
)
def left_align_opp(self):
return (
self.lap_helper(ROW2) or
( self.is_full(ROW3) and ( not self.is_compressible(ROW3) ) and self.lap_helper(ROW1) ) or
(self.is_full(ROW3) and ( not self.is_compressible(ROW3) ) and self.is_full(ROW2) and (
not self.is_compressible(ROW2) ) and self.lap_helper(ROW0) )
)
def rao_helper(self, index):
this_row = index
next_row = ( index + 1 )
return (( self.is_full(next_row) ) and ( not self.is_compressible(next_row) ) and (
not self.is_compressible(this_row) ) and
(
( not ( any(self.b[this_row][3:4]) ) and match(self.b[this_row][0:3], self.b[next_row][1:4]) ) or
( not ( any(self.b[this_row][2:4]) ) and match(self.b[this_row][0:2], self.b[next_row][2:4]) ) or
( not ( any(self.b[this_row][1:4]) ) and match(self.b[this_row][0:1], self.b[next_row][3:4]) )
)
)
def right_align_opp(self):
return (
self.rao_helper(ROW2) or
( self.is_full(ROW3) and ( not self.is_compressible(ROW3) ) and self.rao_helper(ROW1) ) or
(self.is_full(ROW3) and ( not self.is_compressible(ROW3) ) and self.is_full(ROW2) and (
not self.is_compressible(ROW2) ) and self.rao_helper(ROW0) )
)
def up_align_opp(self):
temp = self.b
self.set_board(transpose(self.b))
uao = self.left_align_opp()
self.set_board(temp)
return uao
def down_align_opp(self):
temp = self.b
self.set_board(transpose(self.b))
rao = self.right_align_opp()
self.set_board(temp)
return rao
def align_opp(self, direction):
opp = [self.up_align_opp, self.down_align_opp, self.left_align_opp, self.right_align_opp][direction]
return opp()
def rungame(args):
from gamectrl import BrowserRemoteControl, Fast2048Control
if len(args) == 1:
port = int(args[0])
else:
port = 32000
ctrl = BrowserRemoteControl(port)
# Use Keyboard2048Control if Fast2048Control doesn't seem to be working.
gamectrl = Fast2048Control(ctrl)
board0 = gamectrl.get_board()
be = BoardEvaluator(board0)
moveno = 0
UP, DOWN, LEFT, RIGHT = 0, 1, 2, 3
def go(direction):
gamectrl.execute_move(direction)
be.set_board( gamectrl.get_board() )
def go_left():
go(LEFT)
def go_right():
go(RIGHT)
def go_up():
go(UP)
def go_down():
go(DOWN)
def flip(direction):
return [DOWN, UP, RIGHT, LEFT][direction]
if gamectrl.get_status() == 'ended':
gamectrl.restart_game()
moveno = 0
start = time.time()
br = False
bd = False
second_dir = RIGHT
while ( not ( gamectrl.get_status() in [ 'ended' , 'won' ] ) ):
inv_count = 0
flip_count = 0
while True:
board0 = gamectrl.get_board()
go_down()
if ( be.equals( board0 ) ):
bd = True
print(" down has no effect ")
# must come in handy when the board is full
if ( be.is_full(ROW3) and be.is_full(ROW2) and be.is_full(ROW1) ):
print(" rows 321 are full ")
flip_dir = flip( second_dir )
if be.align_opp(flip_dir):
print("F align opp for ", movename(flip_dir) )
be.print_board()
go(flip_dir)
be.print_board()
continue
if be.align_opp(second_dir):
print("align opp for ", movename(( second_dir )))
be.print_board()
go(second_dir)
be.print_board()
continue
# be.set_board(board1)
if ( be.is_compressible(ROW3) ): # or ( not be.br_is_biggest() ) ):
print("row3 is compressible, so second_dir is RIGHT ")
second_dir = RIGHT
else:
flip_dir = flip( second_dir )
if be.align_opp(flip_dir):
print("row3 is NOT compressible, and align opp for ", movename(flip_dir) )
go(flip_dir)
continue
board1 = gamectrl.get_board()
go(second_dir)
if ( be.equals( board1 ) ):
br = True
print( movename( second_dir ), " has no effect " )
board2 = gamectrl.get_board()
if be.align_opp(flip(second_dir)):
print("AO case 3: align_opp for ", flip( second_dir ) )
go(flip(second_dir))
continue
if board0 == board2:
inv_count += 1
if ( inv_count > 2 ):
print("=============")
print_board(board0)
print(" inv_count = ", inv_count, "flip_count = ", flip_count)
if ( be.is_full(ROW3) and ( not be.is_compressible(ROW3) ) ):
second_dir = flip(second_dir)
inv_count = 0
flip_count += 1
if ( ( flip_count > 5 ) or ( gamectrl.get_status() in ['ended', 'won'] ) ):
print("flip_count > 5 or game finished ")
break
else:
print("row3 not full or not compressible")
break
if ( be.num_open() < 3 ):
print(" less than 3 open squares ")
break
else:
print(" Number of open squares : ", be.num_open())
# if ( all ( board2[3] ) ):
if ( be.is_full(ROW3) and ( not be.is_compressible(ROW3) ) ):
print(" DR did not work, Bottom row full and not compressible, so going left ")
# time.sleep( 3 )
go(flip(second_dir))
boardx = gamectrl.get_board()
if ( board2 == boardx ):
print(
" <><><><><><><><><><><><><><><><><><><><><><><><><><><><> Hail Mary move: left failed, goin right")
go(second_dir)
boardx = gamectrl.get_board()
if ( board2 == boardx ):
print(
" #$%#$%@#$%@#$%@#$%@#$%@#$%@#$%@#$%@#$%@#$%@#$%@#$%@#$%@#$%@#$%@$#%@#$ Hail Mary move: left and right failed, goinup ")
go_up()
continue
elif ( ( be.is_full(COL3) and ( not be.is_compressible(COL3) ) ) ):
print(" DR did not work, Bottom row not full but Right col full and not compressible ")
if ( be.up_align_opp() ):
print(" BR not full but Roght Col full and I smell a up opp ")
# time.sleep( 3 )
go_up()
go_right()
continue
elif ( be.left_align_opp() ):
print(" BR not full but Roght Col full and I smell a left opp ")
# time.sleep( 3 )
go_left()
go_right()
continue
else:
print(" BR not full but Roght Col full and I DO NOT smell a up opp but moving up any way")
# time.sleep( 3 )
go_up()
# what if this fails? [ e.g. only the left most col is empty ]
continue
else:
if ( be.num_open() < 3 ):
print("all attempts failed and less than 3 open squares ")
# break
board0 = gamectrl.get_board()
print(
" <><><><><><><><><><><><><><><><><><><><><><><><><><><><> the real Hail Hanuman move: Try left first ")
go_left()
board1 = gamectrl.get_board()
if ( board0 == board1 ):
go_up()
print("case 6 " + movename(UP))
board3 = gamectrl.get_board()
if ( push_right_opp(board3) ):
go_right()
print("case 6+ " + movename(RIGHT))
else:
go_right()
score = gamectrl.get_score()
board = gamectrl.get_board()
maxval = max(max(row) for row in board )
moveno = gamectrl.moveno
print("Game over. Final score %d; highest tile %d." % (score, 2 ** maxval))
print("%010.6f: Score %d, Move %d, mps= %010.6f" % (
time.time() - start, gamectrl.get_score(), moveno, ( moveno / ( time.time() - start) ) ))
if __name__ == '__main__':
import sys
rungame(sys.argv[1:])