Dice game simulator kotlin - loops

I'm writing a code where I am versing the computer. A player throws a six-sided die and scores as many points as the total shown on the die providing the die doesn’t roll a 1.
The player may continue rolling and accumulating points (but risk rolling a 1) or end his turn.
If the player rolls a 1 his turn is over, he loses all points he accumulated that turn, and he passes the die
to the next player.
If the player ends without throwing a 1, the turn total is then added to the player's grand total.
Play passes from player to player until a winner is determined.
We are playing against the computer. The computer will roll the die using this rule:
A random number between 1 and 2 is CALCULATED. IF the number is a 1, the computer will roll. IF the number is a 2 it will stop rolling and give the dice back to the player. This loops until the calculated random number is a 2.
If a 1 is rolled, the turn is over and the computer loses all points from that turn.
The sum of all the rolls of the dice during this turn are added to computer's grand total
The human player can choose from a menu whether to roll again or "hold" and allow the computer to have a turn.
The issue is when I press hold (2) to pass it to the computer (ai) or when I roll a 1 it does nothing. the program stops. I am trying to git the program to only stop if all conditions are met can someone please help this is what I have so far.
var player = 0
var turntotal = 0
var computerpoints = 0
var grandtotal = 0
var roll = (1..6).random()
var ai = (1..2).random()
println("1. Roll Dice")
println("2. Hold and pass to computer")
println("3. Quit")
println()
println("Please select a menu Item")
player = readLine()!!.toInt()
while (turntotal < 50 && computerpoints < 50 && player != 3)
if (player == 1) {
roll = (1..6).random()
println("You rolled a $roll")
turntotal += roll
println("Turn total: $turntotal")
println("***********************************")
println("* Grand Total - You: $turntotal Computer:$computerpoints *")
println("***********************************")
while (roll != 1) {
println("1. Roll Again")
println("2. Hold")
player = readLine()!!.toInt()
if (player == 2) break
roll = (1..6).random()
println("You rolled a $roll")
turntotal += roll
println("Turn total: $turntotal")
println("***********************************")
println("* Grand Total - You: $turntotal Computer:$computerpoints *")
println("***********************************")
}
if (roll == 1) {
turntotal = 0
println("You rolled a $roll")
println("You lose all your turn points and turn ")
println("***********************************")
println("* Grand Total - You: $turntotal Computer:$computerpoints *")
println("***********************************")
println()
println("Computer's turn to roll")
while ( ai != 1)
roll = (1..2).random()
if (roll == 1)
roll =(1..6).random()
println("Computer decides to roll: $roll")
computerpoints += roll
println("Computer's points: $computerpoints")
println("***********************************")
println("* Grand Total - You: $turntotal Computer:$computerpoints *")
println("***********************************")
if (roll== 1)
computerpoints = 0
println("Computer rolled a $roll")
println("Computer's points is $computerpoints")
println("***********************************")
println("* Grand Total - You: $turntotal Computer:$computerpoints *")
println("***********************************")
if (roll == 2 )
println("1. Roll Dice")
println("2. Hold and pass to computer")
println("3. Quit")
println()
println("Please select a menu Item")
player = readLine()!!.toInt()
}
}
}

That formatting's hard to read (it's hard to see how the ifs and whiles are nested without the indentation and the missing braces) but you're not actually handling the user pressing 2 anywhere, except breaking out of one of the while loops.
Since your whole game loop is in this outer while:
player = readLine()!!.toInt()
...
while (turntotal < 50 && computerpoints < 50 && player != 3) {
// stuff for this turn
}
you need to read the player's choice inside that loop, right? Right now it looks like your loop only does something if player == 1 (everything looks like it's supposed to be inside that if block) but if they entered 2 last turn, then player is still 2, so the while runs forever.
You could do something like this:
// inside your main turn loop
// player turn
val playerBust = false
do {
val playerChoice = showMenu()
// handle the user choosing to roll
if (playerChoice == 1) {
val result = roll()
if (result == 1) playerBust = true
}
} while (!playerBust && playerChoice != 2) // keep going until they bust or hold
By using do/while the loop always runs at least once, so you can show your menu in there, and then check if they get another go in the while check at the end. By not relying on any old player state, each turn starts "fresh" and you can set playerBust to false, read in their first choice and go from there. And you can do the same for the computer turn!
Also I simplified it by using functions like showMenu() (returns the option the player chose) and roll() (rolls the die and returns the result). It's up to you if you want to implement functions like that, but it can really clean up the repeated code and make it simpler to reason about. The computer can call roll() too, right? Same for printing out the results - you can put all that formatting in a separate function, so your game loop is shorter and just contains the core logic. Smaller blocks of code are easier to work with!

