sungka game

closed account (1w0XoG1T)
anybody heard of game called "sungka"?
i was wondering if i could get some help
making a game in C++ just for fun

here's a discription of it:

http://wikimanqala.org/wiki/Sungka

anyone who can patch up a code could be useful,... thanx in advance
Last edited on
Sounds cool. What is what you exactly want/need? What's your experience?
closed account (1w0XoG1T)
i got strong knowledge bout the basics.,.. but im stuck with the algorithm,..
u used alot of loops, functions, but im still stuck
I'm not familiar with the game, but read the wiki link.Basially you need to construct a Board and write a method for the move. I just started the code with basic building blocks. The move method should be something similar. Again I'm not familiar with the game and I have not applied all rules, if I get time tommorrow morning I will add more. This is just to give you an idea
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include<iostream>
#include<vector>
using namespace std;

enum player{LP=0,RP};

struct Board
{

 	int left_pits[7]; // left side pits - seven
	int right_pits[7]; //right side pits
	int right_store;
	int left_store;
	
	
	//ctor
	Board();
	void Move(int player_turn,int pit_seleced,int stone_count); // It should follow all the rules and make one move and update the board
// put Move in a loop until the game finishes
};
Board::Board()// initialize all 
{
	for(int i=0;i<7;i++)
	{
		left_pits[i]=7; // starting position
		right_pits[i]=7;
	}
	left_store=0;
	right_store=0;
}
void Board::Move(int player_turn,int pit_selected,int stone_count)
{// player_seletcted= LP or RP, LP starts at left side RP statrs at right side
// move is always from left to right
/*
							left side
				   6(7) 5(7) 4(7) 3(7) 2(7) 1(7) 0(7)
  right_store(0)										left_store(0)
				   0(7) 1(7) 2(7) 3(7) 4(7) 5(7) 6(7)
							right side

*/ 
	int i;
	int stones_left=stone_count;
	if( player_turn == LP) 
	{// he starts from the left side and goes to right dropping one stone at a time
	
		for(i=pit_selected; stones_left>0 && i<7 ; i++)
		{ // apply rules
			left_pits[i]++;
			stones_left--;
		}
		// pass right_store
		//Move to right_pits, will work only if stones left
		for(i=0;stones_left>0 && i<7 ; i++)
		{
			right_pits[i]++;
			stones_left--;
		}
		// if more stones left, //drop one in the left store
		if(stones_left>0)
		{
			left_store++;
			stones_left--;
		}
		//if more stones left call the function again
		if(stones_left>0)
			this->Move(LP,0,stones_left);
	}

	if( player_turn == RP) 
	{// he starts from the right side and goes to the left dropping one stone at a time
	
		for(i=pit_selected; stones_left>0 && i<7 ; i++)
		{ // apply rules
			right_pits[i]++;
			stones_left--;
		}
		// pass left_store
		//Move to left_pits, will work only if stones left
		for(i=0;stones_left>0 && i<7 ; i++)
		{
			left_pits[i]++;
			stones_left--;
		}
		// if more stones left, //drop one in the right store
		if(stones_left>0)
		{
			right_store++;
			stones_left--;
		}
		//if more stones left call the function again
		if(stones_left>0)
			this->Move(RP,0,stones_left);
	}
	

}


int main(){

	return 0;
}




Did some more coding today and made this basic Sangka game working. Two players can play. The playes are named as Left and Right. The game starts with Left player, insert a pit number of your row(Left is top).
It completes one move and displays the board. It also tells who has the next move. During current move if he gets a bonus, then the current player gets an additional move.
Caution: You may come across many pitfalls
I have never played this game, got the rules from the wiki link. My interpretation of the rules can be wrong. For example, when a move ends in his own row, the player can grab all the stones from pit across of the other row, I took the pit close to it, but it can be diagonally across also. In my case if it ends left_row[2] then it grabs stones from right_row[4] , but it can be, when left_row[2] grab right_row[2].
But I think one can modify the move method and make necessary adjustments. Another issue when a pit contains 14 stones it will end up in an infinite loop, I have no idea how to fix that.

