Just for exercise, if people want to give it a go; see how creative one can be.
Problem Statement: Given a list of data from a file( or user input which ever) as such:
char 1
char 2
char 26
char 27
char 52
char 53
output the mapping of the number like so:
char 1 => 'a'
char 2 => 'b'
char 26 = 'z'
char 27 => 'A'
char 52 => 'Z'
char 53 => 'aa'
If you don't see the pattern then here it is:
[1...26] gets mapped to ['a'...'z']
[27...52] gets mapped to ['A'...'Z']
any thing after 52, ex 53 getswrapped back. For example 53 gets wrapped to 'aa' or 54 gets wrapped to 'bb' or 79 gets wrapped to 'AA'
Free to use any language paradigm....blah...blah...blah, just make sure its understandable.
Difficulty: 2.0f/5.0f
make a simple array container add 2 functios such as add() and operator[]
witch knows the number ranges :)
Something along the lines of:
string alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
string input;
getline(cin,input);
stringstream ss(input);
unsigned int value = 0;
ss >> value;
if(value <= 0)
{
cerr << "Program encountered an unexpected error and will now exit. (Mwuahahaha!)" << endl;
return 1;
}
cout << "value = " << value << endl;
//j is the current index into "alphabet"
//r is the number of times it has wrapped around.
//i is simply used by the loop as the "loop-control" variable.
string::size_type i = 0, j = 0, r = 0;
for( ; i < value; i++, j++)
{
if(j == alphabet.size()) { j = 0; r++; }
}
string output;
for( string::size_type k = 0; k < (r+1); k++ )
{
output += alphabet[j-1];
}
cout << "Output = " << output << endl;Or maybe something along the lines of:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main() {
ifstream infile("input.txt");
ofstream outfile("output.txt");
int value;
while(infile >> value) {
char mod_val = (--value) % 52;
outfile << string(value / 52 + 1,
(mod_val < 26 ? mod_val + 'a' : (mod_val - 26) + 'A'))
<< endl;
};
return 0;
};Or maybe something along the lines of:
#include <iostream> #include <fstream> #include <string> using namespace std; int main() { ifstream infile("input.txt"); ofstream outfile("output.txt"); int value; while(infile >> value) { char mod_val = (--value) % 52; outfile << string(value / 52 + 1, (mod_val < 26 ? mod_val + 'a' : (mod_val - 26) + 'A')) << endl; }; return 0; };
The only problem being the assumption of adjacent letters in the character set. Only digits are guaranteed to be contiguous. But great minds think alike, because my solution is different from yours only in that I used a custom alphabet:
#include <type_traits>
namespace jsw {
/**
* @brief Subtract y from x
* @remarks Moves in an absolute negative direction while preserving sign
*/
template <typename T>
T subtract(T x, T y, typename std::enable_if<std::is_integral<T>::value>::type* = 0)
{
return (x >= 0) ? x - y : x + y;
}
/**
* @brief Calculates the remainder of x / y
* @remarks Behavior is sign agnostic (equivalent regardless of sign)
*/
template <typename T>
T mod(T x, T y, typename std::enable_if<std::is_integral<T>::value>::type* = 0)
{
return (x % y + y) % y;
}
}
#include <cstdlib>
#include <iostream>
#include <string>
int main()
{
std::string const buf = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
int value;
while (std::cin >> value) {
value = jsw::subtract(value, 1);
int const n_wrap = std::abs(value) / buf.size() + 1;
int const index = jsw::mod(value, (int)buf.size());
std::cout << std::string(n_wrap, buf[index]) << '\n';
}
}Yeah now I'm depressed I didn't do the modulus thing. I was thinking about it I swear!
This isn't much of a challenge as it is now, so I decided to do the interesting stuff during compilation.
EDIT: A boost preprocessor array can't have more than 25 elements. That's why I had to split the letters like that.
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/preprocessor/comparison/less.hpp>
#include <boost/preprocessor/arithmetic/add.hpp>
#include <boost/preprocessor/arithmetic/sub.hpp>
#include <boost/preprocessor/arithmetic/div.hpp>
#include <boost/preprocessor/arithmetic/mod.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/array/elem.hpp>
#include <boost/preprocessor/control/if.hpp>
#define LETTERS_a_m (13, ("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"))
#define LETTERS_n_z (13, ("n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"))
#define LETTERS_A_M (13, ("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M"))
#define LETTERS_N_Z (13, ("N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"))
#define LETTER_LOWER(n) \
BOOST_PP_IF(BOOST_PP_LESS(n, 13), \
BOOST_PP_ARRAY_ELEM(n, LETTERS_a_m), \
BOOST_PP_ARRAY_ELEM(BOOST_PP_SUB(n, 13), LETTERS_n_z))
#define LETTER_UPPER(n) \
BOOST_PP_IF(BOOST_PP_LESS(n, 13), \
BOOST_PP_ARRAY_ELEM(n, LETTERS_A_M), \
BOOST_PP_ARRAY_ELEM(BOOST_PP_SUB(n, 13), LETTERS_N_Z))
#define LETTER(z, n, letter_id) \
BOOST_PP_IF(BOOST_PP_LESS(letter_id, 27), \
LETTER_LOWER(BOOST_PP_SUB(letter_id, 1)), \
LETTER_UPPER(BOOST_PP_SUB(letter_id, 27)))
#define PRINT_LETTER(r, unused, n) \
BOOST_PP_REPEAT(BOOST_PP_ADD(BOOST_PP_DIV(n, 52), 1), LETTER, BOOST_PP_MOD(n, 52)) "\n"
#include <cstdio>
#define INPUT (1)(2)(4)(8)(16)(32)(50)(64)(100)(128)(150)
int main()
{
const char * output = BOOST_PP_SEQ_FOR_EACH(PRINT_LETTER, ~, INPUT);
printf(output);
fflush(stdout);
return 0;
} Compiler output: .file "main.cpp"
.def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"
LC0:
.ascii <strong>"a\12b\12d\12h\12p\12F\12X\12ll\12VV\12xxx\12TTT\0"</strong>
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $16, %esp
call ___main
movl $LC0, (%esp)
call _puts
movl __imp___iob, %eax
addl $32, %eax
movl %eax, (%esp)
call _fflush
xorl %eax, %eax
leave
ret
.def _puts; .scl 2; .type 32; .endef
.def _fflush; .scl 2; .type 32; .endef
This isn't much of a challenge as it is now, so I decided to do the interesting stuff during compilation.
EDIT: A boost preprocessor array can't have more than 25 elements. That's why I had to split the letters like that.
#include <boost/preprocessor/repetition/repeat.hpp> #include <boost/preprocessor/comparison/less.hpp> #include <boost/preprocessor/arithmetic/add.hpp> #include <boost/preprocessor/arithmetic/sub.hpp> #include <boost/preprocessor/arithmetic/div.hpp> #include <boost/preprocessor/arithmetic/mod.hpp> #include <boost/preprocessor/seq/for_each.hpp> #include <boost/preprocessor/array/elem.hpp> #include <boost/preprocessor/control/if.hpp> #define LETTERS_a_m (13, ("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m")) #define LETTERS_n_z (13, ("n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z")) #define LETTERS_A_M (13, ("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M")) #define LETTERS_N_Z (13, ("N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z")) #define LETTER_LOWER(n) \ BOOST_PP_IF(BOOST_PP_LESS(n, 13), \ BOOST_PP_ARRAY_ELEM(n, LETTERS_a_m), \ BOOST_PP_ARRAY_ELEM(BOOST_PP_SUB(n, 13), LETTERS_n_z)) #define LETTER_UPPER(n) \ BOOST_PP_IF(BOOST_PP_LESS(n, 13), \ BOOST_PP_ARRAY_ELEM(n, LETTERS_A_M), \ BOOST_PP_ARRAY_ELEM(BOOST_PP_SUB(n, 13), LETTERS_N_Z)) #define LETTER(z, n, letter_id) \ BOOST_PP_IF(BOOST_PP_LESS(letter_id, 27), \ LETTER_LOWER(BOOST_PP_SUB(letter_id, 1)), \ LETTER_UPPER(BOOST_PP_SUB(letter_id, 27))) #define PRINT_LETTER(r, unused, n) \ BOOST_PP_REPEAT(BOOST_PP_ADD(BOOST_PP_DIV(n, 52), 1), LETTER, BOOST_PP_MOD(n, 52)) "\n" #include <cstdio> #define INPUT (1)(2)(4)(8)(16)(32)(50)(64)(100)(128)(150) int main() { const char * output = BOOST_PP_SEQ_FOR_EACH(PRINT_LETTER, ~, INPUT); printf(output); fflush(stdout); return 0; }Compiler output:
.file "main.cpp" .def ___main; .scl 2; .type 32; .endef .section .rdata,"dr" LC0: .ascii <strong>"a\12b\12d\12h\12p\12F\12X\12ll\12VV\12xxx\12TTT\0"</strong> .text .globl _main .def _main; .scl 2; .type 32; .endef _main: pushl %ebp movl %esp, %ebp andl $-16, %esp subl $16, %esp call ___main movl $LC0, (%esp) call _puts movl __imp___iob, %eax addl $32, %eax movl %eax, (%esp) call _fflush xorl %eax, %eax leave ret .def _puts; .scl 2; .type 32; .endef .def _fflush; .scl 2; .type 32; .endef
Thats so not fair, I still have no complete idea what the hell is going on. Mainly because I never gave enough time to learn metaprogramming and boost metaprogramming. Anyways I'll take your word for it to work. Thats pretty cool.
Thats pretty cool.
Haha, thanks! :D
There is a bug in the code above though... It won't work for some edge cases
(e.g. 52 is mapped to "aa" (as is 53) instead of "Z"). I realised it too late to edit
it and correct it (BTW, what's this thing with the 30 minute limit to editing? Why
can't I edit my posts whenever I want?). PRINT_LETTER should look like this: #define PRINT_LETTER(r, unused, n) \ I never gave enough time to learn metaprogramming
BOOST_PP_REPEAT(BOOST_PP_ADD(BOOST_PP_DIV(BOOST_PP_SUB(n, 1), 52), 1), \
LETTER, BOOST_PP_ADD(BOOST_PP_MOD(BOOST_PP_SUB(n, 1), 52), 1)) "\n"
In this case, I think I'll seize the opportunity to show off a little bit more :P
I'll do the same thing using just template metaprogramming (no boost preprocessor tricks). Note that the end
result won't be the same. What I got using preprocessor metaprogramming was a literal constant just the way
I wanted it. I can't do that using just template metaprogramming (AFAIK). The best I can do in this case is fill an
existing array with values generated during compilation. The filling itself will still be made while the program runs.
Let's begin with something simple. A template that generates code that prints the numbers 0 ... 9.
#include <cstdio>
template <int MAX_I, int CUR_I = 0>
struct PrintLoop
{
static void RUN()
{
printf("%c\n", CUR_I + '0');
PrintLoop<MAX_I, CUR_I + 1>::RUN();
}
};
template <int MAX_I>
struct PrintLoop<MAX_I, MAX_I>
{
static void RUN() {}
};
int main()
{
PrintLoop<10>::RUN();
fflush(stdout);
} Compiler output (note that I compile everything using -Os (code size optimization)): .file "main.cpp"
.def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"
LC0:
.ascii "%c\12\0"
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $16, %esp
call ___main
movl $48, 4(%esp)
movl $LC0, (%esp)
call _printf
movl $49, 4(%esp)
movl $LC0, (%esp)
call _printf
movl $50, 4(%esp)
movl $LC0, (%esp)
call _printf
movl $51, 4(%esp)
movl $LC0, (%esp)
call _printf
movl $52, 4(%esp)
movl $LC0, (%esp)
call _printf
movl $53, 4(%esp)
movl $LC0, (%esp)
call _printf
movl $54, 4(%esp)
movl $LC0, (%esp)
call _printf
movl $55, 4(%esp)
movl $LC0, (%esp)
call _printf
movl $56, 4(%esp)
movl $LC0, (%esp)
call _printf
movl $57, 4(%esp)
movl $LC0, (%esp)
call _printf
movl __imp___iob, %eax
addl $32, %eax
movl %eax, (%esp)
call _fflush
xorl %eax, %eax
leave
ret
.def _printf; .scl 2; .type 32; .endef
.def _fflush; .scl 2; .type 32; .endef
It's good, but not good enough. There's something I don't like. There are too many printf calls. Let's see if I can do better...
#include <cstdio>
char output[100] = { 0 };
int output_index = 0;
template <int MAX_I, int CUR_I = 0>
struct FillBufferLoop
{
static void RUN()
{
output[output_index++] = CUR_I + '0';
output[output_index++] = '\n';
FillBufferLoop<MAX_I, CUR_I + 1>::RUN();
}
};
template <int MAX_I>
struct FillBufferLoop<MAX_I, MAX_I>
{
static void RUN() {}
};
int main()
{
FillBufferLoop<10>::RUN();
printf("%s", output);
fflush(stdout);
} Compiler output: .file "main.cpp"
.def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"
LC0:
.ascii "%s\0"
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $16, %esp
call ___main
movl _output_index, %eax
movb $48, _output(%eax)
movb $10, _output+1(%eax)
movb $49, _output+2(%eax)
movb $10, _output+3(%eax)
movb $50, _output+4(%eax)
movb $10, _output+5(%eax)
movb $51, _output+6(%eax)
movb $10, _output+7(%eax)
movb $52, _output+8(%eax)
movb $10, _output+9(%eax)
movb $53, _output+10(%eax)
movb $10, _output+11(%eax)
movb $54, _output+12(%eax)
movb $10, _output+13(%eax)
movb $55, _output+14(%eax)
movb $10, _output+15(%eax)
movb $56, _output+16(%eax)
movb $10, _output+17(%eax)
movb $57, _output+18(%eax)
movb $10, _output+19(%eax)
addl $20, %eax
movl %eax, _output_index
movl $_output, 4(%esp)
movl $LC0, (%esp)
call _printf
movl __imp___iob, %eax
addl $32, %eax
movl %eax, (%esp)
call _fflush
xorl %eax, %eax
leave
ret
.globl _output
.bss
.align 4
_output:
.space 100
.globl _output_index
.align 4
_output_index:
.space 4
.def _printf; .scl 2; .type 32; .endef
.def _fflush; .scl 2; .type 32; .endef
Yeap, that's more like it. Now, let's see how this can be applied to the problem at hand.
I'll need two loops for this. An outer one, that will iterate over the input
data, and an inner one, that will generate the string mapped to the current
integer. Also, note that neither the int -> letter mapping nor the input data
can be arrays if I want to be able to use them as template arguments (AFAIK).
#include <cstdio>
template <int N>
struct Letters;
#define DEF_LETTER(index, value) \
template <> struct Letters<index> \
{ static const char VAL = value; };
DEF_LETTER( 0, 'a') DEF_LETTER( 1, 'b') DEF_LETTER( 2, 'c') DEF_LETTER( 3, 'd')
DEF_LETTER( 4, 'e') DEF_LETTER( 5, 'f') DEF_LETTER( 6, 'g') DEF_LETTER( 7, 'h')
DEF_LETTER( 8, 'i') DEF_LETTER( 9, 'j') DEF_LETTER(10, 'k') DEF_LETTER(11, 'l')
DEF_LETTER(12, 'm') DEF_LETTER(13, 'n') DEF_LETTER(14, 'o') DEF_LETTER(15, 'p')
DEF_LETTER(16, 'q') DEF_LETTER(17, 'r') DEF_LETTER(18, 's') DEF_LETTER(19, 't')
DEF_LETTER(20, 'u') DEF_LETTER(21, 'v') DEF_LETTER(22, 'w') DEF_LETTER(23, 'x')
DEF_LETTER(24, 'y') DEF_LETTER(25, 'z') DEF_LETTER(26, 'A') DEF_LETTER(27, 'B')
DEF_LETTER(28, 'C') DEF_LETTER(29, 'D') DEF_LETTER(30, 'E') DEF_LETTER(31, 'F')
DEF_LETTER(32, 'G') DEF_LETTER(33, 'H') DEF_LETTER(34, 'I') DEF_LETTER(35, 'J')
DEF_LETTER(36, 'K') DEF_LETTER(37, 'L') DEF_LETTER(38, 'M') DEF_LETTER(39, 'N')
DEF_LETTER(40, 'O') DEF_LETTER(41, 'P') DEF_LETTER(42, 'Q') DEF_LETTER(43, 'R')
DEF_LETTER(44, 'S') DEF_LETTER(45, 'T') DEF_LETTER(46, 'U') DEF_LETTER(47, 'V')
DEF_LETTER(48, 'W') DEF_LETTER(49, 'X') DEF_LETTER(50, 'Y') DEF_LETTER(51, 'Z')
template <int N>
struct Input;
#define DEF_INPUT(index, value) \
template <> struct Input<index> \
{ static const int VAL = value; };
const int input_size = 15;
DEF_INPUT( 0, 1) DEF_INPUT( 1, 3) DEF_INPUT( 2, 25) DEF_INPUT( 3, 26) DEF_INPUT( 4, 27)
DEF_INPUT( 5, 30) DEF_INPUT( 6, 51) DEF_INPUT( 7, 52) DEF_INPUT( 8, 53) DEF_INPUT( 9, 59)
DEF_INPUT(10, 80) DEF_INPUT(11, 103) DEF_INPUT(12, 104) DEF_INPUT(13, 105) DEF_INPUT(14, 110)
const int output_size = 100;
char output[output_size] = { 0 };
int output_index = 0;
template <char CUR_C, int MAX_I, int CUR_I = 0>
struct InnerLoop
{
static void RUN()
{
output[output_index++] = CUR_C;
InnerLoop<CUR_C, MAX_I, CUR_I + 1>::RUN();
}
};
template <char CUR_C, int MAX_I>
struct InnerLoop<CUR_C, MAX_I, MAX_I>
{
static void RUN() {}
};
template <int MAX_I, int CUR_I = 0>
struct OuterLoop
{
static void RUN()
{
InnerLoop<Letters<(Input<CUR_I>::VAL - 1) % 52 >::VAL, (Input<CUR_I>::VAL - 1) / 52 + 1>::RUN();
output[output_index++] = '\n';
OuterLoop<MAX_I, CUR_I + 1>::RUN();
}
};
template <int MAX_I>
struct OuterLoop<MAX_I, MAX_I>
{
static void RUN() {}
};
int main()
{
OuterLoop<input_size>::RUN();
printf("%s", output);
fflush(stdout);
} Compiler output: .file "main.cpp"
.def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"
LC0:
.ascii "%s\0"
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $16, %esp
call ___main
movl _output_index, %eax
movb $97, _output(%eax)
movb $10, _output+1(%eax)
movb $99, _output+2(%eax)
movb $10, _output+3(%eax)
movb $121, _output+4(%eax)
movb $10, _output+5(%eax)
movb $122, _output+6(%eax)
movb $10, _output+7(%eax)
movb $65, _output+8(%eax)
movb $10, _output+9(%eax)
movb $68, _output+10(%eax)
movb $10, _output+11(%eax)
movb $89, _output+12(%eax)
movb $10, _output+13(%eax)
movb $90, _output+14(%eax)
movb $10, _output+15(%eax)
movb $97, _output+16(%eax)
movb $97, _output+17(%eax)
movb $10, _output+18(%eax)
movb $103, _output+19(%eax)
movb $103, _output+20(%eax)
movb $10, _output+21(%eax)
movb $66, _output+22(%eax)
movb $66, _output+23(%eax)
movb $10, _output+24(%eax)
movb $89, _output+25(%eax)
movb $89, _output+26(%eax)
movb $10, _output+27(%eax)
movb $90, _output+28(%eax)
movb $90, _output+29(%eax)
movb $10, _output+30(%eax)
movb $97, _output+31(%eax)
movb $97, _output+32(%eax)
movb $97, _output+33(%eax)
movb $10, _output+34(%eax)
movb $102, _output+35(%eax)
movb $102, _output+36(%eax)
movb $102, _output+37(%eax)
movb $10, _output+38(%eax)
addl $39, %eax
movl %eax, _output_index
movl $_output, 4(%esp)
movl $LC0, (%esp)
call _printf
movl __imp___iob, %eax
addl $32, %eax
movl %eax, (%esp)
call _fflush
xorl %eax, %eax
leave
ret
.globl _output
.bss
.align 4
_output:
.space 100
.globl _output_index
.align 4
_output_index:
.space 4
.def _printf; .scl 2; .type 32; .endef
.def _fflush; .scl 2; .type 32; .endef
Program output: a
c
y
z
A
D
Y
Z
aa
gg
BB
YY
ZZ
aaa
fff
Well, while m4ster_r0shi is going at it, I might flex my C++ muscles too...
I just wanted to make the point that doing things at compile-time with meta-programming techniques doesn't have to be really complex and elaborate like m4ster_r0shi's example, especially with C++0x support. For this problem, you could simply do:
#include <iostream>
#include <string>
const char alphabet[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
template <unsigned int Size, unsigned int Index>
struct decoding {
static constexpr std::string value(const int (&arr)[Size]) {
return std::string( (arr[Index] - 1) / 52 + 1,
alphabet[(arr[Index] - 1) % 52] )
+ "\n"
+ decoding<Size, Index + 1>::value(arr);
};
};
template <unsigned int Size>
struct decoding<Size, Size> {
static constexpr std::string value(const int (&)[Size]) {
return "";
};
};
template <unsigned int Size>
constexpr std::string decode(const int (&arr)[Size]) { return decoding< Size, 0 >::value(arr); };
int main() {
constexpr int input[] = {1, 3, 25, 26, 27, 30, 51, 52, 53, 59, 80, 103, 104, 105, 110};
std::cout << decode(input) << std::endl;
return 0;
};