a geicko-2 based round robin ranking system designed to test c++ battleship submissions battleship.dunkirk.sh
at main 7.9 kB view raw
1package terminfo 2 3import ( 4 "bytes" 5 "fmt" 6 "io" 7 "strconv" 8 "strings" 9 "sync" 10) 11 12// parametizer represents the a scan state for a parameterized string. 13type parametizer struct { 14 // z is the string to parameterize 15 z []byte 16 // pos is the current position in s. 17 pos int 18 // nest is the current nest level. 19 nest int 20 // s is the variable stack. 21 s stack 22 // skipElse keeps the state of skipping else. 23 skipElse bool 24 // buf is the result buffer. 25 buf *bytes.Buffer 26 // params are the parameters to interpolate. 27 params [9]interface{} 28 // vars are dynamic variables. 29 vars [26]interface{} 30} 31 32// staticVars are the static, global variables. 33var staticVars = struct { 34 vars [26]interface{} 35 sync.Mutex 36}{} 37 38var parametizerPool = sync.Pool{ 39 New: func() interface{} { 40 p := new(parametizer) 41 p.buf = bytes.NewBuffer(make([]byte, 0, 45)) 42 return p 43 }, 44} 45 46// newParametizer returns a new initialized parametizer from the pool. 47func newParametizer(z []byte) *parametizer { 48 p := parametizerPool.Get().(*parametizer) 49 p.z = z 50 return p 51} 52 53// reset resets the parametizer. 54func (p *parametizer) reset() { 55 p.pos, p.nest = 0, 0 56 p.s.reset() 57 p.buf.Reset() 58 p.params, p.vars = [9]interface{}{}, [26]interface{}{} 59 parametizerPool.Put(p) 60} 61 62// stateFn represents the state of the scanner as a function that returns the 63// next state. 64type stateFn func() stateFn 65 66// exec executes the parameterizer, interpolating the supplied parameters. 67func (p *parametizer) exec() string { 68 for state := p.scanTextFn; state != nil; { 69 state = state() 70 } 71 return p.buf.String() 72} 73 74// peek returns the next byte. 75func (p *parametizer) peek() (byte, error) { 76 if p.pos >= len(p.z) { 77 return 0, io.EOF 78 } 79 return p.z[p.pos], nil 80} 81 82// writeFrom writes the characters from ppos to pos to the buffer. 83func (p *parametizer) writeFrom(ppos int) { 84 if p.pos > ppos { 85 // append remaining characters. 86 p.buf.Write(p.z[ppos:p.pos]) 87 } 88} 89 90func (p *parametizer) scanTextFn() stateFn { 91 ppos := p.pos 92 for { 93 ch, err := p.peek() 94 if err != nil { 95 p.writeFrom(ppos) 96 return nil 97 } 98 if ch == '%' { 99 p.writeFrom(ppos) 100 p.pos++ 101 return p.scanCodeFn 102 } 103 p.pos++ 104 } 105} 106 107func (p *parametizer) scanCodeFn() stateFn { 108 ch, err := p.peek() 109 if err != nil { 110 return nil 111 } 112 switch ch { 113 case '%': 114 p.buf.WriteByte('%') 115 case ':': 116 // this character is used to avoid interpreting "%-" and "%+" as operators. 117 // the next character is where the format really begins. 118 p.pos++ 119 _, err = p.peek() 120 if err != nil { 121 return nil 122 } 123 return p.scanFormatFn 124 case '#', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.': 125 return p.scanFormatFn 126 case 'o': 127 p.buf.WriteString(strconv.FormatInt(int64(p.s.popInt()), 8)) 128 case 'd': 129 p.buf.WriteString(strconv.Itoa(p.s.popInt())) 130 case 'x': 131 p.buf.WriteString(strconv.FormatInt(int64(p.s.popInt()), 16)) 132 case 'X': 133 p.buf.WriteString(strings.ToUpper(strconv.FormatInt(int64(p.s.popInt()), 16))) 134 case 's': 135 p.buf.WriteString(p.s.popString()) 136 case 'c': 137 p.buf.WriteByte(p.s.popByte()) 138 case 'p': 139 p.pos++ 140 return p.pushParamFn 141 case 'P': 142 p.pos++ 143 return p.setDsVarFn 144 case 'g': 145 p.pos++ 146 return p.getDsVarFn 147 case '\'': 148 p.pos++ 149 ch, err = p.peek() 150 if err != nil { 151 return nil 152 } 153 p.s.push(ch) 154 // skip the '\'' 155 p.pos++ 156 case '{': 157 p.pos++ 158 return p.pushIntfn 159 case 'l': 160 p.s.push(len(p.s.popString())) 161 case '+': 162 bi, ai := p.s.popInt(), p.s.popInt() 163 p.s.push(ai + bi) 164 case '-': 165 bi, ai := p.s.popInt(), p.s.popInt() 166 p.s.push(ai - bi) 167 case '*': 168 bi, ai := p.s.popInt(), p.s.popInt() 169 p.s.push(ai * bi) 170 case '/': 171 bi, ai := p.s.popInt(), p.s.popInt() 172 if bi != 0 { 173 p.s.push(ai / bi) 174 } else { 175 p.s.push(0) 176 } 177 case 'm': 178 bi, ai := p.s.popInt(), p.s.popInt() 179 if bi != 0 { 180 p.s.push(ai % bi) 181 } else { 182 p.s.push(0) 183 } 184 case '&': 185 bi, ai := p.s.popInt(), p.s.popInt() 186 p.s.push(ai & bi) 187 case '|': 188 bi, ai := p.s.popInt(), p.s.popInt() 189 p.s.push(ai | bi) 190 case '^': 191 bi, ai := p.s.popInt(), p.s.popInt() 192 p.s.push(ai ^ bi) 193 case '=': 194 bi, ai := p.s.popInt(), p.s.popInt() 195 p.s.push(ai == bi) 196 case '>': 197 bi, ai := p.s.popInt(), p.s.popInt() 198 p.s.push(ai > bi) 199 case '<': 200 bi, ai := p.s.popInt(), p.s.popInt() 201 p.s.push(ai < bi) 202 case 'A': 203 bi, ai := p.s.popBool(), p.s.popBool() 204 p.s.push(ai && bi) 205 case 'O': 206 bi, ai := p.s.popBool(), p.s.popBool() 207 p.s.push(ai || bi) 208 case '!': 209 p.s.push(!p.s.popBool()) 210 case '~': 211 p.s.push(^p.s.popInt()) 212 case 'i': 213 for i := range p.params[:2] { 214 if n, ok := p.params[i].(int); ok { 215 p.params[i] = n + 1 216 } 217 } 218 case '?', ';': 219 case 't': 220 return p.scanThenFn 221 case 'e': 222 p.skipElse = true 223 return p.skipTextFn 224 } 225 p.pos++ 226 return p.scanTextFn 227} 228 229func (p *parametizer) scanFormatFn() stateFn { 230 // the character was already read, so no need to check the error. 231 ch, _ := p.peek() 232 // 6 should be the maximum length of a format string, for example "%:-9.9d". 233 f := []byte{'%', ch, 0, 0, 0, 0} 234 var err error 235 for { 236 p.pos++ 237 ch, err = p.peek() 238 if err != nil { 239 return nil 240 } 241 f = append(f, ch) 242 switch ch { 243 case 'o', 'd', 'x', 'X': 244 fmt.Fprintf(p.buf, string(f), p.s.popInt()) 245 break 246 case 's': 247 fmt.Fprintf(p.buf, string(f), p.s.popString()) 248 break 249 case 'c': 250 fmt.Fprintf(p.buf, string(f), p.s.popByte()) 251 break 252 } 253 } 254 p.pos++ 255 return p.scanTextFn 256} 257 258func (p *parametizer) pushParamFn() stateFn { 259 ch, err := p.peek() 260 if err != nil { 261 return nil 262 } 263 if ai := int(ch - '1'); ai >= 0 && ai < len(p.params) { 264 p.s.push(p.params[ai]) 265 } else { 266 p.s.push(0) 267 } 268 // skip the '}' 269 p.pos++ 270 return p.scanTextFn 271} 272 273func (p *parametizer) setDsVarFn() stateFn { 274 ch, err := p.peek() 275 if err != nil { 276 return nil 277 } 278 if ch >= 'A' && ch <= 'Z' { 279 staticVars.Lock() 280 staticVars.vars[int(ch-'A')] = p.s.pop() 281 staticVars.Unlock() 282 } else if ch >= 'a' && ch <= 'z' { 283 p.vars[int(ch-'a')] = p.s.pop() 284 } 285 p.pos++ 286 return p.scanTextFn 287} 288 289func (p *parametizer) getDsVarFn() stateFn { 290 ch, err := p.peek() 291 if err != nil { 292 return nil 293 } 294 var a byte 295 if ch >= 'A' && ch <= 'Z' { 296 a = 'A' 297 } else if ch >= 'a' && ch <= 'z' { 298 a = 'a' 299 } 300 staticVars.Lock() 301 p.s.push(staticVars.vars[int(ch-a)]) 302 staticVars.Unlock() 303 p.pos++ 304 return p.scanTextFn 305} 306 307func (p *parametizer) pushIntfn() stateFn { 308 var ai int 309 for { 310 ch, err := p.peek() 311 if err != nil { 312 return nil 313 } 314 p.pos++ 315 if ch < '0' || ch > '9' { 316 p.s.push(ai) 317 return p.scanTextFn 318 } 319 ai = (ai * 10) + int(ch-'0') 320 } 321} 322 323func (p *parametizer) scanThenFn() stateFn { 324 p.pos++ 325 if p.s.popBool() { 326 return p.scanTextFn 327 } 328 p.skipElse = false 329 return p.skipTextFn 330} 331 332func (p *parametizer) skipTextFn() stateFn { 333 for { 334 ch, err := p.peek() 335 if err != nil { 336 return nil 337 } 338 p.pos++ 339 if ch == '%' { 340 break 341 } 342 } 343 if p.skipElse { 344 return p.skipElseFn 345 } 346 return p.skipThenFn 347} 348 349func (p *parametizer) skipThenFn() stateFn { 350 ch, err := p.peek() 351 if err != nil { 352 return nil 353 } 354 p.pos++ 355 switch ch { 356 case ';': 357 if p.nest == 0 { 358 return p.scanTextFn 359 } 360 p.nest-- 361 case '?': 362 p.nest++ 363 case 'e': 364 if p.nest == 0 { 365 return p.scanTextFn 366 } 367 } 368 return p.skipTextFn 369} 370 371func (p *parametizer) skipElseFn() stateFn { 372 ch, err := p.peek() 373 if err != nil { 374 return nil 375 } 376 p.pos++ 377 switch ch { 378 case ';': 379 if p.nest == 0 { 380 return p.scanTextFn 381 } 382 p.nest-- 383 case '?': 384 p.nest++ 385 } 386 return p.skipTextFn 387} 388 389// Printf evaluates a parameterized terminfo value z, interpolating params. 390func Printf(z []byte, params ...interface{}) string { 391 p := newParametizer(z) 392 defer p.reset() 393 // make sure we always have 9 parameters -- makes it easier 394 // later to skip checks and its faster 395 for i := 0; i < len(p.params) && i < len(params); i++ { 396 p.params[i] = params[i] 397 } 398 return p.exec() 399} 400 401// Fprintf evaluates a parameterized terminfo value z, interpolating params and 402// writing to w. 403func Fprintf(w io.Writer, z []byte, params ...interface{}) { 404 w.Write([]byte(Printf(z, params...))) 405}