1
0
www.mikescher.com/www/data/programs/desc/BefunUtils/03_Examples/11_Square It.markdown

9.7 KiB

###Square It

An implementation of the game Square It. Complete with a computer opponent.

program Square_It : display[34, 36] // 1 + 1+2*16 || 1 + 1+2*16 + 2
	const
		int FIELD_WIDTH := 16;
		int FIELD_HEIGHT := 16;
		
		char CHAR_VERTICAL := '|';
		char CHAR_HORIZONTAL := '-';
		char CHAR_EMPTY := ' ';
		char CHAR_JUNCTION := '+';
		char CHAR_EMPTYFIELD := ' ';
		char CHAR_PLAYER_P1 := 'X';
		char CHAR_PLAYER_P2 := 'O';
		char CHAR_PLAYER_NEUTRAL := '#';
	
	global
		char currPlayer;
		int p1_c, p2_c;
	begin
		restart();
	end
	
	void restart()
	var
		int choice;
	begin
		for(;;) do
			Init();
			
			outf	"WHAT DO YOU WANT TO PLAY?", 
					"\r\n", 
					"0: Player vs Player", 
					"\r\n", 
					"1: Player vs Computer", 
					"\r\n", 
					"2: Computer vs Computer",
					"\r\n",
					"\r\n",
					"\r\n";
					
			in choice;
			
			if (choice == 0) then
				Game_P_v_P();
			elsif (choice == 1) then
				Game_P_v_NP();
			elsif (choice == 2) then
				Game_NP_v_NP();
			end
		end
	end
	
	void Game_P_v_P()
	var
		char winner;
	begin
		currPlayer = CHAR_PLAYER_P1;
	
		repeat
			outf "PLAYER ", currPlayer, ":\r\n";
			DoPlayerTurn();
		until (GameFinished())
		
		winner = GetWinningPlayer();
		
		if (winner == CHAR_PLAYER_P1) then
			out ">> PLAYER 1 (X) WINS !\r\n\r\n";
		elsif (winner == CHAR_PLAYER_P2) then
			out ">> PLAYER 2 (O) WINS !\r\n\r\n";
		else
			out ">> DRAW !\r\n\r\n";
		end
		
		return;
	end
	
	void Game_P_v_NP()
	var
		char winner;
	begin
		currPlayer = CHAR_PLAYER_P1;
	
		repeat
			if (currPlayer == CHAR_PLAYER_P1) then
				outf "PLAYER ", currPlayer, ":\r\n";
				DoPlayerTurn();
			else
				outf "COMPUTER ", currPlayer, ":\r\n";
				DoComputerTurn();
			end
		until (GameFinished())
		
		winner = GetWinningPlayer();
		
		if (winner == CHAR_PLAYER_P1) then
			out ">> YOU WIN !\r\n\r\n";
		elsif (winner == CHAR_PLAYER_P2) then
			out ">> YOU LOOSE !\r\n\r\n";
		else
			out ">> DRAW !\r\n\r\n";
		end
		
		return;
	end
	
	void Game_NP_v_NP()
	var
		char winner;
	begin
		currPlayer = CHAR_PLAYER_P1;
	
		repeat
			outf "COMPUTER ", currPlayer, ":\r\n";
			DoComputerTurn();
		until (GameFinished())
		
		winner = GetWinningPlayer();
		
		if (winner == CHAR_PLAYER_P1) then
			out ">> PC1 (X) WINS !\r\n\r\n";
		elsif (winner == CHAR_PLAYER_P2) then
			out ">> PC2 (O) WINS !\r\n\r\n";
		else
			out ">> DRAW !\r\n\r\n";
		end
		
		return;
	end
	
	void Init()
	var
		int x, y;
		int px, py;
	begin
		for(x = 0; x < FIELD_WIDTH; x++) do
			if (x > 9) then
				display[2 + x*2, 0] = (char)(x + (int)'7');
			else
				display[2 + x*2, 0] = (char)(x + (int)'0');
			end
		end
		
		for(y = 0; y < FIELD_HEIGHT; y++) do
			if (y > 9) then
				display[0, 2 + y*2] = (char)(y + (int)'7');
			else
				display[0, 2 + y*2] = (char)(y + (int)'0');
			end
		end
	
		for(x = 0; x < FIELD_WIDTH; x++) do
			for(y = 0; y < FIELD_HEIGHT; y++) do
				px = 2 + x*2;
				py = 2 + y*2;
				
				// CENTER
				display[px + 0, py + 0] = CHAR_EMPTYFIELD; 
				
				// TOP RIGHT
				display[px + 1, py + 1] = CHAR_JUNCTION;
			
				// BOTTOM RIGHT
				display[px - 1, py + 1] = CHAR_JUNCTION;
				
				// BOTTOM LEFT
				display[px - 1, py - 1] = CHAR_JUNCTION;
				
				// TOP LEFT
				display[px + 1, py - 1] = CHAR_JUNCTION; 
				
				// TOP
				if (y == 0) then
					display[px + 0, py - 1] = CHAR_HORIZONTAL; 
				else
					display[px + 0, py - 1] = CHAR_EMPTY; 
				end
				
				// RIGHT
				if (x == FIELD_WIDTH - 1) then
					display[px + 1, py + 0] = CHAR_VERTICAL; 
				else
					display[px + 1, py + 0] = CHAR_EMPTY; 
				end
				
				// BOTTOM
				if (y == FIELD_HEIGHT - 1) then
					display[px + 0, py + 1] = CHAR_HORIZONTAL;
				else
					display[px + 0, py + 1] = CHAR_EMPTY; 
				end
				
				// LEFT
				if (x == 0) then
					display[px - 1, py + 0] = CHAR_VERTICAL;
				else
					display[px - 1, py + 0] = CHAR_EMPTY;
				end
	 		end
		end
	end
	
	void DoPlayerTurn()
	var
		char x,y,d;
		
		int ix, iy, idx, idy;
		
		int posx, posy;
	begin
		out "    ";
		out "X: ";
		in x;
		out x;
		out " Y: ";
		in y;
		out y;
		out " Direction (U/D/L/R): ";
		in d;
		outf d, "\r\n";
		
		if (x >= '0' && x <= '9') then
			ix = (int)x - (int)'0';
		elsif (x >= 'A' && x <= 'Z') then
			ix = (int)x - (int)'A';
		elsif (x >= 'a' && x <= 'z') then
			ix = (int)x - (int)'a';
		else
			out "    ";
			out "ERROR - CANT PARSE INPUT (X)\r\n";
			DoPlayerTurn();
			return;
		end
		
		if (y >= '0' && y <= '9') then
			iy = (int)y - (int)'0';
		elsif (y >= 'A' && y <= 'Z') then
			iy = (int)y - (int)'A';
		elsif (y >= 'a' && y <= 'z') then
			iy = (int)y - (int)'a';
		else
			out "ERROR - CANT PARSE INPUT (Y)\r\n";
			DoPlayerTurn();
			return;
		end
		
		if (d == 'U' || d == 'u') then
			idx = 0;
			idy = -1;
		elsif (d == 'R' || d == 'r') then
			idx = 1;
			idy = 0;
		elsif (d == 'D' || d == 'd') then
			idx = 0;
			idy = 1;
		elsif (d == 'L' || d == 'l') then
			idx = -1;
			idy = 0;
		else
			out "    ";
			out "ERROR - CANT PARSE INPUT (DIRECTION)\r\n";
			DoPlayerTurn();
			return;
		end
		
		posx = 2 + ix*2 + idx;
		posy = 2 + iy*2 + idy;
		
		if (display[posx, posy] == CHAR_EMPTY) then
			DoTurn(ix, iy, idx, idy);
			
			return;
		else
			out "    ";
			out "ERROR - FIELD ALREADY SET\r\n";
			DoPlayerTurn();
			return;
		end
	end
	
	void DoTurn(int x, int y, int dx, int dy)
	var
		int posx, posy;
		
		bool t_a, t_b;
	begin
		posx = 2 + 2*x;
		posy = 2 + 2*y;
	
		if (dx == 0) then
			display[posx + dx, posy + dy] = CHAR_HORIZONTAL;
		else
			display[posx + dx, posy + dy] = CHAR_VERTICAL;
		end
		
		t_a = testField(x, y);
		t_b = testField(x + dx, y + dy);
		
		if (! (t_a || t_b)) then
			SwitchPlayer();
		end
	end
	
	void DoComputerTurn()
	begin
		if (FindComputerTurn(3)) then 
			return;
		end
	
		if (FindComputerTurn(1)) then 
			return;
		end
	
		if (FindComputerTurn(0)) then 
			return;
		end
	
		if (FindComputerTurn(2)) then 
			return;
		end
		
		while (true) do out "ERROR"; end
	end
	
	bool FindComputerTurn(int target_surr)
	var 
		int c_x, c_y;
		int x, y;
		int r_x, r_y, r_d;
		
		int c_i, i;
		int dx, dy;
	begin
		r_x = RAND[4];
		r_y = RAND[4];
		r_d = RAND[1];
	
		for(c_x = 0; c_x < FIELD_WIDTH; c_x++) do
			for(c_y = 0; c_y < FIELD_HEIGHT; c_y++) do
				x = (c_x + r_x) % FIELD_WIDTH;
				y = (c_y + r_y) % FIELD_HEIGHT;
				
				if (getSurrounding(x, y) == target_surr) then
					for(c_i = 0; c_i < 4; c_i++) do
						i = (c_i + r_d) % 4;
						
						switch(i)
						begin
							case 0:
								dx = 0;
								dy = -1;
							end 
							case 1:
								dx = 0;
								dy = 1;
							end 
							case 2:
								dx = -1;
								dy = 0;
							end 
							case 3:
								dx = 1;
								dy = 0;
							end 
						end
						
						if (display[2+2*x + dx, 2+2*y + dy] == CHAR_EMPTY) then
							switch(i)
							begin
								case 0:
									outf "  X: ", x, " Y: ", y, " D: [UP]", "\r\n";
								end 
								case 1:
									outf "  X: ", x, " Y: ", y, " D: [DOWN]", "\r\n";
								end 
								case 2:
									outf "  X: ", x, " Y: ", y, " D: [LEFT]", "\r\n";
								end 
								case 3:
									outf "  X: ", x, " Y: ", y, " D: [RIGHT]", "\r\n";
								end 
							end
							
							DoTurn(x, y, dx, dy);
							
							return true;
						end
					end
				end
			end
		end
		
		return false;
	end
	
	bool TestField(int x, int y)
	var
		bool result;
	begin
		x = 2 + x*2;
		y = 2 + y*2;
		
		result = true;
		
		result &= (display[x, y] == CHAR_EMPTYFIELD);
		
		result &= (display[x + 1, y] != CHAR_EMPTY);
		result &= (display[x - 1, y] != CHAR_EMPTY);
		result &= (display[x, y + 1] != CHAR_EMPTY);
		result &= (display[x, y - 1] != CHAR_EMPTY);
		
		if (result) then
			display[x, y] = currplayer;
			return true;
		else
			return false;
		end
	end
	
	void SwitchPlayer() 
	begin
		if (currplayer == CHAR_PLAYER_P1) then
			currplayer = CHAR_PLAYER_P2;
		else
			currplayer = CHAR_PLAYER_P1;
		end
		
		display[DISPLAY_WIDTH - 9, DISPLAY_HEIGHT - 1] = 'P';
		display[DISPLAY_WIDTH - 8, DISPLAY_HEIGHT - 1] = 'L';
		display[DISPLAY_WIDTH - 7, DISPLAY_HEIGHT - 1] = 'A';
		display[DISPLAY_WIDTH - 6, DISPLAY_HEIGHT - 1] = 'Y';
		display[DISPLAY_WIDTH - 5, DISPLAY_HEIGHT - 1] = 'E';
		display[DISPLAY_WIDTH - 4, DISPLAY_HEIGHT - 1] = 'R';
		display[DISPLAY_WIDTH - 3, DISPLAY_HEIGHT - 1] = ' ';
		display[DISPLAY_WIDTH - 2, DISPLAY_HEIGHT - 1] = currplayer;
		
		display[1, DISPLAY_HEIGHT - 1] = (char)((p1_c/100)%10 + 48);
		display[2, DISPLAY_HEIGHT - 1] = (char)((p1_c/10)%10 + 48);
		display[3, DISPLAY_HEIGHT - 1] = (char)((p1_c/1)%10 + 48);
		display[4, DISPLAY_HEIGHT - 1] = ' ';
		display[5, DISPLAY_HEIGHT - 1] = '-';
		display[6, DISPLAY_HEIGHT - 1] = ' ';
		display[7, DISPLAY_HEIGHT - 1] = (char)((p2_c/100)%10 + 48);
		display[8, DISPLAY_HEIGHT - 1] = (char)((p2_c/10)%10 + 48);
		display[9, DISPLAY_HEIGHT - 1] = (char)((p2_c/1)%10 + 48);
	end
	
	int GetSurrounding(int x, int y)
	var
		int result;
	begin
		result = 0;
		
		x = 2 + x*2;
		y = 2 + y*2;
		
		result += (int)(display[x + 1, y] != CHAR_EMPTY);
		result += (int)(display[x - 1, y] != CHAR_EMPTY);
		result += (int)(display[x, y + 1] != CHAR_EMPTY);
		result += (int)(display[x, y - 1] != CHAR_EMPTY);
		
		return result;
	end
	
	bool GameFinished()
	var
		int x, y;
	begin
		p1_c = 0;
		p2_c = 0;
		
		for(x = 0; x < FIELD_WIDTH; x++) do
			for(y = 0; y < FIELD_HEIGHT; y++) do
				if (display[2+2*x, 2+2*y] == CHAR_PLAYER_P1) then
					p1_c++;
				elsif (display[2+2*x, 2+2*y] == CHAR_PLAYER_P2) then
					p2_c++;
				end
			end
		end
		
		return p1_c + p2_c == FIELD_WIDTH * FIELD_HEIGHT;
	end
	
	char GetWinningPlayer()
	begin
		if (p1_c > p2_c) then
			return CHAR_PLAYER_P1;
		elsif (p1_c < p2_c) then
			return CHAR_PLAYER_P2;
		else
			return CHAR_PLAYER_NEUTRAL;
		end
	end

Note: This and other examples are included in the BefunGen download