Class: Snake

Inherits:
Object
  • Object
show all
Defined in:
lib/snake.rb

Defined Under Namespace

Classes: BodyPart, PreviousVectorRecord

Constant Summary collapse

DIRECTION_HASH =
{
  # We are in graphics land, so 0, 0 is the origin,
  # and the y axis goes down _positively_
  Curses::KEY_UP => Point.new(0, -1),
  Curses::KEY_DOWN => Point.new(0, 1),
  Curses::KEY_RIGHT => Point.new(1, 0),
  Curses::KEY_LEFT => Point.new(-1, 0)
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(starting_position:, vector:) ⇒ Snake

Returns a new instance of Snake.



45
46
47
48
49
50
51
# File 'lib/snake.rb', line 45

def initialize(starting_position:, vector:)
  @head = starting_position
  @vector = vector
  @current_direction = DIRECTION_HASH.invert[vector]
  @body = []
  @previous_vector_changes = {}
end

Instance Attribute Details

#bodyObject

Returns the value of attribute body.



43
44
45
# File 'lib/snake.rb', line 43

def body
  @body
end

#headObject

Returns the value of attribute head.



43
44
45
# File 'lib/snake.rb', line 43

def head
  @head
end

Instance Method Details

#add_body_partObject



57
58
59
60
61
62
63
64
# File 'lib/snake.rb', line 57

def add_body_part
  if @body.empty?
    @body << BodyPart.new(@head - @vector, @vector)
  else
    @body << BodyPart.new(@body.last.position - @body.last.vector, @body.last.vector)
  end
  @previous_vector_changes.values.each(&:increment)
end

#handle_food(food, next_head_position) ⇒ Object



66
67
68
69
70
71
72
# File 'lib/snake.rb', line 66

def handle_food(food, next_head_position)
  if next_head_position.eql? food
    2.times { add_body_part }
    return nil
  end
  food
end

#head_directionObject



102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/snake.rb', line 102

def head_direction
  case @current_direction
  when Curses::KEY_UP
    '^'
  when Curses::KEY_DOWN
    'v'
  when Curses::KEY_RIGHT
    '>'
  when Curses::KEY_LEFT
    '<'
  end
end

#positionsObject



53
54
55
# File 'lib/snake.rb', line 53

def positions
  [@head] + @body
end

#process_direction(direction) ⇒ Object



94
95
96
97
98
99
100
# File 'lib/snake.rb', line 94

def process_direction(direction)
  return if direction.nil?
  @current_direction = direction if DIRECTION_HASH.keys.include?(direction)
  @vector = DIRECTION_HASH[direction] || @vector
  5.times { add_body_part } if direction == 'a'
  @previous_vector_changes[head] = PreviousVectorRecord.new(@vector, @body.length + 1)
end

#tick(food) ⇒ Object

Raises:



83
84
85
86
87
88
89
90
91
92
# File 'lib/snake.rb', line 83

def tick(food)
  next_head_position = head + @vector
  raise IllegalStateError if body.any? {|part| part.position == next_head_position }
  food = handle_food(food, next_head_position)
  update_body
  @head = next_head_position
  @previous_vector_changes.values.each(&:decrement)
  @previous_vector_changes.select! { |key, val| val.valid? }
  food
end

#update_bodyObject



74
75
76
77
78
79
80
81
# File 'lib/snake.rb', line 74

def update_body
  @body.map do |part|
    if new_vector_record = @previous_vector_changes[part.position]
      part.vector = new_vector_record.vector
    end
    part.position = part.position + part.vector
  end
end