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"
)

Parameters:

  • conditions_hash (Hash)

    validated conditions with symbol keys



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"
})

Parameters:

  • data (Hash)

    conditions data with string or symbol keys

Returns:

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)

Parameters:

  • value (Object)

    the value to validate

Returns:

  • (Boolean)

    true if valid state value



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

Parameters:

  • other (Object)

    object to compare with

Returns:

  • (Boolean)

    true if conditions are equal



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

Parameters:

  • location (Symbol, String)

    the location coordinate

Returns:

  • (String, nil)

    state value or nil if location not present



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

Returns:

  • (Enumerator)

    if no block given



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

Returns:

  • (Enumerator)

    if no block given



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

Returns:

  • (Enumerator)

    if no block given



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

Returns:

  • (Boolean)

    true if no conditions



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]

Returns:

  • (Array<Symbol>)

    locations that must be empty



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]

Returns:

  • (Array<Symbol>)

    locations that must contain enemy pieces



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

Returns:

  • (Integer)

    hash code



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

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

#inspectString

String representation for debugging

Returns:

  • (String)

    human-readable representation



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"]

Returns:

  • (Array<String>)

    unique keywords used in conditions



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

Returns:

  • (Boolean)

    true if any reserved keywords are present



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

Parameters:

  • location (Symbol, String)

    the location to check

Returns:

  • (Boolean)

    true 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

Returns:

  • (Array<Symbol>)

    all location coordinates as 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]

Returns:

  • (Array<Symbol>)

    locations with QPI piece requirements



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"]

Returns:

  • (Array<String>)

    unique QPI identifiers used in conditions



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

Returns:

  • (Boolean)

    true if any QPI identifiers are present



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

Returns:

  • (Integer)

    number of location 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

Returns:

  • (Hash)

    conditions as a 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

Returns:

  • (String)

    conditions as string



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

Parameters:

  • location (Symbol, String)

    the location to validate

Returns:

  • (Boolean)

    true if 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

Parameters:

  • value (Object)

    the value to validate

Returns:

  • (Boolean)

    true if valid state value



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

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