Class: Sashite::Lcn::Conditions

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/sashite/lcn/conditions.rb

Overview

Represents a set of location conditions in LCN format

This class provides an immutable, functional interface for working with location conditions. All instances are frozen after creation to ensure thread safety and prevent accidental mutations.

Conditions are stored internally with symbol keys for Ruby idiomatic access while supporting flexible input formats (string or symbol keys).

Examples:

Creating conditions

conditions = Sashite::Lcn::Conditions.new(
  e4: "empty",
  f5: "enemy",
  h1: "C:+R"
)

Accessing conditions

conditions[:e4]          # => "empty"
conditions.locations     # => [:e4, :f5, :h1]
conditions.size          # => 3

Analyzing conditions

conditions.empty_locations    # => [:e4]
conditions.enemy_locations    # => [:f5]
conditions.piece_locations    # => [:h1]
conditions.keywords?      # => true
conditions.qpi_identifiers? # => true

Constant Summary collapse

EMPTY_KEYWORD =

Reserved keywords from LCN specification

"empty"
ENEMY_KEYWORD =
"enemy"
RESERVED_KEYWORDS =
[EMPTY_KEYWORD, ENEMY_KEYWORD].freeze
ERROR_INVALID_LOCATION =

Error messages

"Invalid CELL coordinate: %s"
ERROR_INVALID_STATE =
"Invalid state value: %s"
ERROR_NOT_HASH =
"Conditions data must be a Hash"

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(**conditions_hash) ⇒ Conditions

Note:

The hash is duplicated and frozen to ensure immutability

Create a new Conditions instance

Examples:

Direct creation with keyword arguments

conditions = Sashite::Lcn::Conditions.new(
  e4: "empty",
  f5: "enemy"
)


58
59
60
61
62
# File 'lib/sashite/lcn/conditions.rb', line 58

def initialize(**conditions_hash)
  # Deep duplicate to ensure complete isolation
  @conditions = conditions_hash.dup.freeze
  freeze
end

Class Method Details

.parse(data) ⇒ Conditions

Parse and create a Conditions instance from raw data

Accepts both string and symbol keys, normalizing to symbols internally. Validates all locations and state values before creating the instance.

Examples:

Parse with string keys

conditions = Sashite::Lcn::Conditions.parse({
  "e4" => "empty",
  "f5" => "enemy"
})

Parse with symbol keys

conditions = Sashite::Lcn::Conditions.parse({
  e4: "empty",
  f5: "enemy"
})

Raises:

  • (ArgumentError)

    if data is invalid



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/sashite/lcn/conditions.rb', line 84

def self.parse(data)
  raise ArgumentError, ERROR_NOT_HASH unless data.is_a?(Hash)

  validated = {}

  data.each do |location, state_value|
    location_str = location.to_s

    raise ArgumentError, format(ERROR_INVALID_LOCATION, location_str) unless Cell.valid?(location_str)

    raise ArgumentError, format(ERROR_INVALID_STATE, state_value) unless valid_state_value?(state_value)

    validated[location_str.to_sym] = state_value
  end

  new(**validated)
end

.valid_state_value?(value) ⇒ Boolean

Check if a state value is valid (class method for internal use)



318
319
320
321
322
323
324
325
326
# File 'lib/sashite/lcn/conditions.rb', line 318

def self.valid_state_value?(value)
  return false unless value.is_a?(String)

  # Check if it's a reserved keyword
  return true if RESERVED_KEYWORDS.include?(value)

  # Otherwise, check if it's a valid QPI identifier
  Qpi.valid?(value)
end

Instance Method Details

#==(other) ⇒ Boolean Also known as: eql?

Check equality with another Conditions instance



284
285
286
287
288
# File 'lib/sashite/lcn/conditions.rb', line 284

def ==(other)
  return false unless other.is_a?(self.class)

  @conditions == other.to_h
end

#[](location) ⇒ String?

Get state value for a location

Examples:

conditions[:e4]     # => "empty"
conditions["e4"]    # => "empty"
conditions[:z9]     # => nil


118
119
120
# File 'lib/sashite/lcn/conditions.rb', line 118

def [](location)
  @conditions[location.to_sym]
end

#each {|location, state_value| ... } ⇒ Enumerator

Iterate over location-state pairs

Examples:

conditions.each do |location, state|
  puts "#{location}: #{state}"
end

Yields:

  • (location, state_value)

    each location-state pair

Yield Parameters:

  • location (Symbol)

    location coordinate as symbol

  • state_value (String)

    state value



242
243
244
245
246
# File 'lib/sashite/lcn/conditions.rb', line 242

def each(&)
  return enum_for(:each) unless block_given?

  @conditions.each(&)
end

#each_location {|location| ... } ⇒ Enumerator

Iterate over locations only

Examples:

conditions.each_location do |location|
  puts location
end

