Jump to content


Photo

Top 20 Common Game Setups at Gravon site


  • Please log in to reply
21 replies to this topic

#21 Dobby125

Dobby125

    Sergeant

  • Members
  • PipPipPipPipPipPip
  • 359 posts
  • Coat of arms
  • Silver Major

Posted 07 September 2016 - 09:56 PM

In the future, I'll try to list the archive game file names that match the top game setups.  Then you can watch how the top players win/lose. You have to download the game player and archive files at the gravon site to view the games.


  • hondjekapitein likes this

My Youtube Stratego Channel: https://www.youtube....cGDvlZZkGbgq0LA


#22 TemplateRex

TemplateRex

    Captain

  • Members
  • PipPipPipPipPipPipPipPip
  • 919 posts
  • Coat of arms
  • Gold Spy

Posted 04 March 2018 - 01:14 PM

I have now learned Python sufficiently well to be able to do analyze Gravon games myself. Below I will post source code on how to do this yourself.

 

First some preliminary code to convert the Gravon setup encoding to something more readable. To make statistical analysis easier, I convert a 40-character string to a 4 x 10 NumPy array of characters. This allows much easier counting of pieces on a given square, column or row. 

import numpy as np

def rotate(seq, n):
    """ Rotate a sequence by n places.
    If n > 0, rotates the first n elements of the sequence to the back.
    If n < 0, rotates the last n elements of the sequence to the front.
    If n == 0, returns the original sequence.
    """
    n = n % len(seq)
    return seq[n:] + seq[:n]

# page 90 of Vincent de Boer's thesis
# http://www.kbs.twi.tudelft.nl/docs/MSc/2007/deBoer/thesis.pdf
# rotate by -1 because we want the flag as the first piece instead of the last piece
StraDoS2_red = rotate([ chr(i) for i in range(ord('B'), ord('M') + 1) ], -1)
StraDoS2_blu = rotate([ chr(i) for i in range(ord('N'), ord('Y') + 1) ], -1)

# We use 'F' for flag, 'B' for bomb, '1'-'9' for spy-general, and 'X' for marshal.
pieces = [ 'F', 'B' ] + [ str(i) for i in range(1, 10) ] + [ 'X' ]

# A dictionary mapping the StraDoS2 encoding to our conventions.
StraDoS2_decoding = {
    **{ '_' : '*', 'A' : '.' },
    **{ StraDoS2_red[i] : p for i, p in enumerate(pieces) },
    **{ StraDoS2_blu[i] : p for i, p in enumerate(pieces) }
}

def StraDoS2_decode(s):
    """ Decode a StraDoS2 setup string to our conventions. """
    return ''.join([StraDoS2_decoding[c] for c in s])

def mirror(s):
    """ Mirror a setup by reversing its string. """
    return ''.join(reversed(s))

# the board half dimensions of a single player's setup
HALF_HEIGHT = 4
FULL_WIDTH = 10

def to_numpy_array(s):
    """ Convert a setup string to a NumPy array with the board half dimensions. """
    return np.array([ c for c in s ]).reshape(HALF_HEIGHT, FULL_WIDTH)

Next, you have to manually (or using the brilliant wget tool) download all the zip files from Gravon and unzip them into a directory called 'games'. The following code will then read in all the games and extract the red and blue setups.

from lxml import etree
import os

# Requirements:
# 1) extract all .zip files from Gravon in a subdirectory 'games'
#    e.g. using wget -nd -r -P games -A zip http://www.gravon.de/strados2/files/
# 2) unzip all files and delete unwanted game types (barrage, duell, ultimate etc.)
path = 'games'
xml_files = (f for f in os.listdir(path) if f.endswith('.xml'))
setups = []
for f in xml_files:
    filename = os.path.join(path, f)
    tree = etree.parse(filename)
    field = tree.find(".//field")
    if field == None: continue
    content = field.attrib['content']
    red_setup = to_numpy_array(       StraDoS2_decode(content[:40]) )
    blu_setup = to_numpy_array(mirror(StraDoS2_decode(content[60:])))
    setups.append(red_setup)
    setups.append(blu_setup)  

Printing a setup is done as easy as typing print(setups[0]) which will give the red setup of the first game:

[['3' '3' 'B' 'F' 'B' '3' '4' 'B' '2' '3']
 ['B' '5' '7' 'B' '6' '5' 'B' '7' '2' '3']
 ['5' '8' '2' '4' '2' '6' '1' '2' '8' '5']
 ['2' '6' '2' 'X' '7' '4' '9' '4' '2' '6']]

