Super Smash Brothers

Background

  • In Smash Bros, players “smash” each other until one player sustains enough damage that they get knocked out (KO).
  • The exact limit is random, but usually somewhere between 100% and 200%.

Problem

We’re going to create a simplified 2-player Super Smash (SS) game in which ** Users gets to input their names ** Each player is given a random damage limit between 100 and 200 ** Players take turns smashing each other until one player exceeds their damage limit ** On a turn, a player can choose ** a risky smash (10-40 damage) or ** a sure smash (25-30 damage) ** First player’s hits are discounted 5 to make it fair

Solution

Source.cpp

#include <ctime>
#include <iostream>
#include <string>
#include <vector>
#include "SSPlayer.h"
 
using namespace std;
 
// Constants used for printing random smash sounds
const vector<string> SOUNDS = {"AIEEE", "ZLONK","PLOP","GLIPP","SOCK","ZLORP", "ZOK", "POWEE","SPLATT","SLOSH","KAYO", "BANG", "BAM"};
const int MAX_EXCLAMATION_POINT = 5;
const int MIN_EXCLAMATION_POINT = 1;
 
// First player gets a 5 point discount since (s)he goes first
const int FIRST_PLAYER_DISCOUNT = 5;
 
// Static functions (implemented previously)
string prompt_for_name_for_player(int player_num);
string get_random_smash_sound();
void print_smash_sounds();
 
int main()
{
	// SET UP PLAYERS
	srand(time(0));
 
	string player_1_name = prompt_for_name_for_player(1);
	string player_2_name = prompt_for_name_for_player(2);
 
	// Create SSPlayer objects from names
	SSPlayer * player1 = new SSPlayer(player_1_name, FIRST_PLAYER_DISCOUNT);
	SSPlayer * player2 = new SSPlayer(player_2_name, 0);
 
	// Use pointers to keep track of who's attacking and defending
	SSPlayer * current_attacker_ptr = player1;
	SSPlayer * current_defender_ptr = player2;
 
	// EXECUTE MATCH
	// As long as the current attacker wasn't wiped out from the last smash...
	while (current_attacker_ptr->get_damage() <= current_attacker_ptr->get_damage_limit())
	{
		// State whose turn it is and prompt the player if they want a risky or a sure smash
		cout << current_attacker_ptr->get_name() << ", it's your turn to SMASH!" << endl;
		cout << "(R)isky or (S)ure smash? ";
		string input;
		getline(cin, input); // don't need to sync 'cause haven't used cin >> before
 
		// Calculate the hit damage
		double hit_damage;
		if (input == "R")
		{
			hit_damage = current_attacker_ptr->make_risky_smash();
		}
		else
		{
			hit_damage = current_attacker_ptr->make_sure_smash();
		}
 
		// Apply damage to the defender
		current_defender_ptr->suffer_hit(hit_damage);
 
		// print smash sounds...
		print_smash_sounds();
 
		// Say who hit who and for how much
		cout << current_attacker_ptr->get_name() << " SMASHED "
			<< current_defender_ptr->get_name() << " for a loss of " << hit_damage << endl;
 
		// Report the current damage counts for each player
		cout << player1->get_name() << " (" << player1->get_damage() << ") - "
			<< player2->get_name() << " (" << player2->get_damage() << ")" << endl;
 
		// switch roles
		SSPlayer * temp = current_attacker_ptr;
		current_attacker_ptr = current_defender_ptr;
		current_defender_ptr = temp;
 
		system("pause");
	}
 
	// print more smash sound for good measure
	print_smash_sounds();
 
	cout << "MATCH OVER!" << endl;
 
	// print out the full player summaries (which shows the damage limits), winner first
	cout << current_defender_ptr->to_string() << endl << endl
		<< current_attacker_ptr->to_string() << endl;
 
	// print out a congratulations for the winner
	cout << "CONGRATS, " << current_defender_ptr->get_name() << endl;
 
	system("pause");
	return 0;
}
 
/*
*/
string prompt_for_name_for_player(int player_num)
{
	cout << "Player " << player_num << " name: ";
	string player_name;
	getline(cin, player_name);
 
	return player_name;
}
 
/*
Print a line of three smash sounds to the console flanked with two lines of asterices
*/
void print_smash_sounds()
{
	cout << endl 
		<< "****************************" << endl
		<< get_random_smash_sound() << get_random_smash_sound() << get_random_smash_sound() << endl
		<< "*****************************" << endl
		<< endl;
}
 
/*
Generate a random smash sound with a random number of exclamation points
@return smash the generated smash sound
*/
string get_random_smash_sound()
{
	string sound;
 
	int rand_num = rand() % SOUNDS.size();
	sound = SOUNDS[rand_num];
 
	rand_num = rand() % (MAX_EXCLAMATION_POINT - MIN_EXCLAMATION_POINT) + MIN_EXCLAMATION_POINT;
	for (int i = 0; i < rand_num; i++)
	{
		sound += "!";
	}
 
	return sound;
}

SSPlayer.h

#include <string>
 
using namespace std;
 
#ifndef _SSPLAYER_H
#define _SSPLAYER_H
 