Yields:

  • (location)

    each location

Yield Parameters:

  • location (Symbol)

    location coordinate as symbol



258
259
260
261
262
# File 'lib/sashite/lcn/conditions.rb', line 258

def each_location(&)
  return enum_for(:each_location) unless block_given?

  @conditions.each_key(&)
end

#each_state_value {|state_value| ... } ⇒ Enumerator

Iterate over state values only

Examples:

conditions.each_state_value do |state|
  puts state
end

Yields:

  • (state_value)

    each state value

Yield Parameters:

  • state_value (String)

    state value



274
275
276
277
278
# File 'lib/sashite/lcn/conditions.rb', line 274

def each_state_value(&)
  return enum_for(:each_state_value) unless block_given?

  @conditions.each_value(&)
end

#empty?Boolean

Check if no conditions are specified



139
140
141
# File 'lib/sashite/lcn/conditions.rb', line 139

def empty?
  @conditions.empty?
end

#empty_locationsArray<Symbol>

Get locations requiring empty state

Examples:

conditions.empty_locations  # => [:e4, :f1, :g1]


207
208
209
# File 'lib/sashite/lcn/conditions.rb', line 207

def empty_locations
  @conditions.select { |_, v| v == EMPTY_KEYWORD }.keys
end

#enemy_locationsArray<Symbol>

Get locations requiring enemy pieces

Examples:

conditions.enemy_locations  # => [:f5]


217
218
219
# File 'lib/sashite/lcn/conditions.rb', line 217

def enemy_locations
  @conditions.select { |_, v| v == ENEMY_KEYWORD }.keys
end

#hashInteger

Generate hash code for use in Hash and Set



296
297
298
# File 'lib/sashite/lcn/conditions.rb', line 296

def hash
  [self.class, @conditions].hash
end

#inspectString

String representation for debugging



303
304
305
# File 'lib/sashite/lcn/conditions.rb', line 303

def inspect
  "#<#{self.class.name} #{@conditions.inspect}>"
end

#keywordsArray<String>

Get array of keyword state values used

Examples:

conditions.keywords  # => ["empty", "enemy"]


173
174
175
# File 'lib/sashite/lcn/conditions.rb', line 173

def keywords
  @conditions.values.select { |v| RESERVED_KEYWORDS.include?(v) }.uniq
end

#keywords?Boolean

Check if any keywords are used



190
191
192
# File 'lib/sashite/lcn/conditions.rb', line 190

def keywords?
  @conditions.values.any? { |v| RESERVED_KEYWORDS.include?(v) }
end

#location?(location) ⇒ Boolean

Check if location has a condition



147
148
149
# File 'lib/sashite/lcn/conditions.rb', line 147

def location?(location)
  @conditions.key?(location.to_sym)
end

#locationsArray<Symbol>

Get array of all location symbols



125
126
127
# File 'lib/sashite/lcn/conditions.rb', line 125

def locations
  @conditions.keys
end

#piece_locationsArray<Symbol>

Get locations requiring specific pieces

Examples:

conditions.piece_locations  # => [:h1, :e1]


227
228
229
# File 'lib/sashite/lcn/conditions.rb', line 227

def piece_locations
  @conditions.reject { |_, v| RESERVED_KEYWORDS.include?(v) }.keys
end

#qpi_identifiersArray<String>

Get array of QPI identifiers used

Examples:

conditions.qpi_identifiers  # => ["C:+R", "c:p"]


183
184
185
# File 'lib/sashite/lcn/conditions.rb', line 183

def qpi_identifiers
  @conditions.values.reject { |v| RESERVED_KEYWORDS.include?(v) }.uniq
end

#qpi_identifiers?Boolean

Check if any QPI identifiers are used



197
198
199
# File 'lib/sashite/lcn/conditions.rb', line 197

def qpi_identifiers?
  @conditions.values.any? { |v| !RESERVED_KEYWORDS.include?(v) }
end

#sizeInteger

Get number of conditions



132
133
134
# File 'lib/sashite/lcn/conditions.rb', line 132

def size
  @conditions.size
end

#to_hHash

Convert to hash with symbol keys



105
106
107
# File 'lib/sashite/lcn/conditions.rb', line 105

def to_h
  @conditions.dup
end

#to_sString

String representation



310
311
312
# File 'lib/sashite/lcn/conditions.rb', line 310

def to_s
  @conditions.to_s
end

#valid_location?(location) ⇒ Boolean

Check if location uses valid CELL coordinate



155
156
157
# File 'lib/sashite/lcn/conditions.rb', line 155

def valid_location?(location)
  Cell.valid?(location.to_s)
end

#valid_state_value?(value) ⇒ Boolean

Check if state value is valid



163
164
165
# File 'lib/sashite/lcn/conditions.rb', line 163

def valid_state_value?(value)
  self.class.valid_state_value?(value)
end