Note that this shows the mirrored setup from the opponent's viewpoint. To get it from your own viewpoint, you can type print(np.flip(setups[0], 0)) to get

[['2' '6' '2' 'X' '7' '4' '9' '4' '2' '6']
 ['5' '8' '2' '4' '2' '6' '1' '2' '8' '5']
 ['B' '5' '7' 'B' '6' '5' 'B' '7' '2' '3']
 ['3' '3' 'B' 'F' 'B' '3' '4' 'B' '2' '3']]

So here the flag is on D1, and the marshal (symbol X) on D4, with a scout and a captain on the wing front lines.

 

Finally, it is very easy to do simple statistical analyses on the list of setups.

num_setups = len(setups)
placements = { p : sum(s == p for s in setups) for p in pieces }

print("Placement by piece and square")
for p, n in placements.items():
    print(p)
    print(np.round(n / num_setups, 3))
print("")
    
print("Placement by piece and column")
for p, n in placements.items():
    print(p, end=": ")
    print(np.round(np.sum(n, axis = 0) / num_setups, 3))
print("")    
    
print("Placement by piece and row")    
for p, n in placements.items():
    print(p, end=": ")
    print(np.round(np.sum(n, axis = 1) / num_setups, 3))    
print("")

This code will output the following tables:

Placement by piece and square
F
[[0.09  0.026 0.071 0.132 0.097 0.08  0.161 0.084 0.022 0.121]
 [0.003 0.002 0.01  0.017 0.003 0.003 0.02  0.012 0.002 0.007]
 [0.001 0.    0.002 0.004 0.001 0.    0.003 0.002 0.    0.006]
 [0.002 0.    0.003 0.002 0.    0.    0.002 0.005 0.001 0.002]]
B
[[0.144 0.264 0.293 0.257 0.265 0.267 0.249 0.279 0.281 0.138]
 [0.245 0.157 0.188 0.194 0.171 0.163 0.192 0.189 0.144 0.263]
 [0.113 0.125 0.1   0.073 0.082 0.079 0.073 0.095 0.125 0.112]
 [0.093 0.061 0.072 0.061 0.046 0.06  0.062 0.069 0.056 0.095]]
1
[[0.003 0.004 0.004 0.005 0.006 0.006 0.005 0.005 0.005 0.004]
 [0.011 0.017 0.046 0.072 0.04  0.043 0.079 0.054 0.02  0.013]
 [0.004 0.006 0.069 0.119 0.015 0.016 0.127 0.058 0.007 0.004]
 [0.001 0.001 0.02  0.041 0.001 0.001 0.04  0.025 0.001 0.001]]
2
[[0.197 0.178 0.112 0.104 0.144 0.147 0.102 0.099 0.157 0.19 ]
 [0.197 0.22  0.122 0.109 0.19  0.185 0.108 0.115 0.223 0.193]
 [0.235 0.264 0.177 0.191 0.28  0.246 0.188 0.171 0.269 0.221]
 [0.347 0.305 0.202 0.192 0.297 0.316 0.188 0.181 0.296 0.334]]
3
[[0.271 0.231 0.212 0.224 0.215 0.21  0.213 0.228 0.233 0.267]
 [0.145 0.14  0.15  0.165 0.143 0.14  0.166 0.149 0.152 0.138]
 [0.055 0.048 0.112 0.112 0.044 0.044 0.112 0.113 0.055 0.056]
 [0.02  0.014 0.098 0.077 0.015 0.014 0.081 0.091 0.015 0.024]]
4
[[0.144 0.121 0.116 0.096 0.092 0.103 0.091 0.117 0.112 0.139]
 [0.121 0.095 0.072 0.075 0.074 0.068 0.066 0.072 0.1   0.114]
 [0.13  0.075 0.064 0.056 0.061 0.07  0.052 0.058 0.081 0.13 ]
 [0.163 0.168 0.07  0.064 0.151 0.144 0.072 0.071 0.164 0.163]]
5
[[0.062 0.073 0.071 0.064 0.051 0.058 0.064 0.066 0.077 0.053]
 [0.087 0.095 0.087 0.068 0.084 0.074 0.072 0.079 0.089 0.078]
 [0.106 0.111 0.072 0.079 0.112 0.107 0.079 0.076 0.094 0.121]
 [0.178 0.224 0.098 0.092 0.209 0.208 0.082 0.097 0.22  0.174]]