Hope some one who knows the game test it and give a feed back.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
#include<iostream>
#include<string>
using namespace std;

enum player{LP=0,RP};
const int MAX_PITS=7;
const int SCORE = (MAX_PITS*MAX_PITS)*2;

class Board
{
public:
 	int *left_pits; // left side pits - seven
	int *right_pits; //right side pits
	int right_store;
	int left_store;
public:
	//ctor
	Board();
	~Board();
	int Move(int player_turn,int pit_seleced,bool multilap,int stones_count); // It should follow all the rules and make one move and update the board
// put Move in a loop until the game finishes
	void displayBoard();
	int ckboard();
};

Board::Board()// initialize all 
{
	left_pits= new int [MAX_PITS];
	right_pits=new int [MAX_PITS];
	for(int i=0;i<MAX_PITS;i++)
	{
		left_pits[i]=7; // starting position
		right_pits[i]=7;
	}
	left_store=0;
	right_store=0;
}
Board::~Board()
{
	delete [] left_pits;
	delete [] right_pits;
}
void Board::displayBoard()
{
	int i;
	int j=0;
	//cout << "\t\tleft_row "<< endl;
	for(i=0;i<60;i++)
		cout<<"*";
	cout<<endl;
	cout <<"*\t  ";
	for(i=MAX_PITS-1; i>=0 ;i--)
			cout << /*i*/" "<<"(" << left_pits[i]<<")" <<" ";
		cout<<"\t*"<<endl;

	cout<<"*  RS("<<right_store<<")"<<"\t\t\t\t\t   "<<"LS(" <<left_store<<") *"<<endl;
	cout <<"*\t  ";
	for(i=0; i<MAX_PITS;i++)
		cout << /*i*/" " <<"(" << right_pits[i]<<")" <<" ";
	cout<<"\t*"<<endl;
	//cout << "\t\tright_row "<< endl<<endl;
	for(i=0;i<60;i++)
		cout<<"*";
	cout<<endl;


}

int Board::ckboard()
{
	return left_store+right_store;
}
int Board::Move(int player_turn,int pit_selected,bool multilap=false,int stones_count=0)
{
	//cout << "In Move"<<endl;

	int* start_row=NULL;
	int* next_row=NULL;
	int* store;
	int i;
	int stones_left;
	int return_value;
	int player_opposite;
	bool bonus=false;
	if(player_turn == LP)
	{
		start_row=left_pits;
		next_row=right_pits;
		store= &left_store;
		player_opposite=RP;
		return_value=player_opposite;

	}else if(player_turn == RP)
	{
		start_row=right_pits;
		next_row=left_pits;
		store=&right_store;
		player_opposite=LP;
		return_value=player_opposite;

	}
	if( (start_row==NULL)|| (next_row==NULL) )
		return -1;
	
	if(multilap)
	{
		stones_left=stones_count;
		
	}else
	{
		stones_left=start_row[pit_selected];
		//make its contents to zero
		start_row[pit_selected]=0;
		pit_selected=pit_selected+1; // start from the next
	}
	
// Basic one LAP move	 
// he starts from the current_row and goes to next row dropping one stone at a time
// completes one lap, if not finished then make a recursive call with multilap on
	for(i=pit_selected; stones_left>0 && i<MAX_PITS ; i++)
	{ // apply rules
		if(stones_left==1)
		{
			if(start_row[i]==0) // move ends
			{
				//cout << "Move going to end, before it ends the board" << endl;
				//this->displayBoard();
				start_row[i]=1;
				//?? grab the stones across ??
				//cout <<"store value="<< *store << endl;
				//cout<< "across value"<<next_row[(MAX_PITS-1)-i]<<endl;
				(*store)=(*store)+next_row[(MAX_PITS-1)-i];
				//cout <<"new store value="<< *store << endl;
				//next_row[i]=0;
				next_row[(MAX_PITS-1)-i]=0;
				//?? grab the stones across ??
				stones_left--;
				return_value=player_opposite;
				break;
			}else
			{
				stones_left=1+start_row[i];
				continue;
			}
		}
		start_row[i]++;
		stones_left--;
	}
// Adjucent  store always pass
	
//Move to next_row, will work only if stones left
	for(i=0;stones_left>0 && i<MAX_PITS ; i++)
	{
		if(stones_left==1)
		{
			if(next_row[i]==0) // move ends
			{
				next_row[i]=1;
				stones_left--;
				return_value=player_opposite;
				break;
				
			}else
			{
				stones_left=1+next_row[i];
				next_row[i]=0;
				continue;
			}
		}

		next_row[i]++;
		stones_left--;
	}
	// araway stor drop in this store
	if(stones_left>0 )
	{
		if(stones_left==1) // you get a bonus move
		{
			(*store)++;
			stones_left--;
			return_value=player_turn;
			bonus=true;
			
		}else
		{
			(*store)++;
			stones_left--;
		}
	}
		//if more stones left call the function again
		if(stones_left>0)
		{
			//left_pits[0]=left_pits[0]+stones_left;
			cout << "LAP ";
			return_value= this->Move(player_turn,0,true,stones_left);
			cout <<endl;
		}
			
	if(this->ckboard()==SCORE) // finished game
	{
		cout << "All stones cleared " <<endl;
		this->displayBoard();
		return 1000;
	}
	else
	{
		if(bonus)
			cout<<"GOT A BONUS"<<endl;
		return return_value;
	}



}


