software_challenge_client 20.2.4 → 21.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -0
- data/.ruby-version +1 -1
- data/.vscode/launch.json +41 -0
- data/.vscode/settings.json +10 -0
- data/Dockerfile +1 -1
- data/Gemfile +1 -0
- data/Guardfile +1 -0
- data/README.md +4 -3
- data/RELEASES.md +20 -0
- data/Rakefile +4 -3
- data/example/client.rb +6 -9
- data/example/main.rb +9 -9
- data/lib/software_challenge_client.rb +26 -23
- data/lib/software_challenge_client/board.rb +94 -37
- data/lib/software_challenge_client/client_interface.rb +1 -0
- data/lib/software_challenge_client/color.rb +16 -0
- data/lib/software_challenge_client/condition.rb +2 -0
- data/lib/software_challenge_client/coordinate_set.rb +92 -0
- data/lib/software_challenge_client/coordinates.rb +45 -0
- data/lib/software_challenge_client/debug_hint.rb +1 -0
- data/lib/software_challenge_client/field.rb +21 -56
- data/lib/software_challenge_client/game_rule_logic.rb +258 -335
- data/lib/software_challenge_client/game_state.rb +106 -68
- data/lib/software_challenge_client/has_hints.rb +1 -1
- data/lib/software_challenge_client/invalid_move_exception.rb +1 -0
- data/lib/software_challenge_client/logging.rb +1 -0
- data/lib/software_challenge_client/network.rb +1 -1
- data/lib/software_challenge_client/piece.rb +71 -13
- data/lib/software_challenge_client/piece_shape.rb +109 -0
- data/lib/software_challenge_client/player.rb +7 -6
- data/lib/software_challenge_client/player_type.rb +14 -0
- data/lib/software_challenge_client/protocol.rb +81 -74
- data/lib/software_challenge_client/rotation.rb +22 -0
- data/lib/software_challenge_client/runner.rb +2 -1
- data/lib/software_challenge_client/set_move.rb +13 -4
- data/lib/software_challenge_client/skip_move.rb +5 -0
- data/lib/software_challenge_client/util/constants.rb +3 -4
- data/lib/software_challenge_client/version.rb +2 -1
- data/lib/update_client_module.sh +15 -0
- data/software_challenge_client.gemspec +15 -13
- metadata +54 -36
- data/lib/software_challenge_client/cube_coordinates.rb +0 -25
- data/lib/software_challenge_client/direction.rb +0 -55
- data/lib/software_challenge_client/drag_move.rb +0 -22
- data/lib/software_challenge_client/line_direction.rb +0 -15
- data/lib/software_challenge_client/piece_type.rb +0 -18
- data/lib/software_challenge_client/player_color.rb +0 -25
@@ -1,4 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
require_relative './util/constants'
|
@@ -15,36 +14,62 @@ class GameState
|
|
15
14
|
# @!attribute [rw] turn
|
16
15
|
# @return [Integer] Aktuelle Zugnummer (von 0 beginnend)
|
17
16
|
attr_accessor :turn
|
18
|
-
# @!attribute [rw] start_player_color
|
19
|
-
# @return [PlayerColor] Die Farbe des Spielers, der den ersten Zug im Spiel
|
20
|
-
# machen darf.
|
21
|
-
attr_accessor :start_player_color
|
22
|
-
# @!attribute [rw] current_player_color
|
23
|
-
# @return [PlayerColor] Die Farbe des Spielers, der den nächsten Zug machen
|
24
|
-
# darf, der also gerade an der Reihe ist.
|
25
|
-
attr_accessor :current_player_color
|
26
17
|
|
27
|
-
# @!attribute [
|
28
|
-
# @return [
|
29
|
-
attr_accessor :
|
18
|
+
# @!attribute [rw] round
|
19
|
+
# @return [Integer] Aktuelle Rundennummer (von 1 beginnend)
|
20
|
+
attr_accessor :round
|
21
|
+
|
22
|
+
# @!attribute [rw] startColor
|
23
|
+
# @return [Color] Die Farbe, die zuerst legen darf
|
24
|
+
attr_accessor :start_color
|
25
|
+
|
26
|
+
# @!attribute [rw] valid_colors
|
27
|
+
# @return [Array<Color>] Ein Array aller Farben die ziehen können in
|
28
|
+
# der Reihenfolge in der sie drankommen
|
29
|
+
attr_accessor :valid_colors
|
30
|
+
|
31
|
+
# @!attribute [rw] ordered_colors
|
32
|
+
# @return [Array<Color>] Ein Array aller Farben in
|
33
|
+
# der Reihenfolge in der sie drankommen
|
34
|
+
attr_accessor :ordered_colors
|
30
35
|
|
31
36
|
# @!attribute [r] undeployed_blue_pieces
|
32
|
-
# @return [
|
37
|
+
# @return [Array<PieceShape>] Die blauen, nicht gesetzten Spielsteine
|
33
38
|
attr_accessor :undeployed_blue_pieces
|
34
39
|
|
35
|
-
# @!attribute [r]
|
36
|
-
# @return [
|
37
|
-
|
38
|
-
|
39
|
-
#
|
40
|
-
|
40
|
+
# @!attribute [r] undeployed_yellow_pieces
|
41
|
+
# @return [Array<PieceShape>] Die gelben, nicht gesetzten Spielsteine
|
42
|
+
attr_accessor :undeployed_yellow_pieces
|
43
|
+
|
44
|
+
# @!attribute [r] undeployed_red_pieces
|
45
|
+
# @return [Array<PieceShape>] Die roten, nicht gesetzten Spielsteine
|
46
|
+
attr_accessor :undeployed_red_pieces
|
47
|
+
|
48
|
+
# @!attribute [r] undeployed_green_pieces
|
49
|
+
# @return [Array<PieceShape>] Die grünen, nicht gesetzten Spielsteine
|
50
|
+
attr_accessor :undeployed_green_pieces
|
51
|
+
|
52
|
+
# @!attribute [r] player_one
|
53
|
+
# @return [Player] Der erste Spieler
|
54
|
+
attr_reader :player_one
|
55
|
+
|
56
|
+
# @!attribute [r] player_two
|
57
|
+
# @return [Player] Der zweite Spieler
|
58
|
+
attr_reader :player_two
|
59
|
+
|
41
60
|
# @!attribute [rw] board
|
42
61
|
# @return [Board] Das aktuelle Spielbrett
|
43
62
|
attr_accessor :board
|
63
|
+
|
64
|
+
# @!attribute [rw] startPiece
|
65
|
+
# @return [PieceShape] Der Stein, der im ersten Zug von allen Farben gelegt werden muss
|
66
|
+
attr_accessor :start_piece
|
67
|
+
|
44
68
|
# @!attribute [rw] last_move
|
45
69
|
# @return [Move] Der zuletzt gemachte Zug (ist nil vor dem ersten Zug, also
|
46
70
|
# bei turn == 0)
|
47
71
|
attr_accessor :last_move
|
72
|
+
|
48
73
|
# @!attribute [rw] condition
|
49
74
|
# @return [Condition] Gewinner und Gewinngrund, falls das Spiel bereits
|
50
75
|
# entschieden ist, sonst nil.
|
@@ -54,78 +79,86 @@ class GameState
|
|
54
79
|
def field(x, y)
|
55
80
|
board.field(x, y)
|
56
81
|
end
|
57
|
-
def self.parse_pieces_string(string, color)
|
58
|
-
string.chars.map do |c|
|
59
|
-
case c
|
60
|
-
when 'Q'
|
61
|
-
Piece.new(color, PieceType::BEE)
|
62
|
-
when 'S'
|
63
|
-
Piece.new(color, PieceType::SPIDER)
|
64
|
-
when 'G'
|
65
|
-
Piece.new(color, PieceType::GRASSHOPPER)
|
66
|
-
when 'B'
|
67
|
-
Piece.new(color, PieceType::BEETLE)
|
68
|
-
when 'A'
|
69
|
-
Piece.new(color, PieceType::ANT)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
82
|
|
83
|
+
# Erstellt einen neuen leeren Spielstand.
|
74
84
|
def initialize
|
75
|
-
@
|
76
|
-
@start_player_color = PlayerColor::RED
|
85
|
+
@ordered_colors = [Color::BLUE, Color::YELLOW, Color::RED, Color::GREEN]
|
77
86
|
@board = Board.new
|
78
87
|
@turn = 0
|
79
|
-
@
|
80
|
-
@
|
88
|
+
@undeployed_blue_pieces = PieceShape.to_a
|
89
|
+
@undeployed_yellow_pieces = PieceShape.to_a
|
90
|
+
@undeployed_red_pieces = PieceShape.to_a
|
91
|
+
@undeployed_green_pieces = PieceShape.to_a
|
92
|
+
@start_piece = GameRuleLogic.get_random_pentomino
|
93
|
+
@start_color = Color::BLUE
|
81
94
|
end
|
82
95
|
|
83
96
|
# Fügt einen Spieler zum Spielzustand hinzu.
|
84
97
|
#
|
85
98
|
# @param player [Player] Der hinzuzufügende Spieler.
|
86
99
|
def add_player(player)
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
100
|
+
case player.type
|
101
|
+
when PlayerType::ONE
|
102
|
+
@player_one = player
|
103
|
+
when PlayerType::TWO
|
104
|
+
@player_two = player
|
91
105
|
end
|
92
106
|
end
|
93
107
|
|
94
108
|
# @return [Player] Spieler, der gerade an der Reihe ist.
|
95
109
|
def current_player
|
96
|
-
|
97
|
-
return blue if current_player_color == PlayerColor::BLUE
|
110
|
+
turn.even? ? player_one : player_two
|
98
111
|
end
|
99
112
|
|
100
113
|
# @return [Player] Spieler, der gerade nicht an der Reihe ist.
|
101
114
|
def other_player
|
102
|
-
|
103
|
-
return red if current_player_color == PlayerColor::BLUE
|
115
|
+
turn.even? ? player_two : player_one
|
104
116
|
end
|
105
117
|
|
106
|
-
# @return [
|
107
|
-
def
|
108
|
-
|
118
|
+
# @return [PlayerType] Typ des Spielers, der gerade nicht an der Reihe ist.
|
119
|
+
def other_player_type
|
120
|
+
other_player.type
|
109
121
|
end
|
110
122
|
|
111
|
-
# @return [
|
112
|
-
def
|
113
|
-
turn
|
123
|
+
# @return [Color] Der jetzige Index in der Zug Reihenfolge der Farben.
|
124
|
+
def current_color_index
|
125
|
+
turn % 4
|
114
126
|
end
|
115
127
|
|
128
|
+
# @return [Color] Farbe, der gerade an der Reihe ist.
|
129
|
+
def current_color
|
130
|
+
ordered_colors[current_color_index]
|
131
|
+
end
|
132
|
+
|
133
|
+
# @return [Color] Farbe des aktuellen Spielers, die gerade nicht an der Reihe ist.
|
134
|
+
def other_color
|
135
|
+
Color.find_by_ord((current_color.ord + 2) % 4)
|
136
|
+
end
|
137
|
+
|
138
|
+
# @return [Array<PieceShape>] Array aller Shapes, der gegebenen Farbe, die noch nicht gelegt wurden
|
116
139
|
def undeployed_pieces(color)
|
117
140
|
case color
|
118
|
-
when
|
141
|
+
when Color::RED
|
119
142
|
undeployed_red_pieces
|
120
|
-
when
|
143
|
+
when Color::BLUE
|
121
144
|
undeployed_blue_pieces
|
145
|
+
when Color::YELLOW
|
146
|
+
undeployed_yellow_pieces
|
147
|
+
when Color::GREEN
|
148
|
+
undeployed_green_pieces
|
122
149
|
end
|
123
150
|
end
|
124
151
|
|
152
|
+
# @return [Array<PieceShape>] Array aller Shapes, der gegebenen Farbe, die schon gelegt wurden
|
125
153
|
def deployed_pieces(color)
|
126
154
|
board.deployed_pieces(color)
|
127
155
|
end
|
128
156
|
|
157
|
+
# @return [Bool] Ob diese gamestate in der ersten Runde ist
|
158
|
+
def is_first_move?
|
159
|
+
round == 1
|
160
|
+
end
|
161
|
+
|
129
162
|
# Führt einen Zug auf dem Spielzustand aus. Das Spielbrett wird entsprechend
|
130
163
|
# modifiziert.
|
131
164
|
#
|
@@ -140,6 +173,11 @@ class GameState
|
|
140
173
|
!condition.nil?
|
141
174
|
end
|
142
175
|
|
176
|
+
# Entfernt die jetzige Farbe aus der Farbrotation
|
177
|
+
def remove_active_color
|
178
|
+
ordered_colors.delete current_color
|
179
|
+
end
|
180
|
+
|
143
181
|
# @return [Player] Der Spieler, der das Spiel gewonnen hat, falls dies schon
|
144
182
|
# entschieden ist. Sonst false.
|
145
183
|
def winner
|
@@ -156,22 +194,23 @@ class GameState
|
|
156
194
|
# Rundenlimits beendet wird, hat der Spieler mit den meisten Punkten gewonnen.
|
157
195
|
#
|
158
196
|
# @param player [Player] Der Spieler, dessen Punkte berechnet werden sollen.
|
159
|
-
# @return [Integer] Die Punkte des Spielers
|
160
|
-
|
161
|
-
def points_for_player(player)
|
197
|
+
# @return [Integer] Die Punkte des Spielers
|
198
|
+
def points_for_player(_player)
|
162
199
|
# TODO
|
163
200
|
-1
|
164
201
|
end
|
165
202
|
|
166
203
|
def ==(other)
|
167
204
|
turn == other.turn &&
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
205
|
+
start_color == other.start_color &&
|
206
|
+
current_color == other.current_color &&
|
207
|
+
blue == other.blue &&
|
208
|
+
yellow == other.yellow &&
|
209
|
+
red == other.red &&
|
210
|
+
green == other.green &&
|
211
|
+
board == other.board &&
|
212
|
+
lastMove == other.lastMove &&
|
213
|
+
condition == other.condition
|
175
214
|
end
|
176
215
|
|
177
216
|
# Erzeugt eine Kopie des Spielzustandes. Änderungen an dieser Kopie
|
@@ -186,9 +225,8 @@ class GameState
|
|
186
225
|
@current_player_color = other_player_color
|
187
226
|
end
|
188
227
|
|
189
|
-
# @return [Array<Field>] Alle Felder mit
|
228
|
+
# @return [Array<Field>] Alle Felder mit Blöcken des Spielers, der gerade an der Reihe ist.
|
190
229
|
def own_fields
|
191
|
-
board.fields_of_color(
|
230
|
+
board.fields_of_color(current_color)
|
192
231
|
end
|
193
|
-
|
194
232
|
end
|
@@ -1,31 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Ein Spielstein mit Ausrichtung, Koordinaten und Farbe
|
1
4
|
class Piece
|
5
|
+
# @!attribute [r] Farbe
|
6
|
+
# @return [Color]
|
7
|
+
attr_reader :color
|
2
8
|
|
3
|
-
# @!attribute [r]
|
4
|
-
# @return [
|
5
|
-
attr_reader :
|
9
|
+
# @!attribute [r] Form
|
10
|
+
# @return [PieceShape]
|
11
|
+
attr_reader :kind
|
6
12
|
|
7
|
-
# @!attribute [r]
|
8
|
-
# @return [
|
9
|
-
attr_reader :
|
13
|
+
# @!attribute [r] Drehung
|
14
|
+
# @return [Rotation]
|
15
|
+
attr_reader :rotation
|
16
|
+
|
17
|
+
# @!attribute [r] Ob der Stein an der Y-Achse gespiegelt ist
|
18
|
+
# @return [Boolean]
|
19
|
+
attr_reader :is_flipped
|
20
|
+
|
21
|
+
# @!attribute [r] Koordinaten
|
22
|
+
# @return [Coordinates]
|
23
|
+
attr_reader :position
|
10
24
|
|
11
|
-
|
12
|
-
|
25
|
+
# @!attribute [r] Ein Array der Positionsdaten aller Bestandteile von dem Stein in Board Koordinaten, also schon ggf. gedreht und um position versetzt.
|
26
|
+
# return [Array<Coordinates>]
|
27
|
+
attr_reader :coords
|
28
|
+
|
29
|
+
# Erstellt einen neuen leeren Spielstein.
|
30
|
+
def initialize(color, kind, rotation = Rotation::NONE, is_flipped = false, position = Coordinates.origin)
|
13
31
|
@color = color
|
32
|
+
@kind = kind
|
33
|
+
@rotation = rotation
|
34
|
+
@is_flipped = is_flipped
|
35
|
+
@position = position
|
36
|
+
|
37
|
+
@coords = coords_priv
|
14
38
|
end
|
15
39
|
|
16
|
-
|
17
|
-
|
40
|
+
# Dreht den Stein
|
41
|
+
def rotate!(rotation)
|
42
|
+
@rotation = @rotation.rotate(rotation)
|
43
|
+
@coords = coords_priv
|
44
|
+
end
|
45
|
+
|
46
|
+
# Flipped den Stein
|
47
|
+
def flip!(f = true)
|
48
|
+
@is_flipped = @is_flipped ^ f
|
49
|
+
@coords = coords_priv
|
18
50
|
end
|
19
51
|
|
20
|
-
|
21
|
-
|
52
|
+
# Setzt den Stein auf eine Position
|
53
|
+
def locate!(position)
|
54
|
+
@position = position
|
55
|
+
@coords = coords_priv
|
56
|
+
end
|
57
|
+
|
58
|
+
# Verschiebt den Stein
|
59
|
+
def move!(shift)
|
60
|
+
@position = position + shift
|
61
|
+
@coords = coords_priv
|
62
|
+
end
|
63
|
+
|
64
|
+
# Gibt die Fläche der transformierten Steinform von diesem Stein zurück
|
65
|
+
def area()
|
66
|
+
CoordinateSet.new(coords).area
|
67
|
+
end
|
68
|
+
|
69
|
+
def ==(other)
|
70
|
+
color == other.color &&
|
71
|
+
coords == other.coords
|
22
72
|
end
|
23
73
|
|
24
74
|
def to_s
|
25
|
-
color.
|
75
|
+
"#{color.key} #{kind.key} at #{position} rotation #{rotation.key}#{is_flipped ? ' (flipped)' : ''}"
|
26
76
|
end
|
27
77
|
|
28
78
|
def inspect
|
29
79
|
to_s
|
30
80
|
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def coords_priv
|
85
|
+
kind.transform(@rotation, @is_flipped).transform do |it|
|
86
|
+
Coordinates.new(it.x + @position.x, it.y + @position.y)
|
87
|
+
end.coordinates
|
88
|
+
end
|
31
89
|
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'typesafe_enum'
|
4
|
+
|
5
|
+
require_relative 'coordinates'
|
6
|
+
require_relative 'coordinate_set'
|
7
|
+
|
8
|
+
# Die Form eines Spielsteins. Es gibt folgende Formen:
|
9
|
+
#
|
10
|
+
# MONO
|
11
|
+
# DOMINO
|
12
|
+
# TRIO_L
|
13
|
+
# TRIO_I
|
14
|
+
# TETRO_O
|
15
|
+
# TETRO_T
|
16
|
+
# TETRO_I
|
17
|
+
# TETRO_L
|
18
|
+
# TETRO_Z
|
19
|
+
# PENTO_L
|
20
|
+
# PENTO_T
|
21
|
+
# PENTO_V
|
22
|
+
# PENTO_S
|
23
|
+
# PENTO_Z
|
24
|
+
# PENTO_I
|
25
|
+
# PENTO_P
|
26
|
+
# PENTO_W
|
27
|
+
# PENTO_U
|
28
|
+
# PENTO_R
|
29
|
+
# PENTO_X
|
30
|
+
# PENTO_Y
|
31
|
+
#
|
32
|
+
# Zugriff z.B. mit PieceShape::PENTO_S
|
33
|
+
class PieceShape < TypesafeEnum::Base
|
34
|
+
def self.c(x, y)
|
35
|
+
Coordinates.new(x, y)
|
36
|
+
end
|
37
|
+
new :MONO, [c(0, 0)]
|
38
|
+
new :DOMINO, [c(0, 0), c(1, 0)]
|
39
|
+
new :TRIO_L, [c(0, 0), c(0, 1), c(1, 1)]
|
40
|
+
new :TRIO_I, [c(0, 0), c(0, 1), c(0, 2)]
|
41
|
+
new :TETRO_O, [c(0, 0), c(1, 0), c(0, 1), c(1, 1)]
|
42
|
+
new :TETRO_T, [c(0, 0), c(1, 0), c(2, 0), c(1, 1)]
|
43
|
+
new :TETRO_I, [c(0, 0), c(0, 1), c(0, 2), c(0, 3)]
|
44
|
+
new :TETRO_L, [c(0, 0), c(0, 1), c(0, 2), c(1, 2)]
|
45
|
+
new :TETRO_Z, [c(0, 0), c(1, 0), c(1, 1), c(2, 1)]
|
46
|
+
new :PENTO_L, [c(0, 0), c(0, 1), c(0, 2), c(0, 3), c(1, 3)]
|
47
|
+
new :PENTO_T, [c(0, 0), c(1, 0), c(2, 0), c(1, 1), c(1, 2)]
|
48
|
+
new :PENTO_V, [c(0, 0), c(0, 1), c(0, 2), c(1, 2), c(2, 2)]
|
49
|
+
new :PENTO_S, [c(1, 0), c(2, 0), c(3, 0), c(0, 1), c(1, 1)]
|
50
|
+
new :PENTO_Z, [c(0, 0), c(1, 0), c(1, 1), c(1, 2), c(2, 2)]
|
51
|
+
new :PENTO_I, [c(0, 0), c(0, 1), c(0, 2), c(0, 3), c(0, 4)]
|
52
|
+
new :PENTO_P, [c(0, 0), c(1, 0), c(0, 1), c(1, 1), c(0, 2)]
|
53
|
+
new :PENTO_W, [c(0, 0), c(0, 1), c(1, 1), c(1, 2), c(2, 2)]
|
54
|
+
new :PENTO_U, [c(0, 0), c(0, 1), c(1, 1), c(2, 1), c(2, 0)]
|
55
|
+
new :PENTO_R, [c(0, 1), c(1, 1), c(1, 2), c(2, 1), c(2, 0)]
|
56
|
+
new :PENTO_X, [c(1, 0), c(0, 1), c(1, 1), c(2, 1), c(1, 2)]
|
57
|
+
new :PENTO_Y, [c(0, 1), c(1, 0), c(1, 1), c(1, 2), c(1, 3)]
|
58
|
+
|
59
|
+
@transformations
|
60
|
+
Transform = Struct.new(:r, :f, :coords)
|
61
|
+
|
62
|
+
# Anzahl Felder, die der Stein belegt
|
63
|
+
def size
|
64
|
+
value.size
|
65
|
+
end
|
66
|
+
|
67
|
+
# Die Felder, die der Stein belegt
|
68
|
+
def coordinates
|
69
|
+
CoordinateSet.new(value)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Eine Koordinate, die das kleinstmögliche Rechteck beschreibt, welches alle Felder umfasst.
|
73
|
+
def dimension
|
74
|
+
coordinates.area
|
75
|
+
end
|
76
|
+
|
77
|
+
# Erzeugt eine nach Rotation und Flip transformierte Form
|
78
|
+
def transform(rotation, flip)
|
79
|
+
coordinates.rotate(rotation).flip(flip)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Gibt alle Kombinationen aus Rotation und Flipping zurück, welche zu einzigartigen
|
83
|
+
# Koordinatenmengen dieser Form führen.
|
84
|
+
# @return [Array<Transform>] Transform Structs mit Rotation r, Boolean f
|
85
|
+
def unique_transforms()
|
86
|
+
if not defined? @transformations then
|
87
|
+
existing_transforms = []
|
88
|
+
|
89
|
+
Rotation.each do |r|
|
90
|
+
[true, false].each do |f|
|
91
|
+
new_transform = Transform.new(r, f, transform(r, f))
|
92
|
+
|
93
|
+
if existing_transforms.none? { |t| t.coords == new_transform.coords } then
|
94
|
+
existing_transforms << new_transform
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
@transformations = existing_transforms
|
100
|
+
end
|
101
|
+
|
102
|
+
@transformations
|
103
|
+
end
|
104
|
+
|
105
|
+
# Gibt den Form Namen zurück
|
106
|
+
def to_s
|
107
|
+
self.key.to_s
|
108
|
+
end
|
109
|
+
end
|