Game 3-5-7 - Game Logic

This tutorial expands on the game play functionality that was introduced in tutorial Game 3-5-7 - Basic Functionality.

You can download the sample stack from this url: https://tinyurl.com/ybzykgh4

Introduction

By the time you reach this tutorial, you should be able to play the game 3-5-7 on a LiveCode stack. The additional functionality covered here shows you how to add a formal two player mode, restrict moves that are not legal and detect which player has won the game.

Adding a Next Move Button

Adding a Next Move Button

In order to play 3-5-7 with two players, it is necessary to inform LiveCode when one player is finished and the next player is allowed to start. We can do this by adding a "Next Move" button. This button also serves as an indicator for the player who is executing a move at a particular time in the game.

Add a button as is shown in Game 3-5-7 - A Simple Interface, set the button name to "Next Move", and set the button label to "Player 1", as is shown in the image above. These are the only interface changes required. All further changes are implemented in the code.

Introduction to the Code

The code described in the remaining steps replaces the code that was covered in Game 3-5-7 - Basic Functionality. You should copy and paste the code in the order it appears in this tutorial over the code that you already implemented for the game.

A Global Variable

In order to ensure that a player only removes buttons from one line, it is necessary to create a variable that remembers from what line a previous button was removed. We create a global variable for this, allowing the variable content to be visible from all parts of the remaining code.

// Declare a global variable that records from
// which line buttons are being removed.
local gCurrentPlayLine

Opening the Card

If you decide to save the game for future play, we should reset the game when the card opens up. The following command handles openCard events and resets any game state to the game start state. This event handler calls a command that is described later on in this tutorial.

on openCard
   // Reset the game when the stack opens up.
   resetGame
end openCard

Handling Mouse Events

The structure of the mouseUp command in this tutorial is similar to the structure of the mouseUp command in the previous tutorial of this series. We changed the command by added a condition for the new "Next move" button and replaced operational code segments with calls to commands that are implemented in future steps of this tutorial. Moving code into our own defined commands allows us to create a modular and structured flow of the game code.

on mouseUp
   // Declare two variables.
   local tButtonName, tControl
   // Specify a delimiter that allows you to select an item in a line of text.
   set the itemDelimiter to space
   // Get the name of the button as was specified it in the Property Inspector.
   put the short name of target into tButtonName
   // Test if the mouse click comes from a button or something else.
   // The first item of the target name specifies the
   // type of control that sent the mouse message.
   if item 1 of the name of target is "button" then
      if tButtonName is "Reset" then
         // If the reset button was pressed then reset the game.
         resetGame
      else if tButtonName is "Next Move" then
         // If the next move button was pressed
         // then allow the next player to make their move.
         nextPlayer
      else
         // If a game button was pressed, then remove that button.
         testAndRemoveButton tButtonName
         // Test if the current state of the game
         // is a losing state for the current player.
         testForWin
      end if
   end if
end mouseUp

Resetting the Game

The resetGame command shows all the hidden game buttons and updates the label of the "Next Move" button to indicate that "Player 1" should start the game. The variable gCurrentPlayLine is also set to empty, allowing the player to select the first game button from any line that contains buttons.

command resetGame
   // Declare a variable.
   local tControl
   // Specify a delimiter that allows you to select an item in a line of text.
   set the itemDelimiter to space
   // Loop through all the buttons on the card.
   repeat with tControl = 1 to the number of buttons of me
      // Make the button visible that we are currently pointing to.
      set the visible of button tControl to true
   end repeat
   // Set the label of the next move button to Player 1.
   set the label of button "Next Move" to "Player 1"
   // Ensure that the player can start selecting from any line.
   put empty into gCurrentPlayLine
end resetGame

Switching the Player

When a player switches to another player, using the next move button, we need to take two actions:

1. Indicate that the next player can play.

2. Allow the next player to remove the first button of the move from any of the three lines of buttons.

