HiveBrain v1.2.0
Get Started
← Back to all entries
patternrubyMinor

Breaking a chess coordinate string into 2D coordinates

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
coordinatesintocoordinatebreakingchessstring

Problem

Given a chess coordinate as a string (e.g. "a1") I'd like to transform it into a 2-D array (so, for "a1" I'd like to get [1,1]).

Here's what I came up with:

def safe_pawns(pawns)
  pawns.inject([]){|res, pwn| res << [pwn.split('')[0].index(/[a-h]/) + 1, pwn.split('')[1].to_i]}
end


Can anyone suggest a refactoring please to make it more idiomatic Ruby?

Solution

-
Give your code some breathing room. I.e. ) { |a, b| instead of ){|a, b|. And there's no need to put everything on one line. The way your block works right now, it'd be better to store the result of pwn.split in a variable, instead of calling split twice. (There's also no need to abbrevate "pawn" as "pwn".)

-
That being said, strings support array-like access, so you don't need the split at all.

-
Judging from your code, pawns is an array. Transforming an n-element array to a new n-element array is called "mapping". You're using inject which is also known as reduce (and fold in many other languages; see comments) - an operation most often used to take an n-element array and reduce it to a single value. So step 1: Use map instead of inject.

-
I'd probably use a regex to pull the string apart. It'll double as a way to check the coordinate strings for validity (e.g. so no "z9" coordinates will slip through).

-
It's a little low-level, but we can use the fact that "a" is 97 in ASCII. So to get the number for a letter, we can say letter.ord - 96.

You get something like this:

def safe_pawns(squares)
  squares.map do |square|
    [$1.ord - 96, $2.to_i] if square.downcase =~ /^([a-h])([1-8])$/
  end.compact
end


Alternatively, if you're sure that all the input coordinates are valid, lowercase strings already, you don't need the regex or the downcasing:

def safe_pawns(squares)
  squares.map { |square| [square[0].ord - 96, square[1].to_i] }
end


As tokland points out in the comments, we can avoid the hardcoded 96 (which isn't very self-explanatory) and instead get the letter-to-number translation by saying:

square[0].ord - 'a'.ord + 1

Code Snippets

def safe_pawns(squares)
  squares.map do |square|
    [$1.ord - 96, $2.to_i] if square.downcase =~ /^([a-h])([1-8])$/
  end.compact
end
def safe_pawns(squares)
  squares.map { |square| [square[0].ord - 96, square[1].to_i] }
end
square[0].ord - 'a'.ord + 1

Context

StackExchange Code Review Q#62616, answer score: 9

Revisions (0)

No revisions yet.