Related

How to use a While Loop to repeat the code based on the input variable

i'm having a rough time trying to do a loop with the while function.
Basicly i want the code to show me all prime numbers from 0 to the number i wrote in input.
Then, to ask a question if i want to do it one more time (if yes to repeat the code from the start) or if not to exit.
How i got it now is just to repeat the last results infinitely.
All results i found online with the while loop don't really explain how to repeat a certain part of the code.
I'm by no means even a little bit educated when it comes to this stuff so if its a stupid question, please forgive me.
# Python program to print all primes smaller than or equal to
# n using Sieve of Eratosthenes
def start(welcome):
print ("welcome to my calculation.")
value = input("number?:\n")
print(f'you have chosen: {value}')
value = int(value)
def SieveOfEratosthenes(n):
prime = [True for i in range(n + 1)]
p = 2
while (p * p <= n):
if (prime[p] == True):
for i in range(p ** 2, n + 1, p):
prime[i] = False
p += 1
prime[0] = False
prime[1] = False
print("Primary numbers are:")
for p in range(n + 1):
if prime[p]: print(p)
# driver program
if __name__ == '__main__':
n = value
SieveOfEratosthenes(n)
pitanje = input("do you want to continue(yes/no)?")
while pitanje == ("yes"):
start: SieveOfEratosthenes(n)
print("continuing")
if pitanje == ("no"):
print("goodbye")
strong text
Firstly you should remove
value = input("number?:\n")
print(f'you have chosen: {value}')
value = int(value)
from the top of your code, everything must be inside your __main__ program.
Basically what you need to do is create a main While loop where your program is gonna run, it will keeps looping until the response is not "yes".
For each iteration, you ask a new number at the beggining and if it has to keep looping at the end.
Something like this:
# driver program
if __name__ == '__main__':
# starts as "yes" for first iteration
pitanje = "yes"
while pitanje == "yes":
# asks number
value = input("number?:\n")
print(f'you have chosen: {value}')
value = int(value)
# show results
start: SieveOfEratosthenes(value)
# asks for restart
pitanje = input("do you want to continue(yes/no)?")
#if it's in here the response wasn't "yes"
print("goodbye")

How do I remove a single life per collision of two 2D objects?

I am programming a game for fun and to get more familiar with C and GBA mode 3. Though, I have run into an issue.
I have these two blocks on the screen, one is the good guy, the other is the bad guy. When the good guy collides with the bad guy its supposed to remove a life. That is where the problem comes in.
I have this within a while loop that runs the game:
if (plyr_row < enemy_row + enemy_size && plyr_ row
+ plyr_size > enemy_row && plyr_col < enemy_col + enemy_size
&& plyr_size + plyr_col > enemy_col)
{
lives--;
}
The lives do go down, but a lot of lives are taken away while the player is making contact with the enemy. In other words, during contact, the lives drop really fast and I just want to remove one for each time they collide, how can I accomplish that?
You have to use a flag to remember, if a collision is currently happening or not. Something like:
int in_collision = 0; // global flag, initialized to 0 once at start
...
if (plyr_row < enemy_row + enemy_size &&
plyr_row + plyr_size > enemy_row &&
plyr_col < enemy_col + enemy_size &&
plyr_size + plyr_col > enemy_col) {
if (!in_collision) {
in_collision = 1;
lives--;
}
} else {
in_collision = 0;
}
Now, the running collision must stop before another life will be removed on the following collision.
The simplest solution is to maintain a flag IN_COLLISION. You want to remove a life when there is a collision and IN_COLLISION is false.
Then it's a matter of toggling it to true at the first collision detection and then to false when you are not colliding anymore.

How to detect a collision between two objects in an Array (Sprite Kit)

