Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
E
exapunks-hackmatch-bot
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Taddeüs Kroes
exapunks-hackmatch-bot
Commits
cfb67915
Commit
cfb67915
authored
Apr 03, 2020
by
Taddeüs Kroes
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Write parser for game state
parents
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
180 additions
and
0 deletions
+180
-0
.gitignore
.gitignore
+2
-0
parser.py
parser.py
+178
-0
No files found.
.gitignore
0 → 100644
View file @
cfb67915
__pycache__
*.swp
parser.py
0 → 100755
View file @
cfb67915
#!/usr/bin/env python3
import
os
import
time
import
numpy
as
np
from
Xlib
import
display
,
X
from
PIL
import
Image
COLUMNS
=
7
WINDOW_WIDTH
=
1600
WINDOW_HEIGHT
=
900
BLOCK_SIZE
=
60
BOARD_X
=
367
BOARD_Y
=
129
BOARD_WIDTH
=
COLUMNS
*
BLOCK_SIZE
BOARD_HEIGHT
=
638
MAX_COLUMN_HEIGHT
=
546
DETECT_COLUMN_OFFSET_X
=
8
,
50
DETECT_COLUMN_OFFSET_Y
=
-
11
MIN_COLUMN_SAT
=
130
MIN_COLUMN_VAL
=
120
COLUMN_VSHIFT
=
[
-
2
,
-
2
,
-
1
,
-
1
,
0
,
0
,
0
]
RED
,
PINK
,
GREEN
,
BLUE
,
YELLOW
,
NONE
=
range
(
6
)
BOMB_OFFSET
=
NONE
+
1
BASIC_HUES
=
[
248
,
224
,
118
,
158
,
26
]
BOMB_HUES
=
[
250
,
219
,
131
,
174
,
38
]
HUE_TOLERANCE
=
5
DETECT_BASIC_X
=
9
DETECT_BASIC_Y
=
15
DETECT_BOMB_X
=
25
DETECT_BOMB_Y
=
44
MIN_BASIC_SAT
=
180
DETECT_EXA_X
=
30
DETECT_EXA_Y
=
547
EXA_HUE
=
129
EXA_MIN_VAL
=
240
DETECT_HELD_Y
=
579
DETECT_EXA_LIGHT_X
=
30
DETECT_EXA_LIGHT_Y
=
609
EXA_LIGHT_HUE
=
226
MIN_EXA_LIGHT_VAL
=
180
def
is_hue
(
h
,
hexpect
):
return
abs
(
h
-
hexpect
)
<=
HUE_TOLERANCE
def
find_window
(
name
):
def
traverse
(
window
):
if
window
.
get_wm_name
()
==
name
:
return
window
for
child
in
window
.
query_tree
().
children
:
win
=
traverse
(
child
)
if
win
:
return
win
return
traverse
(
display
.
Display
().
screen
().
root
)
def
get_exapunks_window
():
win
=
find_window
(
'EXAPUNKS'
)
assert
win
,
'EXAPUNKS window not found'
geo
=
win
.
get_geometry
()
assert
geo
.
width
==
WINDOW_WIDTH
assert
geo
.
height
==
WINDOW_HEIGHT
return
win
def
focus_window
(
window
):
window
.
set_input_focus
(
X
.
RevertToNone
,
X
.
CurrentTime
)
window
.
raise_window
()
display
.
Display
().
sync
()
def
screenshot_board
(
window
):
start
=
time
.
time
()
raw
=
window
.
get_image
(
BOARD_X
,
BOARD_Y
,
BOARD_WIDTH
,
BOARD_HEIGHT
,
X
.
ZPixmap
,
0xffffffff
)
dim
=
BOARD_WIDTH
,
BOARD_HEIGHT
im
=
Image
.
frombytes
(
'RGB'
,
dim
,
raw
.
data
,
'raw'
,
'BGRX'
)
return
im
.
convert
(
'HSV'
)
def
detect_columns
(
board
):
def
saturated
(
x
,
y
):
h
,
s
,
v
=
board
.
getpixel
((
x
,
y
))
return
s
>
MIN_COLUMN_SAT
and
v
>
MIN_COLUMN_VAL
a
,
b
=
DETECT_COLUMN_OFFSET_X
for
y
in
range
(
MAX_COLUMN_HEIGHT
,
BLOCK_SIZE
,
-
1
):
for
col
in
range
(
COLUMNS
):
x
=
col
*
BLOCK_SIZE
if
saturated
(
x
+
a
,
y
)
and
saturated
(
x
+
b
,
y
):
#print('found bottom in column', col)
return
y
+
1
-
DETECT_COLUMN_OFFSET_Y
+
COLUMN_VSHIFT
[
col
]
def
detect_block_type
(
board
,
x
,
y
):
h
,
s
,
v
=
board
.
getpixel
((
x
+
DETECT_BASIC_X
,
y
+
DETECT_BASIC_Y
))
# check for basic blocks first, use saturation filter to avoid confusing
# green blocks with background
if
s
>=
MIN_BASIC_SAT
:
for
ty
,
hexpect
in
enumerate
(
BASIC_HUES
):
if
is_hue
(
h
,
hexpect
):
return
ty
# if no basic block is detected, check another pixel for bomb contents
h
,
s
,
v
=
board
.
getpixel
((
x
+
DETECT_BOMB_X
,
y
+
DETECT_BOMB_Y
))
for
ty
,
hexpect
in
enumerate
(
BOMB_HUES
):
if
is_hue
(
h
,
hexpect
):
return
ty
+
BOMB_OFFSET
# no basic block or bomb -> empty slot
return
NONE
def
detect_blocks
(
board
):
maxy
=
detect_columns
(
board
)
-
BLOCK_SIZE
for
y
in
range
(
maxy
,
0
,
-
BLOCK_SIZE
):
for
col
in
range
(
COLUMNS
):
x
=
col
*
BLOCK_SIZE
yield
detect_block_type
(
board
,
x
,
y
+
COLUMN_VSHIFT
[
col
])
def
detect_exa
(
board
):
for
col
in
range
(
COLUMNS
):
x
=
col
*
BLOCK_SIZE
+
DETECT_EXA_X
y
=
DETECT_EXA_Y
+
COLUMN_VSHIFT
[
col
]
h
,
s
,
v
=
board
.
getpixel
((
x
,
y
))
if
is_hue
(
h
,
EXA_HUE
)
and
v
>=
EXA_MIN_VAL
:
return
col
def
detect_held
(
board
,
exa
):
if
exa
is
not
None
:
x
=
exa
*
BLOCK_SIZE
+
DETECT_EXA_LIGHT_X
y
=
DETECT_EXA_LIGHT_Y
+
COLUMN_VSHIFT
[
exa
]
h
,
s
,
v
=
board
.
getpixel
((
x
,
y
))
if
not
is_hue
(
h
,
EXA_LIGHT_HUE
)
or
v
<
MIN_EXA_LIGHT_VAL
:
return
detect_block_type
(
board
,
exa
*
BLOCK_SIZE
,
DETECT_HELD_Y
)
return
NONE
def
print_board
(
blocks
,
exa
,
held
):
rows
=
len
(
blocks
)
//
COLUMNS
for
row
in
range
(
rows
):
row
=
rows
-
row
row_blocks
=
blocks
[(
row
-
1
)
*
COLUMNS
:
row
*
COLUMNS
]
print
(
' '
+
''
.
join
(
'rpgby.RPGBY'
[
ty
]
for
ty
in
row_blocks
))
if
exa
is
not
None
:
print
(
' '
*
exa
+
' |'
)
print
(
'-'
*
exa
,
'('
,
'rpgby RPGBY'
[
held
],
')'
,
'-'
*
(
COLUMNS
-
exa
-
1
),
sep
=
''
)
if
__name__
==
'__main__'
:
win
=
get_exapunks_window
()
win
.
raise_window
()
while
True
:
board
=
screenshot_board
(
win
)
blocks
=
list
(
detect_blocks
(
board
))
exa
=
detect_exa
(
board
)
held
=
detect_held
(
board
,
exa
)
print
(
'
\
033
c'
,
end
=
''
)
print_board
(
blocks
,
exa
,
held
)
time
.
sleep
(
0.05
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment