Hi there. After a long break, this post is again about a game. I will talk about the game and use Matlab.
I had downloaded "Calculator: The Game" in the beginning of summer. The aim of the game is, to start with a given number and to reach to the "goal" number in a limited number of operations. Here is a video of that game: https://www.youtube.com/watch?v=w5yyY341-4A. This game was downloaded 5M+ times at that time, so I can assume that it is a famous game. The screenshot, left, is from the first level. This level starts with zero. The allowed operation is +1 and the aim is obtaining 2 in two moves. Since there is only one operation, it is obvious that the solution is pressing +1 two times.
Level 30 |
In advanced levels, more complicated operations are available. For example, '<<' operation gives 432 from 4321. Violet buttons with numbers on them like in the screenshot right, append numbers to the actual number. Pressing violet 5 on 432, implies 4325. Orange conversion buttons, seen on the same screenshot right again, replaces 1s to 2 ( 1 => 2 ) and 2s to 3
( 2 => 3 ). The solution of level 30, in the rightmost screenshot, is pressing: 1, 2, 2=>3, 1=>2, 2, 1. SUM button gives the sum of the digits of the number. Inv10 subtracts each digit from 10. [+]1 works on the calculator buttons and adds 1 to the values on the buttons. Store, stores the number in memory, in order to use the same more than once. Shift, corresponds rotation operation in assembly. Mirror, appends the reversed digits of a number to its left.
( 2 => 3 ). The solution of level 30, in the rightmost screenshot, is pressing: 1, 2, 2=>3, 1=>2, 2, 1. SUM button gives the sum of the digits of the number. Inv10 subtracts each digit from 10. [+]1 works on the calculator buttons and adds 1 to the values on the buttons. Store, stores the number in memory, in order to use the same more than once. Shift, corresponds rotation operation in assembly. Mirror, appends the reversed digits of a number to its left.
Examples:
4325 (SUM) -> 14 (SUM) -> 5
4325 (Inv10) -> 6785
4325 (Shift>) -> 5432 (<Shift) -> 4325
25 (Mirror) -> 2552 -> (Mirror) 25522552
There are also portals in the game which are not buttons. For example, if there is a portal from hundreds place to one's place and if the result of an operation is greater than 100, the portal adds the digit on the hundreds place to one's place and removes the digit from hundreds place.
Bölüm 60 |
I played this game for a long time and noticed that a "trial and error" approach on all combinations is more practical than thinking, in specific levels. For example, let's consider level 30 (the screenshot above). The solution is quite easy. There are 46 = 4096 button combinations in total, since there are 4 buttons and six moves. For this example, thinking is more practical. On the other hand, let's consider 60th level, in the screenshot on the right. This level looks like harder than 30th level however pressing on two keys in five moves makes 25 = 32 different combinations. In this level, brute force technique is much more simpler than thinking.
Not using a computer is unthinkable, when brute force approach is considered. So that, even though 4096 may seem like huge, this can be tried in a computer in a few seconds. The most important is to approach the problem correctly.
Not using a computer is unthinkable, when brute force approach is considered. So that, even though 4096 may seem like huge, this can be tried in a computer in a few seconds. The most important is to approach the problem correctly.
If the operations would be written in a single function, they could not be called in different sequences, in a linearly running code. The button operations should be defined as functions and there must be as many functions as the number of keys. Or in other words, each key should be written as a function.
How can the keys be pressed? For example, even though there are five different keys in a level, pressing only one of them consequtively can be a solution. Or pressing first key and then second key and then first again etc. Let's assume the keys are numbered and pressing sequence does not matter. Since there are five button, five digits will be used for numbering. Let's also assume that number of moves are three for this theoretical level. Pressing the first key consequtively corresponds to 111, pressing first three keys in a sequence corresponds to 123. If generalized, it's used as many numerals as the number of keys and the number corresponding to a key sequence consists from as many digits as the number of moves. These are some examples to the valid combinations: 125, 134, 225, 334, 415, 531, 555. Since there are 53 = 125 combinations in total, there is no need and space to count them all. In the meantime, if 0 is used instead of 5 when numbering the keys, the relation to the 5-based numbering system can be noticed easily.
How can the keys be pressed? For example, even though there are five different keys in a level, pressing only one of them consequtively can be a solution. Or pressing first key and then second key and then first again etc. Let's assume the keys are numbered and pressing sequence does not matter. Since there are five button, five digits will be used for numbering. Let's also assume that number of moves are three for this theoretical level. Pressing the first key consequtively corresponds to 111, pressing first three keys in a sequence corresponds to 123. If generalized, it's used as many numerals as the number of keys and the number corresponding to a key sequence consists from as many digits as the number of moves. These are some examples to the valid combinations: 125, 134, 225, 334, 415, 531, 555. Since there are 53 = 125 combinations in total, there is no need and space to count them all. In the meantime, if 0 is used instead of 5 when numbering the keys, the relation to the 5-based numbering system can be noticed easily.
125 means to press 1st, 2nd and 5th keys or calling first then second and then fifth function respectively. So, how should the functions be called in a certain order according to the value of the number? The easiest way to do this is to work with function pointers, not the functions itself. This might sound a bit complicated. Speaking of complicated, this is done in C as follows:
#include<stdio.h>
void fonk1(int i) {
fprintf(stdout, "Fonk1: %d\n", i);
}
void fonk2(int i) {
fprintf(stdout, "Fonk2: %d\n", i);
}
void fonk3(int i) {
fprintf(stdout, "Fonk3: %d\n", i);
}
int main(int argc, char* argv[]) {
void (*fparray[3])(int i);
int i;
fparray[0] = fonk1;
fparray[1] = fonk2;
fparray[2] = fonk3;
for(i = 0; i < 3; i++) {
(*fparray[i])(i);
}
return 0;
}
void fonk1(int i) {
fprintf(stdout, "Fonk1: %d\n", i);
}
void fonk2(int i) {
fprintf(stdout, "Fonk2: %d\n", i);
}
void fonk3(int i) {
fprintf(stdout, "Fonk3: %d\n", i);
}
int main(int argc, char* argv[]) {
void (*fparray[3])(int i);
int i;
fparray[0] = fonk1;
fparray[1] = fonk2;
fparray[2] = fonk3;
for(i = 0; i < 3; i++) {
(*fparray[i])(i);
}
return 0;
}
In the example above, three simple functions were defined. A void function pointer array with three elements is created in the main() function and pointers of fonk1, fonk2 and fonk3 are assigned to this array. Considering that, the name of a function in C is the pointer to itself at the same time, no operator (*, &) is required for assignments. In other words, the name of the function contains the address of the first command of function. In for loop, elements of the array is called one-by-one with the argument 'i'.
Level 192 |
For example, 192nd level was hard. I had to code for this level. There are five buttons and six moves, which makes so many combinations. There is a portal from thousands position to one's position. First, I started to write functions to the buttons. Please note that, the functions in Matlab must be saved in files with the same name of the function. First function is in the file tus1.m, second function is in the file tus2.m etc.
function deger = tus1(deger)
% +8
deger = deger + 8;
endfunction
function deger = tus2(deger)
% *4
deger = deger * 4;
endfunction
function deger = tus3(deger)
% Inv10
s_deger = int2str(deger); % convert number to string
for k1 = 1:length(s_deger)
if (s_deger(k1) != '0')
s_deger(k1) = int2str(10 - str2num(s_deger(k1))); % subtract the characters from 10
endif
endfor
deger = str2num(s_deger); % convert the string back to number
endfunction
function deger = tus4(deger)
% append 9
deger = deger * 10 + 9;
endfunction
function deger = tus5(deger)
% 7 => 0
if( floor(deger / 100) == 7 )
deger = deger - 700;
endif
if( mod(floor(deger / 10), 10) == 7 )
deger = deger - 70;
endif
if(mod(deger, 10) == 7)
deger = deger - 7;
endif
endfunction
% +8
deger = deger + 8;
endfunction
function deger = tus2(deger)
% *4
deger = deger * 4;
endfunction
function deger = tus3(deger)
% Inv10
s_deger = int2str(deger); % convert number to string
for k1 = 1:length(s_deger)
if (s_deger(k1) != '0')
s_deger(k1) = int2str(10 - str2num(s_deger(k1))); % subtract the characters from 10
endif
endfor
deger = str2num(s_deger); % convert the string back to number
endfunction
function deger = tus4(deger)
% append 9
deger = deger * 10 + 9;
endfunction
function deger = tus5(deger)
% 7 => 0
if( floor(deger / 100) == 7 )
deger = deger - 700;
endif
if( mod(floor(deger / 10), 10) == 7 )
deger = deger - 70;
endif
if(mod(deger, 10) == 7)
deger = deger - 7;
endif
endfunction
I considered the portal as a separate function, accepting the value, returned from any button function, as an argument. The result of a function, enters to the portal function and exits arranged. I named the portal function as "girdicikti":
function deger = girdicikti(deger)
if(deger > 999)
binler = floor(deger / 1000);
deger = mod(deger, 1000) + binler;
if(deger > 999)
girdicikti(deger)
endif
endif
endfunction
if(deger > 999)
binler = floor(deger / 1000);
deger = mod(deger, 1000) + binler;
if(deger > 999)
girdicikti(deger)
endif
endif
endfunction
Main function is as follows:
ilkdeger = 189; % ilkdeger means initial value
% Function array
f_a = { @tus1, @tus2, @tus3, @tus4, @tus5 };
for k1 = 1:5
for k2 = 1:5
for k3 = 1:5
for k4 = 1:5
for k5 = 1:5
%for k6 = 1:5
step1 = girdicikti( feval (f_a{k1}, ilkdeger) );
step2 = girdicikti( feval (f_a{k2}, step1) );
step3 = girdicikti( feval (f_a{k3}, step2) );
step4 = girdicikti( feval (f_a{k4}, step3) );
step5 = girdicikti( feval (f_a{k5}, step4) );
if(step5 == 500)
printf("%d %d %d %d %d\n", k1, k2, k3, k4, k5);
break
endif
%endfor
endfor
endfor
endfor
endfor
endfor
% Function array
f_a = { @tus1, @tus2, @tus3, @tus4, @tus5 };
for k1 = 1:5
for k2 = 1:5
for k3 = 1:5
for k4 = 1:5
for k5 = 1:5
%for k6 = 1:5
step1 = girdicikti( feval (f_a{k1}, ilkdeger) );
step2 = girdicikti( feval (f_a{k2}, step1) );
step3 = girdicikti( feval (f_a{k3}, step2) );
step4 = girdicikti( feval (f_a{k4}, step3) );
step5 = girdicikti( feval (f_a{k5}, step4) );
if(step5 == 500)
printf("%d %d %d %d %d\n", k1, k2, k3, k4, k5);
break
endif
%endfor
endfor
endfor
endfor
endfor
endfor
The 'ilkdeger' variable enters to a function. As a result of a key press (function), ilkdeger becomes step1. Another key press results in step1 being step2... Interestingly, this level is solved in five steps instead of six. The solution took about 15.96 seconds in my computer. This program produces two different outputs:
Level 199 |
4 2 1 4 2: 189 (9) -> 900 (x4) -> 603 (+8) -> 611 (9) -> 125 (x4) -> 500
I wrote another code for the level 199. There are 46 = 4096 button combinations in this level. Since the third button is them same button as the previous example, I skipped it below:
function deger = tus1(deger)
% append 7
deger = deger * 10 + 7;
endfunction
function deger = tus2(deger)
% 3 => 5
deger = str2num(strrep(num2str(deger), '3', '5'));
endfunction
function deger = tus4(deger)
% shift > 3002 => 2300
if(deger > 999)
deger = mod(deger, 10) * 1000 + floor(deger / 10);
elseif(deger > 99)
deger = mod(deger, 10) * 100 + floor(deger / 10);
elseif(deger > 9)
deger = mod(deger, 10) * 10 + floor(deger / 10);
endif
endfunction
% append 7
deger = deger * 10 + 7;
endfunction
function deger = tus2(deger)
% 3 => 5
deger = str2num(strrep(num2str(deger), '3', '5'));
endfunction
function deger = tus4(deger)
% shift > 3002 => 2300
if(deger > 999)
deger = mod(deger, 10) * 1000 + floor(deger / 10);
elseif(deger > 99)
deger = mod(deger, 10) * 100 + floor(deger / 10);
elseif(deger > 9)
deger = mod(deger, 10) * 10 + floor(deger / 10);
endif
endfunction
The portal from ten thousands place to one's place:
function deger = girdicikti(deger)
if(deger > 9999)
onbinler = floor(deger / 10000);
% strip ten thousands place
deger = mod(deger, 1000) + onbinler;
% add to ones place
if(deger > 9999)
girdicikti(deger)
endif
endif
endfunction
if(deger > 9999)
onbinler = floor(deger / 10000);
% strip ten thousands place
deger = mod(deger, 1000) + onbinler;
% add to ones place
if(deger > 9999)
girdicikti(deger)
endif
endif
endfunction
In the main function, unlike the previous example, I assigned the number of functions to lfa variable and ran the for loops up to this variable:
clc
clear
ilkdeger = 3002; % ilkdeger means initial value
f_a = { @tus1, @tus2, @tus3, @tus4 };
lfa = length(f_a);
for k1 = 1:lfa
for k2 = 1:lfa
for k3 = 1:lfa
for k4 = 1:lfa
for k5 = 1:lfa
for k6 = 1:lfa
step1 = girdicikti( feval (f_a{k1}, ilkdeger) );
step2 = girdicikti( feval (f_a{k2}, step1) );
step3 = girdicikti( feval (f_a{k3}, step2) );
step4 = girdicikti( feval (f_a{k4}, step3) );
step5 = girdicikti( feval (f_a{k5}, step4) );
step6 = girdicikti( feval (f_a{k6}, step5) );
if(step6 == 3507)
printf("%d %d %d %d %d %d\n", k1, k2, k3, k4, k5, k6);
return
endif
endfor
endfor
endfor
endfor
endfor
endfor
clear
ilkdeger = 3002; % ilkdeger means initial value
f_a = { @tus1, @tus2, @tus3, @tus4 };
lfa = length(f_a);
for k1 = 1:lfa
for k2 = 1:lfa
for k3 = 1:lfa
for k4 = 1:lfa
for k5 = 1:lfa
for k6 = 1:lfa
step1 = girdicikti( feval (f_a{k1}, ilkdeger) );
step2 = girdicikti( feval (f_a{k2}, step1) );
step3 = girdicikti( feval (f_a{k3}, step2) );
step4 = girdicikti( feval (f_a{k4}, step3) );
step5 = girdicikti( feval (f_a{k5}, step4) );
step6 = girdicikti( feval (f_a{k6}, step5) );
if(step6 == 3507)
printf("%d %d %d %d %d %d\n", k1, k2, k3, k4, k5, k6);
return
endif
endfor
endfor
endfor
endfor
endfor
endfor
This level is solved in six moves. The solution is "1 1 2 3 4 1" and it took approximately 0.68 seconds:
This level finishes the game and ending video starts. This approach, described in the post, can be applied to many levels of this game. But it is difficult to apply the keys like Store and more importantly keys like [+]2. For the latter, it should be possible to define a global increment value and modify the button functions according to this value. Since I had no difficulty with the levels containing such keys, I didn't have to write any code for these.
No comments:
Post a Comment