I have an array of Bullets and Enemies objects. I want the game to check each element in the arrays to see whether there was a collision between the two or not. If there was any collision, then damage that enemy and delete the bullet. Right now every time a bullet hits an enemy it decreases the health of ALL the enemies in the array, thus killing them all at once. How can I make it so that it only decreases the health of the enemy which I'm shooting at?
//This function handles our collision detection
func didBegin(_ contact: SKPhysicsContact) {
//print("COLLISIONS!")
// If contact is with another object
if contact.bodyA.categoryBitMask == pickupCategory && contact.bodyB.categoryBitMask == playerCategory
{
displayText(text: "Picked up Pistol")
player.setHasPistol(gotPistol: true)
pistol.removeFromParent()
}
//Bullet hits an object
if contact.bodyA.categoryBitMask == objectCategory && contact.bodyB.categoryBitMask == bulletCategory
{
bulletCleanup(killNow: true)
//print("BULLET HAS HIT THE PIPE!")
}
//Do collisions between bullets and enemies...
for bullet in bulletList
{
for enemy in enemyList
{
//if the enemy was hit have them take damage.
if contact.bodyA.categoryBitMask == enemyCategory && contact.bodyB.categoryBitMask == bulletCategory
{
//deletes the bullet after hitting an object
bulletCleanup(killNow: true)
//apply damage
enemy.setHitPoints(setPoints: enemy.getHitPoints() - pistol.getDamage())
// print("BULLET HAS HIT THE enemy!!!!")
}
}
}
}
didBegin(contact:) is called for a single collision between one specific object and another specific object. (actually between physics bodies...)
Your problem is occurring because you are iterating over every bullet and every enemy for a single collision and at each iteration you are testing if the collision was between a bullet and an enemy, which it was, so you are applying the damage to every enemy.
All you need to do is to extract the specific enemy from the SKPhysicsContact object and apply damage to that particular enemy.
Also, I suspect you are missing some contacts because for your contact tests, you are not checking if the bodyA and bodyB physics bodies are reversed i.e.
if contact.bodyA.categoryBitMask == pickupCategory && contact.bodyB.categoryBitMask == playerCategory
bodyA might be player and bodyB might be pickup, so you need to test for this also.
Here is an alternative didBegincontact() you might find helpful (It's Swift2, but that shouldn't be a big problem):
func didBeginContact(contact: SKPhysicsContact) {
let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
switch contactMask {
case pickupCategory | playerCategory
displayText(text: "Picked up Pistol")
player.setHasPistol(gotPistol: true)
let pistol = (contact.bodyA.categoryBitMask == pickupCategory) ? contact.bodyA.node! : contact.bodyB.node!
pistol.removeFromParent()
case objectCategory | bulletCategory
bulletCleanup(killNow: true)
//print("BULLET HAS HIT THE PIPE!")
case enemyCategory| bulletCategory
//deletes the bullet after hitting an object
bulletCleanup(killNow: true)
//apply damage
let enemy = (contact.bodyA.categoryBitMask == enemyCategory) ? contact.bodyA.node! : contact.bodyB.node!
enemy.setHitPoints(setPoints: enemy.getHitPoints() - pistol.getDamage())
default :
//Some other contact has occurred
print("Some other contact")
}
}
I'm not sure how your bulletCleanup() function works - you don't appear to be sending it a specific bullet object so I don't know how it knows which bullet to process. The specific bullet involved in the contact can be obtained in didBegincContact: as follows:
let bullet = (contact.bodyA.categoryBitMask == bulletCategory) ? contact.bodyA.node! : contact.bodyB.node!
which is a short form of saying "is nodeA's categoryBitMask a bulletCategory? If it is, then set bullet equal to nodeA, otherwise set bullet to nodeB.
Note that if your categories are more complicated (i.e. objects can belong to multiple categories), this won't work as the simple AND tests (enemyCategory| bulletCategory) won't match.

Taking an array option out for one cycle

Ok so I have this code where spawn locations are put into an array and then one of the locations is picked at random with this code:
let randx = spawnLocations[Int(arc4random_uniform(UInt32(spawnLocations.count)))]
obstacle.position = CGPoint(x: randx, y: 0)
Object Spawning code:
var spawnLocations:[CGFloat] = []
func getObjectSpawnLocation() {
//Create 5 possible spawn locations
let numberOfNodes = 5
// Spacing between nodes will change if: 1) number of nodes is changed, 2) screen width is changed, 3) node's size is changed.
for i in 0...numberOfNodes - 1 {
// spacing used to space out the nodes according to frame (which changes with screen width)
var xPosition = (frame.maxX /*- thePlayer.size.width*/) / CGFloat((numberOfNodes - 1)) * CGFloat(i)
//add a half of a player's width because node's anchor point is (0.5, 0.5) by default
xPosition += thePlayer.size.width/2
//I have no idea what this does but it works.
xPosition -= frame.maxX/1.6
spawnLocations.append( xPosition )
}
()
}
But I have a problem because sometimes the game spawns the objects like in the picture below and it does not let my player advance any further without them dying and so my question is:
Is there anyway I can stop it from doing this?
maybe take one of the spawning locations out of the array temporally?
I should also note that each of the objects (Skulls) are spawned one after the other not all at once and the skulls can spawn at any of the 5 horizontal locations.
The player can only be trapped between the skulls and the screen's edge. You should keep track whether or not you are currently "wedging" the player in or not, for example:
//Keep instance variables to track your current state
BOOL lineFromEdge; //YES if you're currently drawing a "line" of skulls from an edge
BOOL leftEdge; //YES if the line originates from the left edge, NO if from the right
int previousIndex;
Then you determine the value as follows:
- (int) randomIndex {
int randIndex = Int(arc4random_uniform(UInt32(spawnLocations.count)));
// This expression tells you if your current index is at an edge
if (randIndex == 0 || randIndex == (spawnLocations.count - 1)) {
lineFromEdge = YES;
leftEdge = randIndex == 0;
}
//Check if you left a gap
BOOL didLeaveGap = abs(randIndex - previousIndex) > 1
if (didLeaveGap) lineFromEdge = NO;
if ((lineFromEdge && leftEdge && randomIndex == spawnLocations.count) ||
(lineFromEdge && !leftEdge && randomIndex == 0)) {
//You have drawn a line from one edge to the other without leaving a gap;
//Calculate another index and perform the same checks again
return [self randomIndex];
}
//Your index is valid
previousIndex = randIndex;
return randIndex;
}
Note: Your algorithm must return 0 or spawnLocations.count as very first index for this to work. Else your skulls may start at the center and still wedge the player in without you realizing it.

Check taken location on Tic Tac Toe board Matlab

I'm trying to make a small function that checks whether a spot is taken on a Tic Tac Toe board or not. I have created an array of zeroes called tttArray where when each spot is filled, its location is changed to 1. So I first take the input from the player from the below function.
function [pXInputRow, pXInputCol] = pickXspot(playerInput)
%This function is to take inputs from Player X
pXInputRow = 0;
pXInputCol = 0;
%Set text for Row/Col Prompt
prompt = {'Row (1,2, or 3)', '(Col (1, 2, or 3)'};
name = 'Player X Turn';
%Show prompt to input values
playerInput = inputdlg(prompt, name);
pXInputRow = str2num(playerInput{2});
pXInputCol = str2num(playerInput{1});
tttArray(pXInputRow, pXInputCol) = 1;
end
And then use the below function to see if the spot is taken.
function [spotTaken] = checktaken(tttArray)
%Function used to check if spot is taken
%Setup Error Messages
errorMessage = 'This spot is taken, please choose another spot';
errorMessageTitle = 'Spot Taken';
if tttArray(pXInputRow, pXInputCol) || tttArray(pOInputRow, pOInputCol) == 1
msgbox(errorMessage, errorMessageTitle)
spotTaken = 1;
end
end
However, I keep getting the following error after I run and put a row/col in the prompt dialog box. Any Suggestions?
Not enough input arguments.
Error in checktaken (line 8)
if tttArray(pXInputRow, pXInputCol) || tttArray(pOInputRow, pOInputCol) == 1
Couple of problems.
You supplied the tttArray as an input parameter to your checkTaken function as a call argument:
function [spotTaken] = checktaken(tttArray)
but you do not appear to have supplied the row and column parameters pXInputRow, pXInputCol or pOInputRow, pOInputCol as arguments.
So those parameters are undefined when you call
if tttArray(pXInputRow, pXInputCol) || tttArray(pOInputRow, pOInputCol) == 1
You need to supply those coordinates as arguments to your checkTaken function.
You could do the brute force method
function [spotTaken] = checktaken(tttArray, pXInputRow, pXInputCol, pOInputRow, pOInputCol)
or you could do something more elegant like put the coordinates in an array.
Another problem is if you want to check if either of the array elements is equal to 1, your if statement syntax is not correct.
in effect you have
if a || b == 1
but that is probably not what you want. Se the Matlab documentation on operator precedence
Instead you probably want
if (a == 1) || (b == 1)
so you if statement should be
if (tttArray(pXInputRow, pXInputCol) ==1) || (tttArray(pOInputRow, pOInputCol) == 1)

Resources