Thursday, November 8, 2018

Calculator the Game and Its Solution


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. 

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.

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.

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;
}

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
Function pointers in C, are hard to understand (at least for me). It is confusing which parentheses should be where. Instead of C, I used Matlab for the solution. It is quite easier to code this in Matlab. Similar to the & operator in C, there is @ operator in Matlab for function pointers. To store the function pointers, I used cell arrays instead of matrices and feval function to evaluate the button function with given argument. Instead of dealing with number systems in the code, I used nested for loops as many as the number of functions.

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

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

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

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
2 5 4 1 5: 189 (x4) -> 756 (7 => 0) -> 056 (9) -> 569 (+8) -> 577 (7 => 0) -> 500
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

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

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

This level is solved in six moves. The solution is "1 1 2 3 4 1" and it took approximately 0.68 seconds:
3002 (7) -> 30 (7) -> 307 (3 => 5) -> 507 (Inv10) -> 503 (Shift>) -> 350 (7) -> 3507

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