6
[[0.045 0.049 0.061 0.062 0.068 0.066 0.056 0.065 0.061 0.043]
 [0.076 0.089 0.098 0.09  0.09  0.098 0.091 0.099 0.095 0.072]
 [0.146 0.14  0.082 0.079 0.129 0.144 0.076 0.085 0.13  0.138]
 [0.125 0.146 0.114 0.118 0.177 0.17  0.116 0.114 0.159 0.132]]
7
[[0.024 0.037 0.047 0.044 0.046 0.047 0.048 0.046 0.036 0.03 ]
 [0.055 0.09  0.112 0.116 0.095 0.109 0.122 0.112 0.07  0.063]
 [0.093 0.091 0.075 0.068 0.104 0.1   0.074 0.073 0.094 0.087]
 [0.048 0.053 0.115 0.102 0.074 0.059 0.11  0.119 0.059 0.048]]
8
[[0.011 0.012 0.009 0.009 0.011 0.012 0.008 0.009 0.011 0.008]
 [0.034 0.062 0.086 0.075 0.069 0.077 0.065 0.089 0.07  0.037]
 [0.057 0.07  0.117 0.096 0.062 0.068 0.085 0.135 0.069 0.062]
 [0.012 0.012 0.086 0.081 0.013 0.013 0.07  0.097 0.013 0.014]]
9
[[0.003 0.002 0.001 0.001 0.001 0.002 0.001 0.001 0.002 0.002]
 [0.01  0.013 0.013 0.008 0.018 0.017 0.01  0.012 0.013 0.01 ]
 [0.028 0.037 0.063 0.057 0.059 0.08  0.069 0.068 0.04  0.033]
 [0.005 0.008 0.051 0.086 0.007 0.006 0.088 0.061 0.007 0.006]]
X
[[0.004 0.002 0.002 0.001 0.002 0.002 0.001 0.001 0.002 0.003]
 [0.015 0.018 0.015 0.011 0.021 0.021 0.01  0.016 0.021 0.01 ]
 [0.029 0.032 0.064 0.065 0.049 0.041 0.062 0.066 0.034 0.029]
 [0.005 0.006 0.07  0.083 0.008 0.007 0.087 0.071 0.008 0.005]]

Placement by piece and column
F: [0.097 0.028 0.086 0.156 0.101 0.083 0.185 0.102 0.025 0.136]
B: [0.595 0.607 0.652 0.584 0.564 0.569 0.575 0.631 0.606 0.609]
1: [0.019 0.027 0.14  0.237 0.062 0.067 0.251 0.142 0.032 0.021]
2: [0.975 0.967 0.612 0.595 0.91  0.894 0.584 0.566 0.944 0.937]
3: [0.49  0.433 0.573 0.577 0.418 0.408 0.572 0.58  0.456 0.484]
4: [0.558 0.459 0.322 0.291 0.377 0.384 0.281 0.317 0.456 0.546]
5: [0.433 0.504 0.328 0.303 0.456 0.447 0.297 0.318 0.48  0.426]
6: [0.392 0.424 0.355 0.348 0.465 0.478 0.338 0.363 0.445 0.386]
7: [0.221 0.271 0.349 0.33  0.319 0.314 0.354 0.35  0.259 0.228]
8: [0.115 0.156 0.298 0.26  0.155 0.171 0.228 0.329 0.163 0.121]
9: [0.046 0.06  0.128 0.151 0.085 0.106 0.168 0.142 0.062 0.051]
X: [0.053 0.058 0.15  0.16  0.08  0.072 0.16  0.154 0.065 0.047]

Placement by piece and row
F: [0.883 0.079 0.02  0.018]
B: [2.437 1.905 0.976 0.674]
1: [0.048 0.394 0.425 0.131]
2: [1.427 1.662 2.24  2.656]
3: [2.304 1.487 0.751 0.449]
4: [1.132 0.854 0.777 1.229]
5: [0.64  0.814 0.956 1.583]
6: [0.575 0.898 1.149 1.371]
7: [0.405 0.944 0.859 0.786]
8: [0.098 0.665 0.821 0.413]
9: [0.017 0.123 0.535 0.325]
X: [0.02  0.157 0.472 0.349] 

So there you have it: less than a hundred lines of Python code to analyze over 85 thousand Gravon games. Perhaps in later posts, I will make more analyses.

 

 

 


  • Dobby125 likes this

I hereby grant explicit permission to all my opponents to record and publish my games as they see fit.





0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users