This code pre-calculates the winning combinations for an n-sized tic tac toe board.
I first created my function using an imperative approach. This is just how I naturally write code most of the time. I then tried to think about the problem using a "What I want to accomplish?" approach, rather than "What do I want it to do?" In the end I think I still ended up with an imperative approach, just using STL algorithms as loops.
Imperative approach:
std::vector<std::vector<int>> rules3(const int x){
using namespace std;
vector<vector<int>> seqs;
for(int n=0; n<x; ++n){
vector<int> seq;
for(int m=0; m<x; ++m){
seq.push_back(n*x+m);
}
seqs.push_back(seq);
}
for(int n=0; n<x; ++n){
vector<int> seq;
for(int m=0; m<x; ++m){
seq.push_back(n+x*m);
}
seqs.push_back(seq);
}
vector<int> seq;
for(int n=0; n<x; ++n){
seq.push_back(n*x+n);
}
seqs.push_back(seq);
seq.clear();
for(int n=0; n<x; ++n){
seq.push_back(x-1+n*(x-1));
}
seqs.push_back(seq);
return seqs;
}
Getting more functional:
std::vector<std::vector<int>> rules2(const int x){
using namespace std;
vector<vector<int>> seqs;
vector<int> iter(x);
iota(iter.begin(), iter.end(), 0);
for(auto n: iter){
vector<int> seq;
for(auto m: iter){
seq.push_back(n*x+m);
}
seqs.push_back(seq);
}
for(auto n: iter){
vector<int> seq;
for(auto m: iter){
seq.push_back(n+x*m);
}
seqs.push_back(seq);
}
vector<int> seq;
seq.clear();
for(auto n: iter){
seq.push_back(n*x+n);
}
seqs.push_back(seq);
seq.clear();
for(auto n: iter){
seq.push_back(x-1+n*(x-1));
}
seqs.push_back(seq);
return seqs;
}
Functional approach? (still feels imperative):
std::vector<std::vector<int>> rules1(const int x){
using namespace std;
vector<vector<int>> seqs;
vector<int> iter(x);
iota(iter.begin(), iter.end(), 0);
transform(iter.begin(), iter.end(), back_inserter(seqs), [&](const int& n){
vector<int> seq;
transform(iter.begin(), iter.end(), back_inserter(seq), [&](const int& m){
return n*x+m;
});
return seq;
});
transform(iter.begin(), iter.end(), back_inserter(seqs), [&](const int& n){
vector<int> seq;
transform(iter.begin(), iter.end(), back_inserter(seq), [&](const int& m){
return n+x*m;
});
return seq;
});
vector<int> seq;
transform(iter.begin(), iter.end(), back_inserter(seq), [&](const int& n){
return n*x+n;
});
seqs.push_back(seq);
seq.clear();
transform(iter.begin(), iter.end(), back_inserter(seq), [&](const int& n){
//return (x-n-1)*x+n; // 6,4,2
return x-1+n*(x-1); // 2,4,6
});
seqs.push_back(seq);
return seqs;
}
Output when printing:
rules3
std::vector(0, 1, 2)
std::vector(3, 4, 5)
std::vector(6, 7, 8)
std::vector(0, 3, 6)
std::vector(1, 4, 7)
std::vector(2, 5, 8)
std::vector(0, 4, 8)
std::vector(2, 4, 6)
rules2
std::vector(0, 1, 2)
std::vector(3, 4, 5)
std::vector(6, 7, 8)
std::vector(0, 3, 6)
std::vector(1, 4, 7)
std::vector(2, 5, 8)
std::vector(0, 4, 8)
std::vector(2, 4, 6)
rules1
std::vector(0, 1, 2)
std::vector(3, 4, 5)
std::vector(6, 7, 8)
std::vector(0, 3, 6)
std::vector(1, 4, 7)
std::vector(2, 5, 8)
std::vector(0, 4, 8)
std::vector(2, 4, 6)