What you could do is set a maximum size a button should have, and then simply divide the container size to find the amount of buttons you'd want. This part is all easy, adding buttons is not really any problem. You could use the Tag
property to keep track of the buttons position in the tic tac toe array.
I'm thinking though since you have a maximum amount of buttons you'd want, you could create the 9x9 buttons from the beginning, simply setting their Visible
property to false
showing them as you need them. The resize routine then only has to resize the buttons.
I have provided a simple example of how to create the buttons in the form constructor, note though that this is extremely simple, but simply serves to illustrate my above point. Note that I'm using a single dimensional array, instead of a 2 dimensional one, this is to make it easier finding a winner later on.
// Declare constants used for our tic tac toe example
const int minButtons = 3; // The minimum number of buttons in either direction
const int maxButtons = 9; // The maximum number of buttons in either direction
const int buttonDistance = 5; // The distance between the buttons
const int buttonSize = 50; // The targeted button size.
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
// Create our buttons and set some tag value to identify them later.
for (int i = 0; i < maxButtons; i++)
{
for (int j = 0; j < maxButtons; j++)
{
int idx = i * maxButtons + j;
buttons[idx] = new TButton(this);
buttons[idx]->Parent = this;
// Assign the on click event (we define this later)
buttons[idx]->OnClick = ButtonPressed;
}
}
// Let the X player start
currentPlayer = "X";
}
After creating the buttons you can control how many to display and size these in the forms OnResize
event:
void __fastcall TForm1::FormResize(TObject *Sender)
{
// Calculate the number of buttons to display.
int btd = std::min(ClientWidth, ClientHeight) / buttonSize;
// Make sure we have atleast minButtons and at most maxButtons buttons.
btd = (btd < minButtons) ? minButtons : (btd > maxButtons) ? maxButtons : btd;
// Write the tic tac toe board size in the form caption
Caption = IntToStr(btd) + " x " + IntToStr(btd);
// Calculate the new button size.
int buttonWidth = (ClientWidth - (btd - 1) * buttonDistance) / btd;
int buttonHeight = (ClientHeight - (btd - 1) * buttonDistance) / btd;
// Show and position buttons
for (int i = 0; i < maxButtons; i++)
{
for (int j = 0; j < maxButtons; j++)
{
int idx = i * maxButtons + j;
if (i < btd && j < btd)
{
buttons[idx]->Visible = true;
buttons[idx]->Width = buttonWidth;
buttons[idx]->Height = buttonHeight;
buttons[idx]->Left = i * buttonWidth + i * buttonDistance;
buttons[idx]->Top = j * buttonHeight + j * buttonDistance;
}
else
{
buttons[idx]->Visible = false;
}
}
}
}
Now we need the code to process the user input, that is whenever the user presses one of our buttons, we cast the Sender parameter to a TButton, this way we can do the click processing in a single function.
void __fastcall TForm1::ButtonPressed(TObject *Sender)
{
TButton *btn = dynamic_cast<TButton*>(Sender);
if (btn)
{
// Check if this button is free to be pressed
if (btn->Enabled)
{
btn->Caption = currentPlayer;
btn->Enabled = false;
if (IsWinner())
ShowMessage(currentPlayer + " is the winner :)");
if (currentPlayer == "X") currentPlayer = "O";
else currentPlayer = "X";
}
}
}
Finally we add a simple function to check if the current player is the winner, this can obviously be made more smart and much more optimized, but this is just a simple example serving as source of inspiration:
bool __fastcall TForm1::IsWinner()
{
bool foundWinner;
// Calculate the number of buttons to display.
int btd = std::min(ClientWidth, ClientHeight) / buttonSize;
// Make sure we have atleast minButtons and at most maxButtons buttons.
btd = (btd < minButtons) ? minButtons : (btd > maxButtons) ? maxButtons : btd;
// Check for a winner in the direction top to bottom
for (int i = 0; i < btd; i++)
{
foundWinner = true;
for (int j = 0; j < btd; j++)
{
if (buttons[i * maxButtons + j]->Caption != currentPlayer)
foundWinner = false;
}
if (foundWinner) return true;
}
// Check for a winner in the direction left to right
for (int j = 0; j < btd; j++)
{
foundWinner = true;
for (int i = 0; i < btd; i++)
{
if (buttons[i * maxButtons + j]->Caption != currentPlayer)
foundWinner = false;
}
if (foundWinner) return true;
}
// Check for a winner in the diagonal directions
foundWinner = true;
for (int i = 0; i < btd; i++)
{
if (buttons[i * maxButtons + i]->Caption != currentPlayer)
foundWinner = false;
}
if (foundWinner) return true;
foundWinner = true;
for (int i = btd - 1; i >= 0; i--)
{
if (buttons[i * maxButtons + i]->Caption != currentPlayer)
foundWinner = false;
}
return foundWinner;
}
Obviously there is a lot left to be done, the whole processing of who has won (update just added a simple check), creating an interface to start a new game etc. Besides the game is not entirely error proof, in the current version the game adds extra buttons when you resize even after the game has started, this is most likely not what you want, but fixing this is a simple question of adding a check to the resize function. Anyway I'm not about to create the entire game for you, I'm quite certain you'd wanna do that yourself.
If you find it useful you can use it, if not then perhaps (and most likely) you can be inspired by my approach (which is really a 2 minute made solution). Hope it works for you. The free webdesign won't be neccesary, I guess you can save that for some later question ;)