a geicko-2 based round robin ranking system designed to test c++ battleship submissions battleship.dunkirk.sh
1package coninput 2 3import ( 4 "encoding/binary" 5 "fmt" 6 "strconv" 7 "strings" 8) 9 10const ( 11 maxEventSize = 16 12 wordPaddingBytes = 2 13) 14 15// EventType denots the type of an event 16type EventType uint16 17 18// EventUnion is the union data type that contains the data for any event. 19type EventUnion [maxEventSize]byte 20 21// InputRecord corresponds to the INPUT_RECORD structure from the Windows 22// console API (see 23// https://docs.microsoft.com/en-us/windows/console/input-record-str). 24type InputRecord struct { 25 // EventType specifies the type of event that helt in Event. 26 EventType EventType 27 28 // Padding of the 16-bit EventType to a whole 32-bit dword. 29 _ [wordPaddingBytes]byte 30 31 // Event holds the actual event data. Use Unrap to access it as its 32 // respective event type. 33 Event EventUnion 34} 35 36// String implements fmt.Stringer for InputRecord. 37func (ir InputRecord) String() string { 38 return ir.Unwrap().String() 39} 40 41// Unwrap parses the event data into an EventRecord of the respective event 42// type. The data in the returned EventRecord does not contain any references to 43// the passed InputRecord. 44func (ir InputRecord) Unwrap() EventRecord { 45 switch ir.EventType { 46 case FocusEventType: 47 return FocusEventRecord{SetFocus: ir.Event[0] > 0} 48 case KeyEventType: 49 return KeyEventRecord{ 50 KeyDown: binary.LittleEndian.Uint32(ir.Event[0:4]) > 0, 51 RepeatCount: binary.LittleEndian.Uint16(ir.Event[4:6]), 52 VirtualKeyCode: VirtualKeyCode(binary.LittleEndian.Uint16(ir.Event[6:8])), 53 VirtualScanCode: VirtualKeyCode(binary.LittleEndian.Uint16(ir.Event[8:10])), 54 Char: rune(binary.LittleEndian.Uint16(ir.Event[10:12])), 55 ControlKeyState: ControlKeyState(binary.LittleEndian.Uint32(ir.Event[12:16])), 56 } 57 case MouseEventType: 58 m := MouseEventRecord{ 59 MousePositon: Coord{ 60 X: binary.LittleEndian.Uint16(ir.Event[0:2]), 61 Y: binary.LittleEndian.Uint16(ir.Event[2:4]), 62 }, 63 ButtonState: ButtonState(binary.LittleEndian.Uint32(ir.Event[4:8])), 64 ControlKeyState: ControlKeyState(binary.LittleEndian.Uint32(ir.Event[8:12])), 65 EventFlags: EventFlags(binary.LittleEndian.Uint32(ir.Event[12:16])), 66 } 67 68 if (m.EventFlags&MOUSE_WHEELED > 0) || (m.EventFlags&MOUSE_HWHEELED > 0) { 69 if int16(highWord(uint32(m.ButtonState))) > 0 { 70 m.WheelDirection = 1 71 } else { 72 m.WheelDirection = -1 73 } 74 } 75 76 return m 77 case WindowBufferSizeEventType: 78 return WindowBufferSizeEventRecord{ 79 Size: Coord{ 80 X: binary.LittleEndian.Uint16(ir.Event[0:2]), 81 Y: binary.LittleEndian.Uint16(ir.Event[2:4]), 82 }, 83 } 84 case MenuEventType: 85 return MenuEventRecord{ 86 CommandID: binary.LittleEndian.Uint32(ir.Event[0:4]), 87 } 88 default: 89 return &UnknownEvent{InputRecord: ir} 90 } 91} 92 93// EventRecord represents one of the following event types: 94// TypeFocusEventRecord, TypeKeyEventRecord, TypeMouseEventRecord, 95// TypeWindowBufferSizeEvent, TypeMenuEventRecord and UnknownEvent. 96type EventRecord interface { 97 Type() string 98 fmt.Stringer 99} 100 101// FocusEventType is the event type for a FocusEventRecord (see 102// https://docs.microsoft.com/en-us/windows/console/input-record-str). 103const FocusEventType EventType = 0x0010 104 105// FocusEventRecord represent the FOCUS_EVENT_RECORD structure from the Windows 106// console API (see 107// https://docs.microsoft.com/en-us/windows/console/focus-event-record-str). 108// These events are used internally by the Windows console API and should be 109// ignored. 110type FocusEventRecord struct { 111 // SetFocus is reserved and should not be used. 112 SetFocus bool 113} 114 115// Ensure that FocusEventRecord satisfies EventRecord interface. 116var _ EventRecord = FocusEventRecord{} 117 118// Type ensures that FocusEventRecord satisfies EventRecord interface. 119func (e FocusEventRecord) Type() string { return "FocusEvent" } 120 121// String ensures that FocusEventRecord satisfies EventRecord and fmt.Stringer 122// interfaces. 123func (e FocusEventRecord) String() string { return fmt.Sprintf("%s[%v]", e.Type(), e.SetFocus) } 124 125// KeyEventType is the event type for a KeyEventRecord (see 126// https://docs.microsoft.com/en-us/windows/console/input-record-str). 127const KeyEventType EventType = 0x0001 128 129// KeyEventRecord represent the KEY_EVENT_RECORD structure from the Windows 130// console API (see 131// https://docs.microsoft.com/en-us/windows/console/key-event-record-str). 132type KeyEventRecord struct { 133 // KeyDown specified whether the key is pressed or released. 134 KeyDown bool 135 136 // RepeatCount indicates that a key is being held down. For example, when a 137 // key is held down, five events with RepeatCount equal to 1 may be 138 // generated, one event with RepeatCount equal to 5, or multiple events 139 // with RepeatCount greater than or equal to 1. 140 RepeatCount uint16 141 142 // VirtualKeyCode identifies the given key in a device-independent manner 143 // (see 144 // https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes). 145 VirtualKeyCode VirtualKeyCode 146 147 // VirtualScanCode represents the device-dependent value generated by the 148 // keyboard hardware. 149 VirtualScanCode VirtualKeyCode 150 151 // Char is the character that corresponds to the pressed key. Char can be 152 // zero for some keys. 153 Char rune 154 155 //ControlKeyState holds the state of the control keys. 156 ControlKeyState ControlKeyState 157} 158 159// Ensure that KeyEventRecord satisfies EventRecord interface. 160var _ EventRecord = KeyEventRecord{} 161 162// Type ensures that KeyEventRecord satisfies EventRecord interface. 163func (e KeyEventRecord) Type() string { return "KeyEvent" } 164 165// String ensures that KeyEventRecord satisfies EventRecord and fmt.Stringer 166// interfaces. 167func (e KeyEventRecord) String() string { 168 infos := []string{} 169 170 repeat := "" 171 if e.RepeatCount > 1 { 172 repeat = "x" + strconv.Itoa(int(e.RepeatCount)) 173 } 174 175 infos = append(infos, fmt.Sprintf("%q%s", e.Char, repeat)) 176 177 direction := "up" 178 if e.KeyDown { 179 direction = "down" 180 } 181 182 infos = append(infos, direction) 183 184 if e.ControlKeyState != NO_CONTROL_KEY { 185 infos = append(infos, e.ControlKeyState.String()) 186 } 187 188 infos = append(infos, fmt.Sprintf("KeyCode: %d", e.VirtualKeyCode)) 189 infos = append(infos, fmt.Sprintf("ScanCode: %d", e.VirtualScanCode)) 190 191 return fmt.Sprintf("%s[%s]", e.Type(), strings.Join(infos, ", ")) 192} 193 194// MenuEventType is the event type for a MenuEventRecord (see 195// https://docs.microsoft.com/en-us/windows/console/input-record-str). 196const MenuEventType EventType = 0x0008 197 198// MenuEventRecord represent the MENU_EVENT_RECORD structure from the Windows 199// console API (see 200// https://docs.microsoft.com/en-us/windows/console/menu-event-record-str). 201// These events are deprecated by the Windows console API and should be ignored. 202type MenuEventRecord struct { 203 CommandID uint32 204} 205 206// Ensure that MenuEventRecord satisfies EventRecord interface. 207var _ EventRecord = MenuEventRecord{} 208 209// Type ensures that MenuEventRecord satisfies EventRecord interface. 210func (e MenuEventRecord) Type() string { return "MenuEvent" } 211 212// String ensures that MenuEventRecord satisfies EventRecord and fmt.Stringer 213// interfaces. 214func (e MenuEventRecord) String() string { return fmt.Sprintf("MenuEvent[%d]", e.CommandID) } 215 216// MouseEventType is the event type for a MouseEventRecord (see 217// https://docs.microsoft.com/en-us/windows/console/input-record-str). 218const MouseEventType EventType = 0x0002 219 220// MouseEventRecord represent the MOUSE_EVENT_RECORD structure from the Windows 221// console API (see 222// https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str). 223type MouseEventRecord struct { 224 // MousePosition contains the location of the cursor, in terms of the 225 // console screen buffer's character-cell coordinates. 226 MousePositon Coord 227 228 // ButtonState holds the status of the mouse buttons. 229 ButtonState ButtonState 230 231 // ControlKeyState holds the state of the control keys. 232 ControlKeyState ControlKeyState 233 234 // EventFlags specify tge type of mouse event. 235 EventFlags EventFlags 236 237 // WheelDirection specified the direction in which the mouse wheel is 238 // spinning when EventFlags contains MOUSE_HWHEELED or MOUSE_WHEELED. When 239 // the event flags specify MOUSE_WHEELED it is 1 if the wheel rotated 240 // forward (away from the user) or -1 when it rotates backwards. When 241 // MOUSE_HWHEELED is specified it is 1 when the wheel rotates right and -1 242 // when it rotates left. When the EventFlags do not indicate a mouse wheel 243 // event it is 0. 244 WheelDirection int 245} 246 247// Ensure that MouseEventRecord satisfies EventRecord interface. 248var _ EventRecord = MouseEventRecord{} 249 250func (e MouseEventRecord) WheelDirectionName() string { 251 if e.EventFlags&MOUSE_WHEELED > 0 { 252 if e.WheelDirection > 0 { 253 return "Forward" 254 } 255 256 return "Backward" 257 } else if e.EventFlags&MOUSE_HWHEELED > 0 { 258 if e.WheelDirection > 0 { 259 return "Right" 260 } 261 262 return "Left" 263 } 264 265 return "" 266} 267 268// Type ensures that MouseEventRecord satisfies EventRecord interface. 269func (e MouseEventRecord) Type() string { return "MouseEvent" } 270 271// String ensures that MouseEventRecord satisfies EventRecord and fmt.Stringer 272// interfaces. 273func (e MouseEventRecord) String() string { 274 infos := []string{e.MousePositon.String()} 275 276 if e.ButtonState&0xFF != 0 { 277 infos = append(infos, e.ButtonState.String()) 278 } 279 280 eventDescription := e.EventFlags.String() 281 282 wheelDirection := e.WheelDirectionName() 283 if wheelDirection != "" { 284 eventDescription += "(" + wheelDirection + ")" 285 } 286 287 infos = append(infos, eventDescription) 288 289 if e.ControlKeyState != NO_CONTROL_KEY { 290 infos = append(infos, e.ControlKeyState.String()) 291 } 292 293 return fmt.Sprintf("%s[%s]", e.Type(), strings.Join(infos, ", ")) 294} 295 296// WindowBufferSizeEventType is the event type for a WindowBufferSizeEventRecord 297// (see https://docs.microsoft.com/en-us/windows/console/input-record-str). 298const WindowBufferSizeEventType EventType = 0x0004 299 300// WindowBufferSizeEventRecord represent the WINDOW_BUFFER_SIZE_RECORD structure 301// from the Windows console API (see 302// https://docs.microsoft.com/en-us/windows/console/window-buffer-size-record-str). 303type WindowBufferSizeEventRecord struct { 304 // Size contains the size of the console screen buffer, in character cell columns and rows. 305 Size Coord 306} 307 308// Ensure that WindowBufferSizeEventRecord satisfies EventRecord interface. 309var _ EventRecord = WindowBufferSizeEventRecord{} 310 311// Type ensures that WindowBufferSizeEventRecord satisfies EventRecord interface. 312func (e WindowBufferSizeEventRecord) Type() string { return "WindowBufferSizeEvent" } 313 314// String ensures that WindowBufferSizeEventRecord satisfies EventRecord and fmt.Stringer 315// interfaces. 316func (e WindowBufferSizeEventRecord) String() string { 317 return fmt.Sprintf("WindowBufferSizeEvent[%s]", e.Size) 318} 319 320// UnknownEvent is generated when the event type does not match one of the 321// following types: TypeFocusEventRecord, TypeKeyEventRecord, 322// TypeMouseEventRecord, TypeWindowBufferSizeEvent, TypeMenuEventRecord and 323// UnknownEvent. 324type UnknownEvent struct { 325 InputRecord 326} 327 328// Ensure that UnknownEvent satisfies EventRecord interface. 329var _ EventRecord = UnknownEvent{} 330 331// Type ensures that UnknownEvent satisfies EventRecord interface. 332func (e UnknownEvent) Type() string { return "UnknownEvent" } 333 334// String ensures that UnknownEvent satisfies EventRecord and fmt.Stringer 335// interfaces. 336func (e UnknownEvent) String() string { 337 return fmt.Sprintf("%s[Type: %d, Data: %v]", e.Type(), e.InputRecord.EventType, e.InputRecord.Event[:]) 338} 339 340// Coord represent the COORD structure from the Windows 341// console API (see https://docs.microsoft.com/en-us/windows/console/coord-str). 342type Coord struct { 343 // X is the horizontal coordinate or column value. The units depend on the function call. 344 X uint16 345 // Y is the vertical coordinate or row value. The units depend on the function call. 346 Y uint16 347} 348 349// String ensures that Coord satisfies the fmt.Stringer interface. 350func (c Coord) String() string { 351 return fmt.Sprintf("(%d, %d)", c.X, c.Y) 352} 353 354// ButtonState holds the state of the mouse buttons (see 355// https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str). 356type ButtonState uint32 357 358func (bs ButtonState) Contains(state ButtonState) bool { 359 return bs&state > 0 360} 361 362// String ensures that ButtonState satisfies the fmt.Stringer interface. 363func (bs ButtonState) String() string { 364 switch { 365 case bs&FROM_LEFT_1ST_BUTTON_PRESSED > 0: 366 return "Left" 367 case bs&FROM_LEFT_2ND_BUTTON_PRESSED > 0: 368 return "2" 369 case bs&FROM_LEFT_3RD_BUTTON_PRESSED > 0: 370 return "3" 371 case bs&FROM_LEFT_4TH_BUTTON_PRESSED > 0: 372 return "4" 373 case bs&RIGHTMOST_BUTTON_PRESSED > 0: 374 return "Right" 375 case bs&0xFF == 0: 376 return "No Button" 377 default: 378 return fmt.Sprintf("Unknown(%d)", bs) 379 } 380} 381 382func (bs ButtonState) IsReleased() bool { 383 return bs&0xff > 0 384} 385 386// Valid values for ButtonState. 387const ( 388 FROM_LEFT_1ST_BUTTON_PRESSED ButtonState = 0x0001 389 RIGHTMOST_BUTTON_PRESSED ButtonState = 0x0002 390 FROM_LEFT_2ND_BUTTON_PRESSED ButtonState = 0x0004 391 FROM_LEFT_3RD_BUTTON_PRESSED ButtonState = 0x0008 392 FROM_LEFT_4TH_BUTTON_PRESSED ButtonState = 0x0010 393) 394 395// ControlKeyState holds the state of the control keys for key and mouse events 396// (see https://docs.microsoft.com/en-us/windows/console/key-event-record-str 397// and https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str). 398type ControlKeyState uint32 399 400func (cks ControlKeyState) Contains(state ControlKeyState) bool { 401 return cks&state > 0 402} 403 404// Valid values for ControlKeyState. 405const ( 406 CAPSLOCK_ON ControlKeyState = 0x0080 407 ENHANCED_KEY ControlKeyState = 0x0100 408 LEFT_ALT_PRESSED ControlKeyState = 0x0002 409 LEFT_CTRL_PRESSED ControlKeyState = 0x0008 410 NUMLOCK_ON ControlKeyState = 0x0020 411 RIGHT_ALT_PRESSED ControlKeyState = 0x0001 412 RIGHT_CTRL_PRESSED ControlKeyState = 0x0004 413 SCROLLLOCK_ON ControlKeyState = 0x0040 414 SHIFT_PRESSED ControlKeyState = 0x0010 415 NO_CONTROL_KEY ControlKeyState = 0x0000 416) 417 418// String ensures that ControlKeyState satisfies the fmt.Stringer interface. 419func (cks ControlKeyState) String() string { 420 controlKeys := []string{} 421 422 switch { 423 case cks&CAPSLOCK_ON > 0: 424 controlKeys = append(controlKeys, "CapsLock") 425 case cks&ENHANCED_KEY > 0: 426 controlKeys = append(controlKeys, "Enhanced") 427 case cks&LEFT_ALT_PRESSED > 0: 428 controlKeys = append(controlKeys, "Alt") 429 case cks&LEFT_CTRL_PRESSED > 0: 430 controlKeys = append(controlKeys, "CTRL") 431 case cks&NUMLOCK_ON > 0: 432 controlKeys = append(controlKeys, "NumLock") 433 case cks&RIGHT_ALT_PRESSED > 0: 434 controlKeys = append(controlKeys, "RightAlt") 435 case cks&RIGHT_CTRL_PRESSED > 0: 436 controlKeys = append(controlKeys, "RightCTRL") 437 case cks&SCROLLLOCK_ON > 0: 438 controlKeys = append(controlKeys, "ScrollLock") 439 case cks&SHIFT_PRESSED > 0: 440 controlKeys = append(controlKeys, "Shift") 441 case cks == NO_CONTROL_KEY: 442 default: 443 return fmt.Sprintf("Unknown(%d)", cks) 444 } 445 446 return strings.Join(controlKeys, ",") 447} 448 449// EventFlags specifies the type of a mouse event (see 450// https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str). 451type EventFlags uint32 452 453// String ensures that EventFlags satisfies the fmt.Stringer interface. 454func (ef EventFlags) String() string { 455 switch { 456 case ef&DOUBLE_CLICK > 0: 457 return "DoubleClick" 458 case ef&MOUSE_WHEELED > 0: 459 return "Wheeled" 460 case ef&MOUSE_MOVED > 0: 461 return "Moved" 462 case ef&MOUSE_HWHEELED > 0: 463 return "HWheeld" 464 case ef == CLICK: 465 return "Click" 466 default: 467 return fmt.Sprintf("Unknown(%d)", ef) 468 } 469} 470 471func (ef EventFlags) Contains(flag EventFlags) bool { 472 return ef&flag > 0 473} 474 475// Valid values for EventFlags. 476const ( 477 CLICK EventFlags = 0x0000 478 MOUSE_MOVED EventFlags = 0x0001 479 DOUBLE_CLICK EventFlags = 0x0002 480 MOUSE_WHEELED EventFlags = 0x0004 481 MOUSE_HWHEELED EventFlags = 0x0008 482) 483 484func highWord(data uint32) uint16 { 485 return uint16((data & 0xFFFF0000) >> 16) 486}