software_challenge_client 19.1.0 → 20.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,17 +0,0 @@
1
- # coding: utf-8
2
- # frozen_string_literal: true
3
-
4
- # Ein Koordinatenpaar für ein zweidimensionales Koordinatensystem.
5
- class Coordinates
6
-
7
- # X-Koordinate
8
- attr_reader :x
9
- # Y-Koordinate
10
- attr_reader :y
11
-
12
- # Erstellt ein neues Koordinatenpaar aus X- und Y-Koordinate.
13
- def initialize(x, y)
14
- @x = x
15
- @y = y
16
- end
17
- end
@@ -1,30 +0,0 @@
1
- # encoding: utf-8
2
-
3
- require 'typesafe_enum'
4
- # Der Typ eines Feldes des Spielbrettes. Es gibt folgende Typen:
5
- # - EMPTY
6
- # - RED
7
- # - BLUE
8
- # - OBSTRUCTED
9
- #
10
- # Zugriff z.B. mit FieldType::RED
11
- class FieldType < TypesafeEnum::Base
12
- new :EMPTY, '~'
13
- new :RED, 'R'
14
- new :BLUE, 'B'
15
- new :OBSTRUCTED, 'O'
16
-
17
- # @param field_type [FieldType] Der Feldtyp, zu dem die Spielerfarbe ermittelt werden soll.
18
- # @return [PlayerColor] Die zum Feldtyp gehörende Spielerfarbe, also PlayerColor::RED für FieldType::RED und PlayerColor::BLUE für FieldType::BLUE. In allen anderen Fällen PlayerColor::NONE.
19
- # @see PlayerColor#field_type
20
- def self.player_color(field_type)
21
- case field_type
22
- when FieldType::RED
23
- PlayerColor::RED
24
- when FieldType::BLUE
25
- PlayerColor::BLUE
26
- else
27
- PlayerColor::NONE
28
- end
29
- end
30
- end
@@ -1,126 +0,0 @@
1
- # coding: utf-8
2
- # frozen_string_literal: true
3
-
4
- require_relative './util/constants'
5
- require_relative 'direction'
6
- require_relative 'coordinates'
7
- require_relative 'line_direction'
8
-
9
- # Ein Iterator, der alle Koordinatenpaare auf einer Linie des Spielbrettes enthält.
10
- class Line
11
- include Enumerable
12
- include Constants
13
-
14
- # Erzeugt einen neuen Iterator.
15
- #
16
- # @param start [Coordinates]
17
- # @param direction [LineDirection]
18
- def initialize(start, direction)
19
- @direction = direction
20
- @start = start
21
- # we will iterate from left to right, so find the leftmost field on the line
22
- # inside the field note that (0,0) is the lowest, leftmost point, x-axis
23
- # goes to the right, y-axis goes up
24
- case @direction
25
- when LineDirection::HORIZONTAL
26
- leftmost_x = 0
27
- leftmost_y = @start.y
28
- when LineDirection::VERTICAL
29
- leftmost_x = @start.x
30
- leftmost_y = SIZE - 1
31
- when LineDirection::RISING_DIAGONAL
32
- # for rising diagonals, we have to decrease x and y
33
- shift = [@start.x, @start.y].min
34
- leftmost_x = @start.x - shift
35
- leftmost_y = @start.y - shift
36
- when LineDirection::FALLING_DIAGONAL
37
- # for falling diagonals, we have to decrease x and increase y
38
- shift = [@start.x, (SIZE - 1) - @start.y].min
39
- leftmost_x = @start.x - shift
40
- leftmost_y = @start.y + shift
41
- end
42
- @xi = leftmost_x
43
- @yi = leftmost_y
44
-
45
- @members = []
46
- while @xi >= 0 && @yi >= 0 && @xi < SIZE && @yi < SIZE
47
- @members << Coordinates.new(@xi, @yi)
48
- # horizontal lines and diagonals move right
49
- if [LineDirection::HORIZONTAL,
50
- LineDirection::RISING_DIAGONAL,
51
- LineDirection::FALLING_DIAGONAL].include? @direction
52
- @xi += 1
53
- end
54
- # vertical lines and falling diagonals move down
55
- if [LineDirection::VERTICAL,
56
- LineDirection::FALLING_DIAGONAL].include? @direction
57
- @yi -= 1
58
- elsif @direction == LineDirection::RISING_DIAGONAL
59
- # rising diagonals move up
60
- @yi += 1
61
- end
62
- end
63
- end
64
-
65
- def each(&block)
66
- @members.each(&block)
67
- end
68
-
69
- # Begrenzt den Iterator auf Koordinatenpaare von Feldern innerhalb der gegebenen beiden Koordinatenpaare (exklusive).
70
- # Kann als Filter verwendet werden.
71
- #
72
- # @example
73
- # Line.new(
74
- # Coordinates.new(2, 3), LineDirection::HORIZONTAL
75
- # ).select do |c|
76
- # Line.between(Coordinates.new(2, 3), Coordinates.new(5, 3), LineDirection::HORIZONTAL).call(c)
77
- # end
78
- def self.between(start, bound, direction)
79
- lower_x = [start.x, bound.x].min
80
- lower_y = [start.y, bound.y].min
81
- higher_x = [start.x, bound.x].max
82
- higher_y = [start.y, bound.y].max
83
- proc do |f|
84
- case direction
85
- when LineDirection::HORIZONTAL
86
- f.x > lower_x && f.x < higher_x
87
- when LineDirection::VERTICAL
88
- f.y > lower_y && f.y < higher_y
89
- when LineDirection::RISING_DIAGONAL, LineDirection::FALLING_DIAGONAL
90
- f.x > lower_x && f.x < higher_x && f.y > lower_y && f.y < higher_y
91
- else
92
- throw `unknown direction ${direction}`
93
- end
94
- end
95
- end
96
-
97
- # @param line_direction [LineDirection] Ausrichtung der Linie
98
- # @return [Array<Direction>] Die beiden Bewegungsrichtungen, die auf einer Linie mit der Ausrichtung möglich sind.
99
- def self.directions_for_line_direction(line_direction)
100
- case line_direction
101
- when LineDirection::HORIZONTAL
102
- [Direction::LEFT, Direction::RIGHT]
103
- when LineDirection::VERTICAL
104
- [Direction::UP, Direction::DOWN]
105
- when LineDirection::RISING_DIAGONAL
106
- [Direction::UP_RIGHT, Direction::DOWN_LEFT]
107
- when LineDirection::FALLING_DIAGONAL
108
- [Direction::UP_LEFT, Direction::DOWN_RIGHT]
109
- end
110
- end
111
-
112
- # @param line_direction [Direction] Bewegungsrichtung
113
- # @return [Array<Direction>] Die Ausrichtung einer Linie, die auf der Bewegungsrichtung liegt.
114
- def self.line_direction_for_direction(direction)
115
- case direction
116
- when Direction::LEFT, Direction::RIGHT
117
- LineDirection::HORIZONTAL
118
- when Direction::UP, Direction::DOWN
119
- LineDirection::VERTICAL
120
- when Direction::UP_RIGHT, Direction::DOWN_LEFT
121
- LineDirection::RISING_DIAGONAL
122
- when Direction::UP_LEFT, Direction::DOWN_RIGHT
123
- LineDirection::FALLING_DIAGONAL
124
- end
125
- end
126
- end
@@ -1,84 +0,0 @@
1
- # encoding: utf-8
2
- require_relative 'debug_hint'
3
-
4
- # Ein Spielzug. Er ist definiert durch das Koordinatenpaar des Ausgangsfeldes (ein Fisch des Spielers, der den Zug machen will) und eine Bewegungsrichtung.
5
- class Move
6
- # @!attribute [r] x
7
- # @return [Integer] X-Koordinate des Fisches, der bewegt werden soll. Die Spalte ganz links auf dem Spielbrett hat X-Koordinate 0, die ganz rechts 9.
8
- attr_reader :x
9
-
10
- # @!attribute [r] y
11
- # @return [Integer] Y-Koordinate des Fisches, der bewegt werden soll. Die Zeile ganz unten auf dem Spielbrett hat Y-Koordinate 0, die ganz oben 9.
12
- attr_reader :y
13
-
14
- # @!attribute [r] direction
15
- #
16
- # @return [Direction] Die Richtung, in die bewegt werden soll.
17
- attr_reader :direction
18
-
19
- # @!attribute [r] hints
20
- # @return [Array<DebugHint>] Hinweise, die an den Zug angeheftet werden sollen. Siehe {DebugHint}.
21
- attr_reader :hints
22
-
23
- # Erstellt einen neuen Zug.
24
- # @param x [Integer]
25
- # @param y [Integer]
26
- # @param direction [Direction]
27
- def initialize(x, y, direction)
28
- @x = x
29
- @y = y
30
- @direction = direction
31
- @hints = []
32
- end
33
-
34
- # @param hint [DebugHint]
35
- def add_hint(hint)
36
- @hints.push(hint)
37
- end
38
-
39
- def ==(other)
40
- x == other.x && y == other.y && direction == other.direction
41
- end
42
-
43
- def to_s
44
- "Move: (#{x},#{y}) #{direction}"
45
- end
46
-
47
- # @return [Coordinates] Die Koordinaten des Ausgangsfeldes des Zuges als Koordinatenpaar.
48
- def from_field
49
- Coordinates.new(x, y)
50
- end
51
-
52
- # Überprüft, ob der Zug in dem gegebenen Spielzustand regelkonform ausgeführt werden kann.
53
- # @param gamestate [GameState]
54
- # @return [Boolean]
55
- def valid?(gamestate)
56
- GameRuleLogic.valid_move?(self, gamestate.board, gamestate.current_player_color)
57
- end
58
-
59
- # Führt den Zug in dem gegebenen Spielzustand aus. Sollte dabei gegen Spielregeln verstossen werden, wird eine InvalidMoveException geworfen.
60
- # @param gamestate [GameState]
61
- def perform!(gamestate)
62
- if GameRuleLogic.valid_move?(self, gamestate.board, gamestate.current_player_color)
63
- type = gamestate.board.field(x, y).type
64
- target = GameRuleLogic.move_target(self, gamestate.board)
65
- gamestate.board.change_field(x, y, FieldType::EMPTY)
66
- gamestate.board.change_field(target.x, target.y, type)
67
- else
68
- raise InvalidMoveException.new('Invalid move', self)
69
- end
70
- # change the state to the next turn
71
- gamestate.last_move = self
72
- gamestate.turn += 1
73
- gamestate.switch_current_player
74
- gamestate.condition = GameRuleLogic.winning_condition(gamestate)
75
- end
76
-
77
-
78
- # Ermittelt die Koordinaten des Zielfeldes des Zuges mit einer gegebenen Zugweite.
79
- # @param speed [Integer] Die Zugweite. Entspricht normalerweise der Anzahl der Fische auf der Bewegungslinie.
80
- # @return [Coordinates] Koordinaten des Zielfeldes. Eventuell ausserhalb des Spielbrettes.
81
- def target_field(speed)
82
- direction.translate(from_field, speed)
83
- end
84
- end