We switch the label of the "Next Move" button by testing the existing value of the label. If the label is "Player 1" then switch the label to "Player 2", otherwise switch the label to "Player 1". The variable gCurrentPlayLine is set to empty in order to allow the next player to remove buttons from any one of the three lines of buttons.

command nextPlayer
   // If the next move button displays Player 1, then switch it to Player 2.
   if the label of button "Next Move" is "Player 1" then
      set the label of button "Next Move" to "Player 2"
   else
      set the label of button "Next Move" to "Player 1"
   end if
   // Ensure that the player can start selecting from any line.
   put empty into gCurrentPlayLine
end nextPlayer

Removing Valid Game Buttons

When it is a player's turn to make a move, the player can remove any number of buttons from only one line of buttons on the board. The initial button selection can be from any line on the board, but subsequent button selections must be from the same line from which the first button was removed. This behavior is implemented by using the gCurrentPlayLine variable. Before a player makes a first move, this variable is empty, once the player has made a move, this variable is assigned the line on which the button was stored. A test in the command described in this step test if gCurrentPlayLine is empty or if a value is set and matches the line number of the button to the value stored in the variable.

The line number is stored in the name of each button and we access this number by stepping through the space delimited items in the button name.

If the player tries to remove a button that is not on the same line as the first button that was removed, then the player receives a message, indicating that the button selection was illegal.

command testAndRemoveButton pButtonName
   // Specify a delimiter that allows you to select an item in a line of text.
   set the itemDelimiter to space
   // Test if the player is allowed to take that button away from the board.
   if gCurrentPlayLine is empty or item -1 of pButtonName is gCurrentPlayLine then
      // Make one of the 15 game buttons invisible.
      set the visible of control pButtonName to false
      // Put the line number from which the button
      // was removed into gCurrentPlayLine.
      put item -1 of pButtonName into gCurrentPlayLine
   else
      // If this was an illegal move then inform the player.
      answer "That is an illegal move. Only take buttons from the same line." with "Okay"
   end if
end testAndRemoveButton

Who is the Winner?

After every move, a test is carried out to identify if the current player is the winner of the game. The test loops through all of the controls of the board and tests for a game button that is visible. If such a button can be found, then the game is not over and the test terminates. If a visible game button cannot be found, then a message is raised, indicating that the current player has won the game. Have a look at the last line of the code to see how this test identifies which player is the winner.

command testForWin
   // Declare two buttons.
   local tButtonName, tControl
   // Specify a delimiter that allows you to select an item in a line of text.
   set the itemDelimiter to space
   // Loop through all the buttons on the card.
   repeat with tControl = 1 to the number of controls of me
      // Get the name of the button that we are currently pointing at.
      put the short name of control tControl into tButtonName
      // If the button we are currently pointing at is visible, then exit this test.
      if item 1 of tButtonName is "Btn" and the visible of control tButtonName is true then
         exit testForWin
      end if
   end repeat
   // If we could not find a visible game button, 
   // then inform the user that they have lost.
   answer the label of button "Next Move" & ", you have won." with "Okay"
end testForWin

13 Comments

Ellery

I am getting the notification that I won everytime I click any button I have copied the code exactly... is anyone else getting this problem or know why I am getting it?

Hanson Schmidt-Cornelius

Hi Ellery,

this lesson is the last one in a set of three.

You should make sure that you followed the instructions in the previous lessons. In particular, you should ensure that the buttons are correctly named, as specified in the first lesson: http://lessons.runrev.com/s/lessons/buckets/809/lessons/44007

If the buttons are not named properly, then "testForWin" assumes that all playing buttons are invisible and the last person playing selected the last button(s).

Hope this fixes it for you.

Kind Regards,

Hanson

Ullrich

it has to do with how you copy and paste the code from the pdf. double check every line to make sure that all of the executable code is NOT in a comment line! That was my issue.

Hanson Schmidt-Cornelius

Hi Ulrich,

yes, when you copy and past the code from the lessons, then you can get certain characters that do not paste directly into the LiveCode Script Editor. It is necessary to remove characters at the beginning of each line.