int getPitFromUser(int n)
{
	string s;
	int pit;
	if(n)
		s="RIGHT PLAYER";
	else
		s="LEFT PLAYER";
	cout <<s<<endl;
	cout <<"Enter your pit selection: a number between 0 and 6 " << endl;
	cin>>pit;
	while( !cin.good() || pit<0 || pit>6)
	{
		cin.clear();
		cin.ignore(1000,'\n');
		cout <<"Enter your pit selection: a number between 0 and 6 " << endl;
		cin>>pit;
	}
	return pit;
}
int playOrNot()
{	char q;
	cout << "Would you continue playing....Type q to quit, any char to continue";
	cin >>q;
	return q;
}

int main()
{
	Board my_sungka;
	my_sungka.displayBoard();
	int next_turn=LP;
	int pit_number;

	while(next_turn !=1000)
	{//Play
		int n=0;
		pit_number=getPitFromUser(next_turn);
		next_turn= my_sungka.Move(next_turn,pit_number,false,0);
		my_sungka.displayBoard();
		//n=playOrNot();
		if(n==1000)
			next_turn=n;
		else
			cout << "NEXT TURN=" <<endl;
	}

	//my_sungka.Move(0,6,true,15);

	//my_sungka.displayBoard();
	
	
	
	
	return 0;
}
HereĀ“s the final version of a very similiar game to sungka named kalah.

field.h
player.h
main.cpp

Have fun!

source: http://en.wikipedia.org/wiki/Kalah

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#include<iostream>
using namespace std;

class field{
private:
	int stones;
public:
	field(){
		stones=3;
	}
	~field(){};
	int get_stones(){
		return stones;
	}
	void add_stones(int s){
		stones += s;
	}
	void sub_stones(int s){
		stones -= s;
	}
	bool empty(){
		return (stones == 0);
	}
};

#include<iostream>
#include<string>
#include<vector>
using namespace std;

