Well, unexpectedly, the code testing for my Congklak code is completed faster than I thought. Almost no significant error was found other that some stupid variable typo. So, as I promised you, here it is, Congklak, the traditional board game from Indonesia, in MATLAB!
MATLAB Congklak – Screenshot 01
MATLAB Congklak – Screenshot 02
Since the gameplay of Congklak is simple (For those of you who does not know how Congklak is played, check out my previous post about How to play Congklak), it is quite easy to code the game. However, to make it easier for the player to follow the game, I used some simple animation to visualized how the beans or seeds is moved from house to another. Unfortunately, my internet is very slow and I can’t upload my video to youtube. So, I can’t show you the animation on this post, but I will update it as soon as I’ve finished uploading my video to youtube:D.
Before deciding the algorithm for Congklak’s gameplay, I decided to use a simple 1×16 array, called board, to represent the current number of beans in the Congklak’s board. The first to seventh element of the array represent the number of beans in player’s houses, respectively from left to right, while the eighth element of the array represent the number of beans in player’s storehouse or player’s score. On the other hand, the ninth to fifteenth element of the array represent the number of beans in COM’s houses, respectively from right to left, while the last element represent the number of beans in COM’s storehouse. This arrangement is done to make the gameplay easier to code.
For the gameplay, as usual, a while command is used to perform loop and execute turns for each player. This while command will end when all seeds in the houses are taken or when close game button is clicked. Before the while loop started, rand function is used to determine randomly player that will start its turn. At the end of the while loop, each storehouse is checked to determine who is the winner. Here is a peek of my code that executes the entire gameplay:
%Randomly choose player for first turn decision=rand; if decision<=0.5 turn='c'; elseif decision>0.5 turn='p'; end %Playing the game until all seeds are taken into score hole playstat=1; while (playstat==1)&&(sum(board([1:7,9:15])==0)~=14) if strcmpi(turn,'p') if sum(board(1:7)==0)~=7 selectedhole=playermove(board); [board,turn]=playseed(board,turn,selectedhole,... animationtype); else turn=switchturn(turn); end elseif strcmpi(turn,'c') if sum(board(9:15)==0)~=7 if difficultylevel==1 selectedhole=commove_easy(board); elseif difficultylevel==2 selectedhole=commove_normal(board); elseif difficultylevel==3 selectedhole=commove_hard(board); end [board,turn]=playseed(board,turn,selectedhole,... animationtype); else turn=switchturn(turn); end end end %Announcing winner if board(8)>board(16) set(instructionbox,... 'String',['Congratulations! You win! Press start to',... ' play again!']) elseif board(8)<board(16) set(instructionbox,... 'String','Sorry, you lose! Press start to retry!') elseif board(8)==board(16) set(instructionbox,... 'String','It is a draw! Press start to retry!') end
Notice that in the code above, before a player executes his turn, his houses are checked first to see whether there is an available move. If there is not, player’s turn is forfeited. On the other side, to execute a turn, a local function playseed is used. This function calculates the changes made on the board based on the houses chosen by its player to be played. This function alsodetermines whether a player can play his turn again (if he dropped the last bean in his own store house) or when a player has finished his turn.
Playing a Turn
In a turn, player chooses a house from his side, take all beans in it, and distribute it by putting one on the next house except in the opponent’s storehouse. Because of the arrangement of board variables (remember, the 1×16 array), this play can be coded easily by using while command as shown below. First, hand variable is used for the number of beans on the chosen house and lasthole variable for the current location of house. Then, until hand is equal to zero, the lasthole was moved forward by one and the house on those position was given one bean. Note that when the position is at 8th or 16th hole, a check is done using if command. This is done to avoid putting bean in opponent’s storehouse.
%Taking seeds from selected hole hand=board(selectedhole); board(selectedhole)=0; %Moving seeds forward lasthole=selectedhole; while hand>0 lasthole=lasthole+1; if lasthole>16 lasthole=lasthole-16; end if (lasthole==8) if strcmpi(turn,'p') hand=hand-1; board(lasthole)=board(lasthole)+1; end elseif (lasthole==16) if strcmpi(turn,'c') hand=hand-1; board(lasthole)=board(lasthole)+1; end else hand=hand-1; board(lasthole)=board(lasthole)+1; end end
Note that the code shown above is only for executing one play. Remember that depending on the number of beans on the last house and the position of the last house itself, player may continue his turn, choose new house to play again, shoot opponent’s house and end his turn or just simply end his turn. This means, after each play, number of beans at the last house and the position of the last house must be checked. This was done by using another while command. So, in complete, the playseed function will be like this:
function [board,turn]=playseed(board,turn,selectedhole) %Performing normal seedplay turnend=0; while turnend==0 %Taking seeds from selected hole hand=board(selectedhole); board(selectedhole)=0; %Moving seeds forward lasthole=selectedhole; while hand>0 lasthole=lasthole+1; if lasthole>16 lasthole=lasthole-16; end if (lasthole==8) if strcmpi(turn,'p') hand=hand-1; board(lasthole)=board(lasthole)+1; end elseif (lasthole==16) if strcmpi(turn,'c') hand=hand-1; board(lasthole)=board(lasthole)+1; end else hand=hand-1; board(lasthole)=board(lasthole)+1; end end %Anticipating continuous turn if (board(lasthole)==1)||(lasthole==8)||(lasthole==16) turnend=1; else selectedhole=lasthole; end end %Anticipating hole shooting and replaying if strcmpi(turn,'p') if (lasthole>0)&&(lasthole<8) board=shoothole(board,turn,lasthole,animationtype); end if lasthole~=8 turn=switchturn(turn); end elseif strcmpi(turn,'c') if (lasthole>8)&&(lasthole<16) board=shoothole(board,turn,lasthole,animationtype); end if lasthole~=16 turn=switchturn(turn); end end end
Notice that in function above, every inner while (the one for executing one play) is done, the value of board(lasthole) is checked. If it is not 0, another play is executed by using lasthole as the new selected hole. If it is zero, then the turn is ended and another check was done to see whether player just end his turn or he can shoot the opponent’s house first before ending his turn.
Shooting Opponent’s House
When shooting can be done, playseed function calls shoothole function to execute the shooting play. Basicly, shooting play is just moving all beans in the last house and the opposing house to player’s store house. Since congklak has 16 house in total, then the location of the opposing house (the house to be shooted), can determine from 16-lasthole (Remeber the board variable arrangement). Thus, based on that, the shoothole function was written as follows:
function board=shoothole(board,turn,shootinghole,animationtype) %Finding seed amount in the shooted hole temphand=0; shootedhole=16-shootinghole; seedcount=board(shootedhole); %Taking all in the shootinghole board(shootinghole)=0; temphand=1; %Taking all seeds in the shootedhole board(shootedhole)=0; temphand=1+seedcount; %Putting all taken seeds in the scorehole if strcmpi(turn,'p') target=8; elseif strcmpi(turn,'c') target=16; end board(target)=board(target)+temphand; temphand=0; end
Regarding the COM’s AI, actually I’m not deadset on this one and I may changed it in the future because the easy AI is to easy to beat, while the hard AI is to impossible to beat. Either way, I’m gonna explain it a little here. As you can see in the main code, during COM’s turn, a commove function is called. This function uses the current board condition as an input for the house that should be played by COM. For the easy AI (commove_easy), the house to be played is chosen randomly from the available options. On the other hand, for the hard AI, each available option is evaluated by calling playseed function and the COM will choose the house that will result in another turn (ended in COM’s storehouse). However, I think this is cheating because the AI shouldn’t be using the gameplay function as its aid for decision making. So, maybe (if I’m not too lazy) in the future, I will modify it to make it more fair.
And, I think that’s all about Congklak and my code in MATLAB. Basically, this code is much simpler than the MATLAB DoodleJump code because it does not need real time processing while reading user input at the same time. So, I hope that this is understandable for all of you. I’ve already put the code in my MATLAB Fun Toolbox page and you can downloaded it from there. As usual, comments and critics are welcomed:D.
Update for this post: A Little Update on Congklak