Kind Regards,

Hanson

Filip

Hi,

I wrote took the first two parts of this tutorial and everything worked flawlessly.

However, with this tutorial, nothing is happening when I click on a button. It doesn't matter which button I click, nothing is happening.

I did not copy paste the code, instead I wrote the code literally as written in this tutorial, but without the // green sentences.

Do I need this green sentences in my code as well? I thought they are only there to clarify what you need to do, and in the other parts of this tutorial it worked without this code. I double checked and everything is the same as here.

I wrote the code down in chronological order as in this tutorial, so starting from above with local gCurrentPlayLine etc.
After each piece of code I have a return, but I tried with and without return, nothing changed.

Is there anything else I could have overlooked?

Thanks,

Jessie Mark L. Fajerga

i get the same problem with Ellery, every time i click a button the notification pop-up that it is an invalid move.

Hanson Schmidt-Cornelius

Hi,

I think this reply is relevant to everyone who has so far posted comments to this lesson.

I have attached a sample stack that implements the functionality of this lesson. This should take the pain out of copying the code in the lesson and formatting it.

This game implements basic two player functionality and does not provide any artificial intelligence that allows the computer to play against a human player. So the "Player X" button indicates what human player is currently playing.
If one player is finished making their moves, then they should hit that button. The button toggles the number between 1 and 2 and the next player then makes their moves. When the next player is finished, they then hit the button, and so on, until the game is over.

I hope this addresses a number of issues you may have been having with this lesson.

Kind Regards,

Hanson

Wouter De Backer

When I save this stack as a standalone app for Windows and run it then two indications appear in the user interface that look like a button:
1) revGeometryBack
2) revCommon

Even when I use the stack that is downloadable from this lesson.

How can I avoid those indications?

Greetings

Willy

Hi.

I have tried the supplied stack as well as my own written code following the tutorial but then i m having same problem like Wouter De Backer.

After building standalone program for Mac osx. When running the program, i got revGeometryBack & revCommon button.

Any advice on how to get rid of these buttons?

Thanks.

Moira O'Brien

I have the same issue as Wouter De Backer but with Mac OS:

revGeometryBack
revCommon

appear on top of the buttons.

How can we get rid?

Neil

Hi Wouter,

Some libraries in LiveCode are saved within buttons and these are included when a standalone is built. This will also explain why you will not see them in the IDE.

The main reason these are showing is because “control” is being used instead of “button” in the reset game handler. Changing this to button allows the standalone to work as expected. The correct resetGame handler is shown below-

command resetGame
// Declare a variable.
local tControl
// Specify a delimiter that allows you to select an item in a line of text.
set the itemDelimiter to space
// Loop through all the buttons on the card.
repeat with tControl = 1 to the number of buttons of me
// Make the button visible that we are currently pointing to.
set the visible of button tControl to true
end repeat
// Set the label of the next move button to Player 1.
set the label of button "Next Move" to "Player 1"
// Ensure that the player can start selecting from any line.
put empty into gCurrentPlayLine
end resetGame

I will also update the lesson with this information

Kind Regards,


Neil Roger
--
LiveCode Support Team ~ http://www.livecode.com

Ed Lamaster

I had to change the "-1" to "2" to make this work in Livecode 9.5:

command testAndRemoveButton pButtonName
[...]
change: if gCurrentPlayLine is empty or item -1 of pButtonName is gCurrentPlayLine then
to: if gCurrentPlayLine is empty or item 2 of pButtonName is gCurrentPlayLine then
[...]
change: put item -1 of pButtonName into gCurrentPlayLine
to: put item 2 of pButtonName into gCurrentPlayLine
[...]
end testAndRemoveButton

Elanor Buchanan

Hi Ed

Item -1 refers to the last item, I just did a quick test and it appears to work in 9.5 here. If you have named your buttons slightly differently it might be that the code needs to be adjusted to match your button names.

Could you try the sample stack attached to the lesson and see if that works for you?

Thanks

Elanor

Add your comment

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.