class SSPlayer
{
public:
	//CONSTRUCTOR
 
	/*
	Create a new player with a random damage limit between 100 and 200
	*/
	SSPlayer(string _name, double hit_discount);
 
	//MEMBER FUNCTIONS
 
	/*
	@return name of this player
	*/
	string get_name() const;
 
	/*
	@return the current damage to *this* player
	*/
	double get_damage() const;
 
	/*
	@return the damage limit at which this player dies
	*/
	double get_damage_limit() const;
 
	/*
	This function calculates a hit damage in a larger range
	Updates are made to calculate max, min, and avg hit damage
	@return a random value in a larger range
	*/
	double make_risky_smash();
 
	/*
	This function calculates a hit damage in a small range
	Updates are made to calculate max, min, and avg hit damage
	@return a random value in a smaller range
	*/
	double make_sure_smash();
 
	/*
	@param damage points that should be added to player's current damage
	*/
	void suffer_hit(double hit_damage);
 
	/*
	@return string representation that includes the player's name, damage, damage limit
	*/
	string to_string() const;
 
private:
	/*
	This function is used for make_sure_smash and make_risky_smash so as to not repeat code
	but is not accessible outside of the class
	*/
	double make_smash(double lower_range, double upper_range);
 
	// DATA MEMBERS
 
	string name;
	double hit_discount;
 
	double damage;
	double damage_limit;
	double max_match_hit;
	double min_match_hit;
 
	int total_hits; // used to calculate average hit damage
	double total_hit_damage; // used to calculate average hit damage
 
	// static means that not every object of the class will keep its own copy of the variable
	// const means that the value can't change
	// these are initialized in .cpp file
	static const double MAX_PLAYER_DAMAGE;
	static const double MIN_PLAYER_DAMAGE;
 
	static const double MAX_SURE_HIT_DAMAGE;
	static const double MIN_SURE_HIT_DAMAGE;
	static const double MAX_RISKY_HIT_DAMAGE;
	static const double MIN_RISKY_HIT_DAMAGE;
};
 
#endif

SSPlayer.cpp

#include <iomanip>
#include <sstream>
#include "SSPlayer.h"
 
// Initialize the static constants from the .h file
const double SSPlayer::MAX_PLAYER_DAMAGE = 200;
 
const double SSPlayer::MIN_PLAYER_DAMAGE = 100;
 
const double SSPlayer::MAX_SURE_HIT_DAMAGE = 30;
 
const double SSPlayer::MIN_SURE_HIT_DAMAGE = 25;
 
const double SSPlayer::MAX_RISKY_HIT_DAMAGE = 40;
 
const double SSPlayer::MIN_RISKY_HIT_DAMAGE = 10;
 
SSPlayer::SSPlayer(string _name, double _hit_discount)
{
	name = _name;
	hit_discount = _hit_discount;
 
	damage = 0;
	// randomly set the damage limit when player is created
	damage_limit = (rand() * 1.0 / RAND_MAX) * (MAX_PLAYER_DAMAGE - MIN_PLAYER_DAMAGE) + MIN_PLAYER_DAMAGE;
	max_match_hit = -1.0;
	min_match_hit = 100000;
 
	total_hits = 0;
	total_hit_damage = 0.0;
}
 
string SSPlayer::get_name() const
{
	return name;
}
 
double SSPlayer::get_damage() const
{
	return damage;
}
 
double SSPlayer::get_damage_limit() const
{
	return damage_limit;
}
 
double SSPlayer::make_risky_smash()
{
	// use private member function to avoid code duplication
	return make_smash(MAX_RISKY_HIT_DAMAGE, MIN_RISKY_HIT_DAMAGE);
}
 
double SSPlayer::make_sure_smash()
{
	// use private member function to avoid code duplication
	return make_smash(MAX_SURE_HIT_DAMAGE, MIN_SURE_HIT_DAMAGE);
}
 
void SSPlayer::suffer_hit(double hit_damage)
{
	damage += hit_damage;
}
 
string SSPlayer::to_string() const
{
	ostringstream strm;
 
	strm << fixed << setprecision(2);
 
	strm << name << endl
		<< "Damage: " << damage << "/" << damage_limit << endl
		<< "Avg hit: " << (total_hit_damage/total_hits) << endl
		<< "Max hit: " << max_match_hit << endl
		<< "Min hit: " << min_match_hit << endl;
 
	return strm.str();
}
 
double SSPlayer::make_smash(double lower_limit, double upper_limit)
{
	double smash_damage = (rand() * 1.0 / RAND_MAX) * (upper_limit - lower_limit) + lower_limit - hit_discount;
 
	// is this smash the max so far? the min? update accordingly
	if (smash_damage > max_match_hit)
	{
		max_match_hit = smash_damage;
	}
	if (smash_damage < min_match_hit)
	{
		min_match_hit = smash_damage;
	}
 
	// update tallies to calculate average hit damage at the end
	total_hits++;
	total_hit_damage += smash_damage;
 
	return smash_damage;
}
cs-142/super-smash-brothers.txt · Last modified: 2015/06/04 12:27 by cs142ta
Back to top
CC Attribution-Share Alike 4.0 International
chimeric.de = chi`s home Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0