class player{
private:
	int kalah;
	int caught_field;	
	int playernumber;
	static int number;
	bool turn;
	string namen;
	vector<field> playerfield;
public:
	player(string n){
		kalah = 0;
		caught_field = -1;
		playernumber = ++number;
		turn = true;
		namen = n;
		for (int i=0; i<6; i++)	//create 6 fields
			playerfield.push_back(field());
	}
	~player(){};
	int move (int fieldnumber){

		turn = false;
		caught_field = -1;
		int tmp=playerfield[fieldnumber].get_stones();

		if (playerfield[fieldnumber].get_stones() + fieldnumber >= playerfield.size()){
			if (playerfield[fieldnumber].get_stones() + fieldnumber == playerfield.size())
				turn = true; //last moved stone goes to players pot results in an extra turn
			playerfield[fieldnumber].sub_stones(1);
			add_kalah(1);
		}
		
		int stones = playerfield[fieldnumber].get_stones();
		for (int i=fieldnumber+1;i<playerfield.size() && stones != 0; i++,stones --){
			if (tmp + fieldnumber < playerfield.size() && stones == 1 && playerfield[i].empty()){
				playerfield[fieldnumber].sub_stones(1); //last moved stone goes to an own empty field
				catch_opponent_field(i);
				add_kalah(1);
				stones--;
				break;
				}
			playerfield[i].add_stones(1);
			playerfield[fieldnumber].sub_stones(1);
		}

		if (stones != 0){
			playerfield[fieldnumber].sub_stones(stones);
			return stones;
		}
		return 0;
	}
	int move_to_opponent(int stones){
		for (int i=0; i<playerfield.size()&& stones != 0; i++,stones--){
			playerfield[i].add_stones(1);
		}
		return stones;
	}
	void catch_opponent_field (int fieldnumber){ //calculate opposite-field. Example: own field 0: (0-5) * -1 
		caught_field = (fieldnumber - 5) * (-1); //opposite-field = 5 //
	}
	int get_caught_field(){
		return caught_field;
	}
	int get_opponent_stones(int fieldnumber){	//return caught stones
		int stones = playerfield[fieldnumber].get_stones();
		playerfield[fieldnumber].sub_stones(stones);
		return stones;
	}
	bool playerturn(){
		return turn;
	}
	void set_turn(bool b){
		turn = b;
	}
	bool field_empty(int fieldnumber){
		return playerfield[fieldnumber].empty();
	}
	bool emtpy (){ //return true if all fields of a specific player are empty
		int sum=0;
		for (int i=0; i<6; i++)
			sum += playerfield[i].get_stones();
		return (sum==0);
	}
	void add_kalah(int s){
		kalah += s;
	}
	int get_kalah(){
		return kalah;
	}
	string get_name(){
		return namen;
	}
	void print_overview(){
		cout << "Player: " << namen  << " Points: " << kalah << endl;
		cout << "Fields: ";
		if (playernumber == 1)
			for (int i=5; i>=0; i--)
				cout << playerfield[i].get_stones() << " ";
		else
			for (int i=0; i<6; i++)
				cout << playerfield[i].get_stones() << " ";
		cout << endl << endl;
	}
};
int player::number = 0;

#include<iostream>
#include<string>
#include<vector>
#include "field.h"
#include "player.h"
using namespace std;

void clear_main(){
	cout <<  endl << endl << endl;
	system("pause");
	system("cls");
}

