Skip to content

Instantly share code, notes, and snippets.

@practicingruby
Created October 25, 2011 00:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save practicingruby/1310883 to your computer and use it in GitHub Desktop.
Save practicingruby/1310883 to your computer and use it in GitHub Desktop.
# Looking to reduces rows of board game data to
# primitives (for eventual JSON output).
# each cell can be either unoccupied, or occupied by N
# armies of a given color. What data format do you prefer,
# and why?
#----------------------------------------------------------
# 1) nil indicates empty territory
[[:white, 2], nil, [:black, 3]]
# 2) :empty indicates empty territory
[[:white, 2], :empty, [:black, 3]]
# 3) somewhat homogenous. nil indicates count being non-applicable
[[:white, 2], [:empty, nil], [:black, 3]]
# 4) fully homogenous. 0 indicates no units of either color present
[[:white, 2], [:empty, 0], [:black, 3]]
# your own representation (leave a note in the comments)
@steveklabnik
Copy link

nil sucks. #4.

@locks
Copy link

locks commented Oct 25, 2011

what steveklabnik said.
it's a bit more verbose, but consistent/homogenous.

@radar
Copy link

radar commented Oct 25, 2011

Agreed, #4.

@skalnik
Copy link

skalnik commented Oct 25, 2011

#4. It's the most obvious in what it's trying to convey. What's the advantage of the others?

@semmons99
Copy link

I give #4 five 🐨

🐨 🐨 🐨 🐨 🐨

It makes for a consistent data structure and gets rid of nil.

@practicingruby
Copy link
Author

@skalnik: The others might be slightly easier to use in case statements, but otherwise don't offer any advantages over #4, it seems.

@ljsc
Copy link

ljsc commented Oct 25, 2011

I guess I'll be the dissenting vote here. I think [:empty, 0] is duplication. Personally, I'd go with:

[[2, :white], 0, [3, :black]] 

@practicingruby
Copy link
Author

@ljsc: Hmm... that seems fundamentally different than any of the examples I've shown. While I can see breaking homogeneity to introduce nil as a "not applicable" value, or a symbol as a sort of label for a "not applicable" value, introducing a 0 masks intent and isn't easy to infer a rule from just by looking at the dataset. Did I miss some advantage?

@tundal45
Copy link

#4 get's my vote.

@ljsc
Copy link

ljsc commented Oct 25, 2011

I think semantically the fact that you have 0 things in that position already denotes that it's :empty—thus you are duplicating that information. It seems like the color of the thing is only pertinent if there is anything there in the first place.

It's probably just my propensity to add mathematical properties to type domains (probably YAGNI in this case): I can see why others would favor consistency of #4, however.

@semmons99
Copy link

Okay, here's an off-the-wall idea:

[-2,0,3]

Indicates 2 white in the first position, 0 in second, and 3 black in the third. So, negative is white, positive is black, 0 is empty.

@practicingruby
Copy link
Author

@semmons99: That's a really bad idea. Think about all the extra logic you'd need to support that :)

@ljsc
Copy link

ljsc commented Oct 25, 2011

@sandal @semmons99 Unless the logic of the game dictated that whenever two opposing armies battled one another, the pieces canceled each other out. In that case using signed integers would be an elegant solution. Absent that, however, I agree: again you ain't gonna need it.

@semmons99
Copy link

@sandal I agree it's bad ✨

@practicingruby
Copy link
Author

@ljsc @semmons99: I almost corrected myself because my logic is close to that, but not quite there. the difference is that it'd transfer from -1 to 1 (or vice versa) during a fight, and I'd need to add a special case.

@phiggins
Copy link

Out of the listed strategies, I'd say #4 is the one I'd prefer. However, we're making an uninformed decision without knowing the implementation behind this.

The most obvious thing to me while sticking with the general format outlined would be:

[[:white, 2], [], [:black, 3]]

Then for the implementation, something like:

class Territory < Struct.new(:occupier, :armies)
  alias occupied? occupier
end

Why render the board as an array though? Why not a hash?

TERRITORIES = Hash.new { UnnocupiedTerritory.new }
TERRITORIES.merge! {:kamchatka => [:white, 2], :irkutsk => [:black, 3]} # Risk is TM Hasbro

Disclaimer: I am very sick right now. I apologize if this is incomprehensible.

@gvc
Copy link

gvc commented Oct 25, 2011

#4 is the best to me!

@practicingruby
Copy link
Author

@phiggins: Interesting ideas, thanks for sharing. The board is an NxN grid, so an array of arrays makes sense for this game.

The context is important, but it's okay to assume it's a generic board in which cells can be empty, or have n cells of a given color (either white or black)

@adkron
Copy link

adkron commented Oct 25, 2011

Maybe you should look at using a class for each cell. At that point it would be easier to extend and add other information or maybe some behavior to a cell. You could also make it more clear with intention reviling method name. I have often wanted to add unary operators to game cells.

@arwagner
Copy link

Not to go all "appeal to authority" on you, but I just read this last night, and thought it worth mentioning:

The more code we write, the more we're convinced that we should define types to represent value concepts in the domain, even if they don't do much. It helps to create a consistent domain model that is more self-explanatory. If we create, for example, an Item type in a system, instead of just using String, we can find all the code that's relevant for a change without having to chase through the method calls. Specific types also reduce the risk of confusion -- as the Mars Climate Orbiter disaster showed, feet and metres may both be represented as numbers but they're different things. Finally, once we have a type to represent a concept, it usually turns out to be a good place to hang behavior, guiding us towards using a more object-oriented approach instead of scattering related behavior across the code.

-- Growing Object Oriented Software, Guided by Tests

@practicingruby
Copy link
Author

@adkron, @arwagner: I am using a class for each cell, I just need to reduce things to primitives for serialization purposes.

@adkron
Copy link

adkron commented Oct 26, 2011

In that case I would go with number 4. I like constancy in my data and api. If the empty cells are going to take up too much space then I would go with 1 to save space.

@fguillen
Copy link

I go for #4, after all the advantages already said, I'd add the self-documented style.

As you said is a serialization structure what we are defining here, so would be possible to think it is gonna be drunk up by external systems, better then that the info has an implicit way to be understood.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment