Getting an Ace value to represent a 1 or a 11 - console-application

I'm playing with some code for a blackjack program but I'm having trouble finding a way to make the Ace be a 1 or an 11, like in real blackjack. This isn't homework. I'm just getting back into programming. Can anyone point me in the right direction?` class Program
{
static string[] playerCards = new string[11];
static string hitOrStay = "";
static int total = 0, count = 1, dealerTotal = 0;
static Random cardRandomizer = new Random();
static string name = "";
static void Main(string[] args)
{
using (SpeechSynthesizer synth = new System.Speech.Synthesis.SpeechSynthesizer())
{
Console.Title = "Blackjack";
synth.Speak("Welcome to johns Talking Blackjack Simulator. My name is Alice and I'll be your Dealer. Whom am I speaking with?");
name = Console.ReadLine();
synth.Speak("Thank You");
synth.Speak(name);
synth.Speak("lets get started.");
Console.Clear();
}
Start();
}
static void Start()
{
dealerTotal = cardRandomizer.Next(15, 22);
playerCards[0] = Deal();
playerCards[1] = Deal();
do
{
Console.WriteLine("You were dealed a " + playerCards[0] + " and a " + playerCards[1] + ". \nYour total is " + total + ".\nWould you like to hit or stay? h for hit s for stay.");
hitOrStay = Console.ReadLine().ToLower();
} while (!hitOrStay.Equals("h") && !hitOrStay.Equals("s"));
Game();
}
static void Game()
{
if (hitOrStay.Equals("h"))
{
using (SpeechSynthesizer synth = new System.Speech.Synthesis.SpeechSynthesizer())
{
synth.Speak(name + "takes a card");
}
Hit();
}
else if (hitOrStay.Equals("s"))
{
if (total > dealerTotal && total <= 21)
{
Console.WriteLine("\nCongrats! You won the game! The dealer's total was " + dealerTotal + ".\nWould you like to play again? y/n");
using (SpeechSynthesizer synth = new System.Speech.Synthesis.SpeechSynthesizer())
{
synth.Speak("Congratulations! You Win!");
}
PlayAgain();
}
else if (total < dealerTotal)
{
Console.WriteLine("\nSorry, you lost! The dealer's total was " + dealerTotal + ".\nWould you like to play again? y/n");
using (SpeechSynthesizer synth = new System.Speech.Synthesis.SpeechSynthesizer())
{
synth.Speak("Sorry, you lost! Maybe you should try the slot machines?");
}
PlayAgain();
}
}
Console.ReadLine();
}
static string Deal()
{
string Card = "";
int cards = cardRandomizer.Next(1, 14);
switch (cards)
{
case 1: Card = "Two"; total += 2;
break;
case 2: Card = "Three"; total += 3;
break;
case 3: Card = "Four"; total += 4;
break;
case 4: Card = "Five"; total += 5;
break;
case 5: Card = "Six"; total += 6;
break;
case 6: Card = "Seven"; total += 7;
break;
case 7: Card = "Eight"; total += 8;
break;
case 8: Card = "Nine"; total += 9;
break;
case 9: Card = "Ten"; total += 10;
break;
case 10: Card = "Jack"; total += 10;
break;
case 11: Card = "Queen"; total += 10;
break;
case 12: Card = "King"; total += 10;
break;
case 13: Card = "Ace"; total += 11;
break;
default: Card = "2"; total += 2;
break;
}
return Card;
}
static void Hit()
{
count += 1;
playerCards[count] = Deal();
Console.WriteLine("\nYou were dealed a(n) " + playerCards[count] + ".\nYour new total is " + total + ".");
if (total == 21)
{
Console.WriteLine("\nYou got Blackjack! The dealer's total was " + dealerTotal + ".\nWould you like to play again?");
using (SpeechSynthesizer synth = new System.Speech.Synthesis.SpeechSynthesizer())
{
synth.Speak("Congradulations! Blackjack!");
}
PlayAgain();
}
else if (total > 21)
{
Console.WriteLine("\nYou busted. Sorry. The dealer's total was " + dealerTotal + ".\nWould you like to play again? y/n");
using (SpeechSynthesizer synth = new System.Speech.Synthesis.SpeechSynthesizer())
{
synth.Speak("Ouch! Busted! Try your luck again?");
}
PlayAgain();
}
else if (total < 21)
{
do
{
using (SpeechSynthesizer synth = new System.Speech.Synthesis.SpeechSynthesizer())
{
synth.Speak("Would you like a card?");
}
Console.WriteLine("\nWould you like to hit or stay? h for hit s for stay");
hitOrStay = Console.ReadLine().ToLower();
} while (!hitOrStay.Equals("h") && !hitOrStay.Equals("s"));
Game();
}
}
static void PlayAgain()
{
string playAgain = "";
do
{
playAgain = Console.ReadLine().ToLower();
} while (!playAgain.Equals("y") && !playAgain.Equals("n"));
if (playAgain.Equals("y"))
{
Console.WriteLine("\nPress enter to restart the game!");
Console.ReadLine();
Console.Clear();
dealerTotal = 0;
count = 1;
total = 0;
Start();
}
else if (playAgain.Equals("n"))
{
using (SpeechSynthesizer synth = new System.Speech.Synthesis.SpeechSynthesizer())
{
synth.Speak("\nPress enter to close Black jack." + dealerTotal);
}
ConsoleKeyInfo info = Console.ReadKey();
if (info.Key == ConsoleKey.Enter)
{
Environment.Exit(0);
}
else
{
Console.Read();
Environment.Exit(0);
}
}
}
}
}
changed some of the code to this but still problems
else if (total > 21)
{
if (playerCards[0] == "Ace")
{
total -= 10;
}
if (playerCards[1] == "Ace")
{
total -= 10;
}
do
{
using (SpeechSynthesizer synth = new System.Speech.Synthesis.SpeechSynthesizer())
{
synth.Speak("Would you like a card?");
}
Console.WriteLine("\nWould you like to hit or stay? h for hit s for stay");
hitOrStay = Console.ReadLine().ToLower();
if (total > 21)
Console.WriteLine("\nYou busted. Sorry. The dealer's total was " + dealerTotal + ".\nWould you like to play again? y/n");
using (SpeechSynthesizer synth = new System.Speech.Synthesis.SpeechSynthesizer())
{
synth.Speak("Ouch! Busted! Try your luck again?");
}
PlayAgain();

Seems like a clean solution would be to calculate all possible totals for a given set of cards, then choose the one that's appropriate for each user action, if needed. For example, if a user stays, then 9-A would be 20, not 10. If the user hits to arrive at 9-A-A, and then stays, it would be 21, not 11 or 30.
Here's some pseudocode for one game:
Deal out cards; show both of the player's cards and one of the dealer's cards
Determine all possible scores for player's cards
If (One of the scores is 21)
Goto Dealer's Turn (this is a blackjack)
Else
While (Hitting)
Add one card to player's hand
Determine all possible scores for player's cards
If minimum score > 21
Goto Dealer's Turn (this is a bust)
End If
End While
End If
Dealer's Turn
Determine highest score for player that's 21 or lower
Play Out Dealer's Hand
Determine Winner

Related

Why is my vector initialisation making all objects in my array the same?

I'm working on a program to aid me in world-building that randomly generates a settlement (hamlet, village, town, city) based on a nation (German, Latin, Eastern) that the user chooses. I've integrated a sort of settler generation system to create settlers within the settlement, each with a name, age, gender, and wealth using a constructor and holding the results as objects within a vector. Unfortunately, the program creates an entire population of clones, filling the vector with settlers with the same name, age, etc.
I've tried initialising the Settler class' constructor in a for loop, but that hasn't changed anything except causing you to get a different set of settlers each time you request information on one of them.
Settler Constructor:
class Settler {
public:
int settlerAge;
string settlerName;
string settlerGender;
string settlerWealth;
Settler(int type, int nation, int quantity) {
int result{};
string givenName{};
string surName{};
// Latin Male First Name
string latinMaleName[15] = {"Faustus", "Mamercus", "Mettius", "Appius", "Hostus", "Quintus", "Cossus", "Secundus", "Servius", "Gallio", "Tettienus", "Petronius", "Paesentius", "Pescunnius", "Clodius"};
// Latin Surname
string latinSurname[30] = {"Natalinus", "Lucilianus", "Crispian", "Laetinianus", "Falco", "Otho", "Plautius", "Pascentius", "Lepidus", "Moderatus", "Caeparius", "Caetronius", "Hostilius", "Aedinius", "Papius", "Gennadia", "Triaria", "Planta","Amantia", "Mico", "Opilio", "Augusta", "Laevina", "Longina", "Mico", "Servana", "Sicula", "Iovina", "Albana", "Concessa"};
// Latin Female First Name
string latinFemaleName[15] = {"Vorenia", "Tuccia", "Consentia", "Vinicia", "Aurelia", "Helvia", "Fabia", "Aemilia", "Petilia", "Cloelia", "Viducia", "Betiliena", "Sornatia", "Memmia", "Pedia"};
// As above, so below...
string germanMaleName[15] = {"Carsten", "Benedikt", "Emmerich", "Tillmann", "Maik", "Severin", "Adrian", "Gregor", "Ingolf", "Germund", "Adelmar", "Eckard", "Raimund", "Marwin", "Dietmar"};
string germanSurname[30] = {"Loeb", "Spielberg", "Lindemann", "Frenz", "Buxbaum", "Macher", "Bacharach", "Homrighausen", "Faulhaber", "Herder", "Germar", "Eisen", "Hackl", "Specht", "Rossmann", "Erdmann", "Osterhaus", "Steinsaltz", "Spiegelmann", "Lindemann", "Kluckhohn", "Kuttner", "Seelmann", "Sattler", "Kautner", "Dunhaupt", "Scharf", "Preisner", "Werthner", "Breitner"};
string germanFemaleName[15] = {"Selina", "Isabel", "Walburg", "Berta", "Kate", "Gisela", "Amelie", "Ronja", "Karin", "Lena", "Alexandra", "Sarah", "Monica", "Kai", "Nadja"};
// NOTE: Surname is before given name in eastern nations
string easternMaleName[15] = {"Nikki", "Moronobu", "Yaichiro", "Shuncho", "Tamasaburo", "Sekien", "Kazutoshi", "Yasuhide", "Omezo", "Kinzo", "Junji", "Utamuro", "Hisaki", "Taki", "Mitsuo"};
string easternSurname[30] = {"Maki", "Shinohara", "Tsukino", "Ikeda", "Matsutoya", "Sakata", "Horiuchi", "Suda", "Tsuga", "Kawano", "Kanbayashi", "Kirigaya", "Sakimoto", "Urushido", "Inaba", "Tsukiyomi", "Saeki", "Soga", "Morioka", "Yamabe", "Nakajima", "Maruyama", "Suga", "Kamino", "Kawamoto", "Takanashi", "Ito", "Kuramoto", "Maeda", "Kanemaru"};
string easternFemaleName[15] = {"Saito", "Ane", "Fuuko", "Taji", "Isoko", "Gen", "Kuwa", "Taira", "Sachi", "Uka", "Ryoko", "Hina", "Mitsu", "Asa", "Tomie"};
// Gender Generation (Male/Female)
result = (1 + (rand() % 2));
if (result > 1) {
settlerGender = "female";
} else {
settlerGender = "male";
}
// Name and Age Generation (See Arrays)
result = (rand() % 15);
switch(nation) {
case 1: // Latin (Equal split of ages)
if (settlerGender == "male") {
givenName = latinMaleName[result];
} else {
givenName = latinFemaleName[result];
}
result = (1 + (rand() % 100));
if (result >= 66) {
settlerAge = (41 + (rand() % 30));
} else if (result > 33 || result < 66) {
settlerAge = (22 + (rand() % 41));
} else {
settlerAge = (1 + (rand() % 22));
}
result = (rand() % 30);
surName = latinSurname[result];
settlerName = givenName + " " + surName;
break;
case 2: // German (More young people)
if (settlerGender == "male") {
givenName = germanMaleName[result];
} else {
givenName = germanFemaleName[result];
}
result = (1 + (rand() % 100));
if (result >= 90) {
settlerAge = (41 + (rand() % 30));
} else if (result > 40 || result < 90) {
settlerAge = (22 + (rand() % 41));
} else {
settlerAge = (1 + (rand() % 22));
}
result = (rand() % 30);
surName = germanSurname[result];
settlerName = givenName + " " + surName;
break;
case 3: // Eastern (More older people)
if (settlerGender == "male") {
givenName = easternMaleName[result];
} else {
givenName = easternFemaleName[result];
}
result = (1 + (rand() % 100));
if (result >= 40) {
settlerAge = (41 + (rand() % 30));
} else if (result > 20 || result < 40) {
settlerAge = (22 + (rand() % 41));
} else {
settlerAge = (1 + (rand() % 22));
}
result = (rand() % 30);
surName = easternSurname[result];
settlerName = surName + " " + givenName;
break;
}
// Wealth Generation (Poor/Decent/Rich: Based on Surname)
switch(type){
case 1: // Hamlet
if (result >= 28) {
settlerWealth = "Rich";
} else if (result > 24 || result < 28) {
settlerWealth = "Decent";
} else {
settlerWealth = "Poor";
}
break;
case 2: // Village
if (result >= 26) {
settlerWealth = "Rich";
} else if (result > 19 || result < 26) {
settlerWealth = "Decent";
} else {
settlerWealth = "Poor";
}
break;
case 3: // Town
if (result >= 25) {
settlerWealth = "Rich";
} else if (result > 9 || result < 25) {
settlerWealth = "Decent";
} else {
settlerWealth = "Poor";
}
break;
case 4: // City
if (result >= 20) {
settlerWealth = "Rich";
} else if (result > 9 || result < 20) {
settlerWealth = "Decent";
} else {
settlerWealth = "Poor";
}
break;
}
}
};
Vector Initialisation and Output:
Settlement objSettlement(tempType,tempNation);
int tempNum = objSettlement.settlementQuantity;
std::vector<Settler> objSettler(objSettlement.settlementQuantity, Settler(tempType, tempNation, tempNum));
cout << "Welcome to the " << objSettlement.settlementType << " " << objSettlement.settlementName << " in the " << objSettlement.settlementNation << " nation!\n";
cout << "Featuring a population of " << objSettlement.settlementQuantity << " with " << objSettlement.settlementWealth << " wealth.\n\n";
bool repeat = true;
while (repeat == true) {
cout << "Enter the ID of a settler you would like to read about (from 0-" << (objSettlement.settlementQuantity - 1) << ", or enter 999999 to exit): ";
cin >> tempNum;
cout << "\n\n";
if (tempNum == 999999) {
repeat = false;
} else {
cout << objSettler[tempNum].settlerName << ", " << objSettler[tempNum].settlerGender << ", is " << objSettler[tempNum].settlerAge << " years old and has " << objSettler[tempNum].settlerWealth << " wealth.\n\n";
}
}
For context, "objSettlement" refers to a randomly generated Settlement instance and ".settlementQuantity" is an integer representing the settlement's population.
So, when I create a latin hamlet with 30 people, the program creates a vector with 30 cases of: "Faustus Crispian, male, is 41 years old and has Poor wealth." regardless of what number I put in from 0-29.
Why is my vector initialisation making all objects in my array the same?
This :
std::vector<Settler> objSettler(objSettlement.settlementQuantity, Settler(tempType, tempNation, tempNum));
creates a vector with objSettlement.settlementQuantity copies of the same object Settler(tempType, tempNation, tempNum).
Refer to this reference page for details on how the various vector constructors work.
Something like this might be closer to what you want :
std::vector<Settler> objSettler;
for (int i = 0; i < objSettlement.settlementQuantity; ++i) {
objSettler.emplace_back(tempType, tempNation, tempNum);
}
When you create your objSettler vector, you create one Settler randomly, which will get copied objSettlement.settlementQuantity times. In other words, your constructor is called only once and the instances in the vector are created from that one settler object using the default copy constructor.
See std::vector
For generating n random settlers, you might want to use std::generate_n and std::back_inserter:
std::vector<Settler> objSettler;
std::generate_n(std::back_inserter(objSettler),
objSettlement.settlementQuantity,
[&](){ return Settler(tempType, tempNation, tempNum); });

Why doesn't the Player.x and Player.y variables change?

Edit #2: Ok, I did another *.cpp to check if the codes for Arrow Keys were right. Doing that, I noticed keyPressed variable in detectKeyPressing() had the wrong type of variable, so I changed it from char to int and changed the codes.
Once I did that, it worked. Now I have put the limits, so the Player cannot go outside the square. But I have another problem, the movement is too tough and if you press the keys too fast, the instructions run with a annoying delay. I know I should use either Sleep(ms) or Delay(ms), but I don't know when I should use it.
This is the new code:
#include <iostream>
#include <cmath>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#include <Windows.h>
using namespace std;
int detectKeyPressing() {
// 0: Escape
// 1: Enter
//2: Up
// 3: Left
// 4: Down
// 5: Right
int keyPressed = 0;
while (keyPressed != 27) {
if (keyPressed == 0 || keyPressed == 224) {
keyPressed = _getch(); //First value of _getch() when any of the arrow keys are pressed is "224", the next one is the code depending of which arrow you pressed
}
else if (keyPressed == 13) {
return 1;
}
else {
switch (keyPressed) {
//Up
case 72:
return 2;
break;
//Left
case 75:
return 3;
break;
//Down
case 80:
return 4;
break;
//Right
case 77:
return 5;
break;
//Default
default:
return -1;
break;
}
}
};
return 0;
};
int mainMenu() {
int enterPressed = 0;
cout << "Press Enter to Begin, or ESC to exit" << endl;
enterPressed = detectKeyPressing();
system("cls");
return enterPressed;
};
void draw(int playerX, int playerY) {
//Player coordinates, made for testing
cout << "Player.x = " << playerX << endl << "Player.y = " << playerY << endl;
//The next 8 spaces go blank
for (int i = 1; i < 8; i++) {
cout << endl;
}
//Square Limit Making
//Top Limit
for (int iw = 1; iw < 80; iw++) {
cout << "-";
}
cout << endl;
//Border limits and inside the Square
for (int ih = 1; ih < 30; ih++) {
//Left border
cout << "|";
//Inside the Square
for (int iw = 1; iw < 78; iw++) {
if (iw == playerX && ih == playerY) {
cout << "a"; //This is supposed to be ♥ but I don't know how to put it in the screen with a cout
}
else {
cout << " ";
}
}
//Right border
cout << "|" << endl;
}
//Bottom limit
for (int iw = 1; iw < 80; iw++) {
cout << "-";
}
}
int main() {
//Hide cursor
HANDLE hCon;
hCon = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cci;
cci.dwSize = 1;
cci.bVisible = FALSE;
SetConsoleCursorInfo(hCon, &cci);
//Variable Making
int gameStarted = -1; // 1 if game is running, 0 if not
//int t = 0; //Turn Counter, not useful for now
Sleep(200); //Wait to get a new seed
srand(time(NULL)); //Seed for rand()
//Menu Loop, remember, 1 if game starts running, 0 if you exit
while (gameStarted > 1 || gameStarted < 0) {
gameStarted = mainMenu();
}
//Like Void Start() in Unity
if (gameStarted == 1) {
int pressedKey = -1; //Creating pressedKey at Start
class Player {
public:
int life = 20;
int accuracy = 80 + (rand() % 100) / 20;
int damage = 5 + (accuracy / 10) + (rand() % 100) / 50;
bool isAlive = true;
int x = 39;
int y = 24;
int speed = 1;
};
class Enemy {
public:
int life = 100;
int satisfaction = 0;
bool isAlive = true;
bool isSatisfied = false;
int damage = 2 + (rand() % 100) / 20;
};
Player Player;
Enemy Enemy;
draw(Player.x, Player.y);
//Like Void Update() in Unity
while (gameStarted != 0) {
pressedKey = detectKeyPressing(); // Save detectKeyPressing()'s return in pressedKey
//Draw if proyectile is moving - not yet
//Draw if player is moving (pay attention specially to this part)
if (pressedKey == 0) {
gameStarted = 0; //if ESC is pressed, exit the loop and exits
}
//If any of the Arrow Keys are pressed
else if (pressedKey > 1 && pressedKey < 6) {
switch (pressedKey) {
//Up
case 2:
Sleep(200);
if (Player.y == Player.speed) {
Player.y = Player.speed; //Top Limit
}
else {
Player.y -= Player.speed;
}
break;
//Left
case 3:
Sleep(200);
if (Player.x == Player.speed) {
Player.x = Player.speed; //Left Limit
}
else {
Player.x -= Player.speed;
}
break;
//Down
case 4:
Sleep(200);
if (Player.y == 30 - Player.speed) {
Player.y = 30 - Player.speed; //Bottom Limit
}
else {
Player.y += Player.speed;
}
break;
//Right
case 5:
Sleep(200);
if (Player.x == 78 - Player.speed) {
Player.x = 78 - Player.speed; //Right Limit
}
else {
Player.x += Player.speed;
}
break;
};
system("cls"); //Erase all
draw(Player.x, Player.y); //Redraw everything, with Player.x or Player.y modified
};
};
};
return 0;
};
Edit #1: I fixed the mistakes you told me, here's the main function modified. It isn't working though.
int main(){
//Hide cursor
HANDLE hCon;
hCon = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cci;
cci.dwSize = 50;
cci.bVisible = FALSE; //Changed "TRUE" to "FALSE"
SetConsoleCursorInfo(hCon, &cci);
//Variable Making
int gameStarted = -1; // 1 if game is running, 0 if not
//int t = 0; //Turn Counter, not useful for now
Sleep(200); //Wait to get a new seed
srand(time(NULL)); //Seed for rand()
//Menu Loop, remember, 1 if game starts running, 0 if you exit
while (gameStarted > 1 || gameStarted < 0) {
gameStarted = mainMenu();
}
//Like Void Start() in Unity
if (gameStarted == 1) {
int pressedKey = -1; //Creating pressedKey at Start
class Player {
public:
int life = 20;
int accuracy = 80 + (rand() % 100) / 20;
int damage = 5 + (accuracy / 10) + (rand() % 100) / 50;
bool isAlive = true;
int x = 39;
int y = 24;
int speed = 2;
};
class Enemy {
public:
int life = 100;
int satisfaction = 0;
bool isAlive = true;
bool isSatisfied = false;
int damage = 2 + (rand() % 100) / 20;
};
Player Player;
Enemy Enemy;
draw(Player.x, Player.y);
//Like Void Update() in Unity
while (gameStarted != 0) {
pressedKey = detectKeyPressing(); //Save detectKeyPressing()'s return in pressedKey
//Draw if proyectile is moving - not yet
//Draw if player is moving (pay attention specially to this part)
if (pressedKey == 0) {
gameStarted = 0; //if ESC is pressed, exit the loop and exits
}
//If any of the Arrow Keys are pressed
else if (pressedKey > 1 && pressedKey < 6) {
cout << "There's no problem in Else If statement"; //Couts made for testing
switch (pressedKey) {
cout << "There's no problem in Switch statement";
//Up
case 2:
Player.y -= Player.speed;
cout << "You moved Up";
break;
//Left
case 3:
Player.x -= Player.speed; //Fixed Left movement
cout << "You moved Left";
break;
//Down
case 4:
Player.y += Player.speed;
cout << "You moved Down";
break;
//Right
case 5:
Player.x += Player.speed;
cout << "You moved Right";
break;
};
//system("cls"); //Erase all
//draw(Player.x, Player.y); //Redraw everything, with Player.x and Player.y supposedly modified
};
};
};
return 0;
};
Initial Post: I'm trying to do something like an Undertale normal fight and now I'm doing the "dodging attacks" part, but I'm stuck at making the player move (Yep, that "a") because it didn't update when I press an arrow key (for movement). It is supposed to draw, and put the Player in Player.x and Player.y, so I did something in main() to edit these variables depending on the arrow key you pressed, and then erase and re-draw with the Player.x or Player.y modified.
Here's the code:
#include <iostream>
#include <cmath>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#include <Windows.h>
using namespace std;
int detectKeyPressing(){
// 0: Escape
// 1: Enter
// 2: Up
// 3: Left
// 4: Down
// 5: Right
char keyPressed = 0;
while (keyPressed != 27){
if(keyPressed == 0){
keyPressed = _getch();
}
else if(keyPressed == 13){
return 1;
}
else{
switch (keyPressed) {
//Up
case 65:
return 2;
break;
//Left
case 68:
return 3;
break;
//Down
case 66:
return 4;
break;
//Right
case 67:
return 5;
break;
//Default
default:
return -1;
break;
}
}
};
return 0;
};
int mainMenu(){
int enterPressed = 0;
cout << "Press Enter to Begin, or ESC to exit" << endl;
enterPressed = detectKeyPressing();
system("cls");
return enterPressed;
};
void draw(int playerX, int playerY) {
//Player coordinates, made for testing
cout << "Player.x = " << playerX << endl << "Player.y = " << playerY << endl;
//The next 8 spaces go blank
for (int i = 1; i < 8; i++) {
cout << endl;
}
//Square Limit Making
//Top Limit
for (int iw = 1; iw < 80; iw++) {
cout << "-";
}
cout << endl;
//Border limits and inside the Square
for (int ih = 1; ih < 30; ih++) {
//Left border
cout << "|";
//Inside the Square
for (int iw = 1; iw < 78; iw++) {
if (iw == playerX && ih == playerY){
cout << "a"; //This is supposed to be ♥ but I don't know how to put it in the screen with a cout
}
else {
cout << " ";
}
}
//Right border
cout << "|" << endl;
}
//Bottom limit
for (int iw = 1; iw < 80; iw++) {
cout << "-";
}
}
int main(){
//Hide cursor
HANDLE hCon;
hCon = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cci;
cci.dwSize = 50;
cci.bVisible = TRUE;
SetConsoleCursorInfo(hCon, &cci);
//Variable Making
int gameStarted = -1; // 1 if game is running, 0 if not
//int t = 0; //Turn Counter, not useful for now
Sleep(200); //Wait to get a new seed
srand(time(NULL)); //Seed for rand()
//Menu Loop, remember, 1 if game starts running, 0 if you exit
while (gameStarted > 1 || gameStarted < 0) {
gameStarted = mainMenu();
}
//Like Void Start() in Unity
if (gameStarted == 1) {
class Player {
public:
int life = 20;
int accuracy = 80 + (rand() % 100) / 20;
int damage = 5 + (accuracy / 10) + (rand() % 100) / 50;
bool isAlive = true;
int x = 39;
int y = 24;
int speed = 2;
};
class Enemy {
public:
int life = 100;
int satisfaction = 0;
bool isAlive = true;
bool isSatisfied = false;
int damage = 2 + (rand() % 100) / 20;
};
Player Player;
Enemy Enemy;
draw(Player.x, Player.y);
//Like Void Update() in Unity
while (gameStarted != 0) {
//Draw if proyectile is moving - not yet
//Draw if player is moving (pay attention specially to this part)
if (detectKeyPressing() == 0) {
gameStarted = 0; //if ESC is pressed, exit the loop and exits
}
//If any of the Arrow Keys are pressed
else if (detectKeyPressing() > 1 && detectKeyPressing() < 6) {
switch (detectKeyPressing()) {
//Up
case 2:
Player.y -= Player.speed;
break;
//Left
case 3:
Player.x += Player.speed;
break;
//Down
case 4:
Player.y += Player.speed;
break;
//Right
case 5:
Player.x += Player.speed;
break;
};
system("cls"); //Erase all
draw(Player.x, Player.y); //Redraw everything, with Player.x and Player.y supposedly modified
};
};
};
return 0;
};
I did a few tests and it seems that the else if in "//If any of the Arrow Keys is Pressed" part isn't running but I don't know why.
I would really appreciate any help you can provide. Sorry if anything isn't well written, I'm not a native english speaker.
Where you have this comment
//Draw if proyectile is moving - not yet add a variable to save your pressed key, something like
int pressedKey = detectKeyPressing();
Then, use that variable to check which condition is met within your if-else.
What’s happening is that you’re calling your function, thus asking/waiting for an input each time a condition is being checked.

Snake in C++ won't turn twice in a row

I've just recently started to learn C++. I decided to program a little Snake game that runs in the console. It is relatively simple and doesn't look amazing, but it does it's thing as it's supposed to.The only issue I am having, is that my Snake won't turn twice in a row. In other words you can't do tight U-turns with it. It will however turn immediately after pressing the button. (Unless you just turned that is).
My code is 120 lines long so here it is:
First my includes and namespace:
#include <iostream>
#include <vector>
#include <conio.h>
#include <windows.h>
#include <random>
using namespace std;
This function draws the whole field in the console:
void drawGrid(vector<vector<char>> &g, int height, int width, int score, int time)
{
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), { 0,0 });
for (int r = 0; r < height; r++)
{
for (int c = 0; c < width; c++) std::cout << g[c][r] << " ";
std::cout << '|' << endl;
}
std::cout << "Current score: " << score << " ";
std::cout << "\nCurrent speed: " << time << " ";
}
This function checks whether the food is under the snake:
bool foodSnake(vector<int> &f, vector<vector<int>> &t, int l)
{
for (int i = 0; i < l; i++)
if (f[0] == t[i][0] && f[1] == t[i][1]) return true;
return false;
}
And this is the big poobah:
int main(void)
{
int sleeptime = 1000; // how long the break is between each frame
bool foodExists = 0;
int width = 20; //width and height of the field
int height = 15;
mt19937_64 engine; //random distributions for food generation
uniform_int_distribution<int> heightDist(0, height - 1);
uniform_int_distribution<int> widthDist(0, width - 1);
int tailLengthstart = 4;
int tailLength = tailLengthstart;
char movementDirection = 'u'; //starts moving upwards
char input;
bool alive = 1; //keeps the program running on death = 0
vector<int> pos = { (width - 1) / 2,(height - 1) / 2 }; //starts in the middle of field
vector<int> foodPos = pos; // so that the food generates at the beginning
vector<vector<int>> tail(tailLength, pos);
vector<vector<char>> emptyGrid(width, vector<char>(height, ' '));
vector<vector<char>> grid = emptyGrid;
while (alive) //runs main program until alive == 0
{
grid = emptyGrid; // clear grid
grid[pos[0]][pos[1]] = 'Q'; //place head in grid
if (!foodExists) //generates food if it was eaten
{
while (foodSnake(foodPos, tail, tailLength) || foodPos == pos)
{ // keeps regenerating until it isn't under the snake
foodPos[0] = widthDist(engine);
foodPos[1] = heightDist(engine);
}
foodExists = 1;
}
grid[foodPos[0]][foodPos[1]] = 'X'; //place food in grid
for (int i = 0; i < tailLength; i++) grid[tail[i][0]][tail[i][1]] = 'O'; // place tail in grid
drawGrid(grid, height, width, tailLength - tailLengthstart, sleeptime); //call above function to draw the grid
input = '_';
Sleep(sleeptime);
if (_kbhit()) { //this was the best way I found to wait for input
input = _getch();
switch (input)
{ //disallows moving in opposite direction otherwise changes direction
case 'w':
if (movementDirection == 'd') break;
movementDirection = 'u';
break;
case 'a':
if (movementDirection == 'r') break;
movementDirection = 'l';
break;
case 's':
if (movementDirection == 'u') break;
movementDirection = 'd';
break;
case 'd':
if (movementDirection == 'l') break;
movementDirection = 'r';
break;
case '_':
break;
}
}
for (int i = tailLength - 1; i > 0; i--)
tail[i] = tail[i - 1];
tail[0] = pos; //move the tail along
if (movementDirection == 'u') pos[1]--;
if (movementDirection == 'l') pos[0]--;
if (movementDirection == 'r') pos[0]++;
if (movementDirection == 'd') pos[1]++; // move the head
if (pos[0] < 0 || pos[0] > width - 1 || pos[1] < 0 || pos[1] > height - 1)
alive = 0; // if head is out of bounds -> dead
for (int i = 0; i < tailLength; i++)
if (pos == tail[i])
alive = 0; // if head is on tail -> dead
if (foodPos == pos)
{ // if head is on food -> eat
foodExists = 0; // food needs to be generated
tail.push_back(tail[tailLength - 1]); //tail adds a link
tailLength++; // tail is now longer
if (tailLength % 5 == 0) sleeptime *= 0.75; // at certain lengths game speeds up
}
}
this next part happens once you are dead or alive == 0
std::system("cls");
std::cout << endl << endl << endl << endl << "\tYou have died" << endl << endl << endl << endl;
std::cout << endl;
std::system("pause");
return 0;
}
So if anyone has an idea why it's not turning quickly, please help. Or any other improvement ideas are welcome as well.
The problem with movement is caused by fact that you advance tail and changing direction causes head advance immediately. That means that there is always a step before snake would actually turn.
The state set as I see it:
Setup scene.
Check key.
Change direction of movement if key pressed and it isn't opposite of current direction.
Make old head tail and add a head element in set direction from old head.
Check for death
Check for food.
If food found, grow tail by changing TailLength.
If snake length is greater than TailLength, remove tail elements until they are equal.
Render scene
Sleep and go to 2.
It is better to represent snake by a list, not by a vector. It won't reallocate memory on size change or if you will cut first elements out.
If your platform is Windows (obviously, you're using Sleep() function instead of usleep), the answer to this question offers better solution for key detection.
Get key press in windows console
Similar solutions exist for POSIX platforms.
There is a little problem that you're waiting sleeptime even the key was pressed
Sleep(sleeptime);
The main cycle may be like this pseudo code
while (IsAlive())
{
currtime = 0;
DrawState();
while (currtime++ < sleeptime)
{
if (CheckAndProcessKeyboardInput())
break;
SleepOneMilliSecond();
}
}

Confusing of "Access Violation "

I don't Understand with this case but this is really really important for me, Please Help me...
void __fastcall TForm1::Button4Click(TObject *Sender)
{
String masuk, keluar, kosong;
int i, x, j, n = 0;
masuk = Edit2->Text;
keluar = masuk;
kosong = " ";
n = 0;
x = 0;
mulai:
i = 1;
j = 0;
j = j + n;
i = i + j;
if (masuk[i] == 'a')
{
keluar[i] = 't';
}
else if (masuk[i] == 't')
{
keluar[i] = 'a';
}
else if (masuk[i] == 'c')
{
keluar[i] = 'g';
}
else if (masuk[i] == 'g')
{
keluar[i] = 'c';
}
else
{
Application->MessageBoxA("Masukan Anda Salah", "Peringatan", MB_OK | MB_ICONWARNING);
keluar = kosong;
goto end;
}
n = n + 1;
if (i < 10)
goto mulai;
else
goto end;
end:
Memo1->Text = keluar;
}
if I make masukan more than 10 (i<10 (10 as default value)), it is ok but if it less than 10, it will make message exception Class EAccessViolation..
Taking a shot in the dark, but I think what you're actually trying to do might be this. I'm assuming that you're taking a single string of 10 characters which represents one half of a genome and you're generating another string of the pair values.
void __fastcall TForm1::Button4Click(TObject *Sender)
{
String masuk, keluar;
masuk = Edit2->Text;
keluar = masuk;
char kosong = ' ';
for (int i=0; i < 10; i++)
{
switch(masuk[i]) {
case 'a':
keluar[i] = 't';
break;
case 't':
keluar[i] = 'a';
break;
case 'c':
keluar[i] = 'g';
break;
case 'g':
keluar[i] = 'c';
break;
default:
Application->MessageBoxA("Masukan Anda Salah", "Peringatan", MB_OK | MB_ICONWARNING);
keluar[i] = kosong;
break;
}
Memo1->Text = keluar;
}

Poker code cleanup modification from book...not quite right

Working through more book examples- this one is a partial poker program-
This segment deals with straight hand....
First what was given- only relevant parts....will provide entire code if needed...
int suits[5]; //index 1..4- value start at 1
int values[14]; //index 1..13- value same as rank, A = 1, K = 13
cin.get(rankCh);
switch (toUpper(rankCh)) {
case 'A': values = 1; break;
case '2': values = 2; break;
case '3': values = 3; break;
case '4': values = 4; break;
case '5': values = 5; break;
case '6': values = 6; break;
case '7': values = 7; break;
case '8': values = 8; break;
case '9': values = 9; break;
case 'T': values = 10; break;
case 'J': values = 11; break;
case 'Q': values = 12; break;
case 'K': values = 13; break;
default:
badCard = true;
}
Other functions:
bool isFlush(int suits[]) {
for(i = 1; i <= 4; i++)
if (suits[i] == 5) //5 here is Number of Cards
return true;
return false;
}
Yeah, I know about the array declarations but that is how it is defined- nice justification for it in the text...starting to number at 1
I want my straight hand to handle both Ace high and low- right now as define above aces are low...
Two versions: 1st appears not sure correct with low aces...
CODE
bool isStraight(int values[]) //Version one only straight- low aces only
{
int count = 0;
for (i = 1; i <= 13; i++) {
if (values[i] != 1) {
count++;
} else
count = 0;
if (count == 5) //5 is NUMCARDS
return true;
}
return false;
}
Now this is the where I need some recommendation: to have a function to handle both ace high and low:
bool isStraight(int values[]) //Version handles both high and low
{
int count = 0;
for (i = 1; i <= 13; i++) {
if (values[i] != 1) {
count++;
// if(i == 1 && values[1] != 0) //Check for high and low
// count++;
} else
count = 0;
if (count == 5) //5 is NUMCARDS
return true;
}
return false;
}
Would what I have in comments work to handle both ace high and low...
Since i = 1 is represented as ace and not sure what values[1] is correct should it be values[13] or what...maybe something like
if (i == 1)
values[13] //not sure...
Recommendations-
do not want wholesale changes- just to have minor changes with what I have...I do not want to sort or solve by brute force i.e like values[1] == 1 && values [2] ==1 you get the point- the text does that already but I am trying to rewrite it this way...
Thanks...Hope I am getting across my modification I would like...
EDIT: I figured I'd would first answer your question directly. Lets first clear up how the original algorithm worked. Basically it loops from 1 to 13, and each time it sees a card in that slot, it adds to count. If anything ever breaks the sequence, it resets the counter. Finally, if the counter reaches 5, you have a straight.
I can't say off hand if your solution would work, I say give it a go. However, a simple quick patch to the original would probably go something like this:
//Version handles both high and low
bool isStraight(int values[]) {
int count = 0;
for (i = 1; i <= 13; i++) {
if (values[i] != 1) {
count++;
} else
count = 0;
if (count == 5) //5 is NUMCARDS
return true;
}
// handle ace high.
if(count == 4 && values[1] != 0) {
return true;
}
return false;
}
Basically what that does is say "if we already have 4 in a row, and we've just looked at the very last card (the loop is over), then check an ace is there, if so, we do have a straight and it is ace high".
ORIGINAL ANSWER:
I think the easiest way to handle ace high and low is to have the "get rank" function have two modes, one which returns ace high, the other which returns ace low. Then just calculate the hand value for each case and take the better one.
Also, your get rank could be way simpler :-P.
int get_rank(char card) {
static const char *cards = "A23456789TJQK";
char *p = strchr(cards, toupper(card));
if(p) {
return (p - cards) + 1;
} else {
return -1;
}
}
so if you want to have a get_rank which has an ace_high or an ace_low, you could do this:
int get_rank(char card, bool ace_high) {
static const char *cards_high = "23456789TJQKA";
static const char *cards_low = "A23456789TJQK";
const char *cards = ace_high ? cards_high : cards_low;
char *p = strchr(cards, toupper(card));
if(p) {
return (p - cards) + 1;
} else {
return -1;
}
}
EDIT:
for fun, i've made a quick and dirty program which detects straights (handling both high and low ace). It is fairly simple, but could be shorter (also note that there is no attempt at buffer safety with these arrays, something of production quality should use something safer such as std::vector:
#include <algorithm>
#include <iostream>
#include <cstring>
int get_rank(char card, bool ace_high) {
static const char *cards_high = "23456789TJQKA";
static const char *cards_low = "A23456789TJQK";
const char *cards = ace_high ? cards_high : cards_low;
char *p = strchr(cards, toupper(card));
if(p) {
return (p - cards) + 1;
} else {
return -1;
}
}
bool is_rank_less_low(int card1, int card2) {
return get_rank(card1, false) < get_rank(card2, false);
}
bool is_rank_less_high(int card1, int card2) {
return get_rank(card1, true) < get_rank(card2, true);
}
bool is_straight(int hand[], bool ace_high) {
std::sort(hand, hand + 5, ace_high ? is_rank_less_high : is_rank_less_low);
int rank = get_rank(hand[0], ace_high);
for(int i = 1; i < 5; ++i) {
int new_rank = get_rank(hand[i], ace_high);
if(new_rank != rank + 1) {
return false;
}
rank = new_rank;
}
return true;
}
bool is_straight(int hand[]) {
return is_straight(hand, false) || is_straight(hand, true);
}
int main() {
int hand1[5] = { 'T', 'J', 'Q', 'K', 'A' };
int hand2[5] = { 'A', '2', '3', '4', '5' };
std::cout << is_straight(hand1) << std::endl;
std::cout << is_straight(hand2) << std::endl;
}
The case where an ace-high straight exists can be found by changing the final test:
if (count == 5 || count == 4 && values[1] == 1) // 2nd case handles ace-high straight
return true;
It's a special case, so it must be handled separately.