void main(){
	vector<player>plist;
	plist.push_back(player("PARKER"));
	plist.push_back(player("ED SMITH"));
	int pp=0;								// = playerpointer
	cout << "================== WELCOME TO KALAH ==================" << endl<<endl;
	clear_main();
	do{
		while (plist[pp].playerturn()){
			int choice;
			cout <<  endl << endl;
			cout << "       <---------- " << endl << endl;
			plist[0].print_overview();
			plist[1].print_overview();
			cout << "       ----------> " << endl;
			cout << plist[pp].get_name() << "S turn" << endl << endl << endl;
			cout << "Please insert the field, from where you would like to move the stones" << endl;
			cout << "Number between 0 to 5: " << endl;
			cin >> choice;
			if (choice > 5 || plist[pp].field_empty(choice)){
				cout <<  "You picked an empty or an invalid field, please pick a valid field!" << endl;
				clear_main();
				continue;
			}
			else{
				int return_stones=0;
				int move_to_opponent = plist[pp].move(choice);			//players move//
				if (move_to_opponent != 0)								//if fieldnumber+number of stones > own fields+1
					return_stones = plist[(pp+1)%2].move_to_opponent(move_to_opponent);//the remaining stones go to opponent-field//
				if (return_stones != 0){									//if remaining stones > opponent field
					return_stones = plist[(pp)].move_to_opponent(return_stones); //stones come back to own fields
				}
				if (plist[pp].get_caught_field()!=-1){							
					int fieldnumber = plist[pp].get_caught_field();		//if last stone goes to an own empty field
					int stones = plist[(pp+1)%2].get_opponent_stones(fieldnumber); //player get the opposite-placed stones to his pot
					plist[pp].add_kalah(stones);//also as his last moved stone//
				}
				clear_main();
			}
		}
		pp = (pp+1)%2;		//next players turn
		plist[pp].set_turn(true);
		
	}while (plist[0].get_kalah()<19 && plist[1].get_kalah()<19 && !plist[0].emtpy() && !plist[1].emtpy());
	//game is over when one player got more then 18 stones (total stones = 36) or all his fields are empty
	cout << "       <---------- " << endl << endl;
			plist[0].print_overview();
			plist[1].print_overview();
			cout << "       ----------> " << endl;
	if (plist[0].get_kalah() > plist[1].get_kalah())
		cout << plist[0].get_name() << " wins "<< endl;
	else if (plist[0].get_kalah() == plist[1].get_kalah())
		cout << " Game ends in a draw "<< endl;
	else cout << plist[1].get_name() << " wins "<< endl; 
}
Last edited on
closed account (1w0XoG1T)
thanks guys for the ideas,...just got logged in today, been busy with the project myself,.. gathering ideas, anyway,

heres how the rules applied:

from what i gathered(from locals who played it, here in Philippines,..): if a player lands in his own domain(either house or pit), he gets another turn, if not, the next player gets to take the turn,.

*note: there is a special condition when a player lands on his own domain, where, if there is nothing in there, 0 to be exact, he gets the tiles across it, *note if there is something across it,
and add it to his own house(total score) and when all domains from 0-6(1-7) of left and right players are zero(0) then they start to count to see who wins, if left player gets higher score than right, he wins, or the other way around.
*note that there are 7 tiles for each pits, so there are 98 tiles all in all.

thanks
to anilpanicker (93) - still i got to check and update your codes applying the rules
to Fenor (6) - i really like the code, but to be fair, i have trouble looking at the output, lol, but thanks anyway,...

and i really want to make this one a short project, in terms of lines, thanks guys,
if you still got some ideas, feel free to share,
closed account (1w0XoG1T)
i was wondering if we can make an AI out of this,...
using randomizations on structures or pointers,..
whatever useful,
help me out on this one guys,.. thanks in advance
One uestion:

At each turn a player empties one of his small pits and then distributes its contents in a counterclockwise direction, one by one, into the following pits including his own store, but passing the opponents store.

If the last stone falls into a non-empty small pit, its contents are lifted and distributed in another lap. Q: Is this in the same turn or another turn after the other player is moved?
If the last stone is dropped into the player's own store, the player gets a bonus move.
If the last stone is dropped into an empty, the move ends.
closed account (1w0XoG1T)
to anilpanicker (100)

> If the last stone falls into a non-empty small pit, its contents are lifted and distributed in another lap?

> answer: no, if the last stone falls into a non empty small pit, (if the last stone falls into your own pit, you have another move, if it falls into the opponents pit, the turn ends)

> a players turn will consist of passing his own pit and store as well as the opponent's pit, but not the opponent's store,..
then you need to modify the else statement in line 163
1
2
3
4
5
6
7
8
else
			{
				stones_left=0;
				next_row[i]=1;
				break;
			}

closed account (1w0XoG1T)
i've copied the program by fenor,
and i had few little ideas about it,
since sungka is a 7 stone 7 pit and 2 house game,
and the moves goes clock wise(not counter clockwise)
it seems there are minor errors,
thanks for the code fenor,
we can use this but i have to admit,
this is a high-level language we are using,
and thanks to anilpanicker for the code fragments and ideas

this is hereby solved...
Not knowing it's name, I've actually played this game on computer years ago. Might have a go myself.
Topic archived. No new replies allowed.