Lambda Question

So I know how to use a lambda to find the least accurate person in my structure.
My struct contains information on each Gunman which like their accuracy and if they are alive or not. Here is what I use to find who is the least accurate.
 
position = std::min_element( gMen , gMen + POPULATION , []( const Gunman &lhs , const Gunman &rhs ){ return( lhs.accuracy < rhs.accuracy && lhs.alive && rhs.alive ); } )->position;

I can't think of anyway to find who the second least accurate alive Gunman is. It wouldn't be bad if I could use outside variables inside the lambda then I could do != position...but you cannot does anyone have any suggestions I could do?
The reason I am doing this is because I am going to have different settings on who the Gunman should aim at and for example if they are aiming at the least accurate Gunman and it is currently the least accurate Gunman shooting I don't want him committing suicide I want him to shoot the next least accurate guy.
Say for example this
Gunman 1 accuracy 10.
Gunman 2 accuracy 20;
Gunman 3 accuracy 30;
Gunman 1 shoots at Gunman 2. Gunman 2 shoots at Gunman 1. Gunman 3 shoots at Gunman 1.

Or do you guys think that using a Lambda is a bad idea and I should make a temp vector of Gunmen then stable_sort it and then just go to the next alive Gunman?
I was told though that using a lambda is the best way to search for highest/lowest stuff like that.

Thanks,
-Giblit
Last edited on
> It wouldn't be bad if I could use outside variables inside the lambda

Lambda capture: http://software.intel.com/sites/products/documentation/studio/composer/en-us/2011Update/compiler_c/cref_cls/common/cppref_lambda_lambdacapt.htm


> I should make a temp vector of Gunmen then stable_sort it and then just go to the next alive Gunman?

Or make a std::vector< std::reference_wrapper<Gunman> > and then apply std::nth_element() on it.
http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper
http://www.cplusplus.com/reference/algorithm/nth_element/
Cool thanks did not know any of that stuff. I'll give it a try and let you know =]
What is wrong with this?
1
2
position = std::min_element( gMen , gMen + POPULATION , []( const Gunman &lhs , const Gunman &rhs ){ return( lhs.accuracy < rhs.accuracy && lhs.alive && rhs.alive ); } )->position;
        position = std::min_element( gMen , gMen + POPULATION , [ = ]( const Gunman &lhs , const Gunman &rhs ){ return( lhs.accuracy < rhs.accuracy && lhs.position != position && rhs.position != position && lhs.alive && rhs.alive ); } )->position;

It sounds correct to me but isn't giving correct results here's what I thought it was doing.
1) setting position equal to the position with the lowest accuracy && is alive.
2) setting position equal to the position with the lowest accuracy && is not equal to the least accurate position && is alive.

After typing this I am guessing it is something to do with the comparison. Is there a way to skip over a position?
ex:
shooter 1 accuracy 60
shooter 2 accuracy 50
shooter 3 accuracy 70
get the lowest
------------------
compare shooter 1 to shooter 3 //shooter 1 is lower
compare shooter 1 to shooter 2 //shooter 2 is lower
shooter 2 has the least accuracy.
-------------------
get second lowest
-----------------------
compare shooter 1 to shooter 3 //shooter 1 is lower
ignore shooter 2
no more shooters
shooter 1 is the second least accurate

Guess I can always try the std::reference_wrapper and nth_element now since I have failed with lambda


> Guess I can always try the std::reference_wrapper and nth_element now since I have failed with lambda

No, I made a stupid mistake. std::nth_element() is not relevant. Sorry about that.

1
2
3
4
5
6
7
8
9
const auto cmp1 = [position1] ( const Gunman &lhs , const Gunman &rhs )
                    { return( lhs.accuracy < rhs.accuracy && lhs.alive );  };
auto position1 = std::min_element( gMen , gMen + POPULATION , cmp1 )->position ;

// the element at position1 is not less than any other element 
const auto cmp2 = [position1,cmp1] ( const Gunman &lhs , const Gunman &rhs )
                    { return( cmp1(lhs,rhs) && lhs.position != position1 );  };

auto positoion2 = std::min_element( gMen , gMen + POPULATION , cmp2 )->position ;



1
2
3
4
std::vector< std::reference_wrapper<Gunman> > vec( gMen , gMen + POPULATION ) ;
std::std::sort( vec.begin(), vec.end(), cmp1 ) ;
auto position1 = vec[0].position ;
auto position2 = vec[1].position ; 
Last edited on
I tried doing the lambda way that you did but that still returns the least accurate guy and not the second least.
By the way I thought things were automatically declared as auto?
Going to try the reference_wrapper way now
Thanks for the help btw =] appreciate it.
btw I don't know if this is relevant or not but the way I am getting my gunmen is like this
Gunman *gMen = new Gunman[ AMOUNTOFGUNMEN ]; //where the amount comes from an input
then I am putting gMen in my function.
Last edited on
> I tried doing the lambda way that you did but that still returns the least accurate guy and not the second least.

Did you use the cmp2 lambda for the second call?


> I am getting my gunmen is like this
> Gunman *gMen = new Gunman[ AMOUNTOFGUNMEN ]; //where the amount comes from an input

Make life simpler; use std::vector<>,.
std::vector<Gunman> gMen( AMOUNTOFGUNMEN ) ;
Last edited on
>Make life simpler; use std::vector<>,.
I actually was thinking about that a second ago

and yes I did call cmp2 I wrote it my own way similar to yours and it didn't work then I tried yours and that didn't work also I'll post up some more code.
and still trying to figure out refernce_mapper I am guessing it is some sort of function that copies a vector into another vector.

here is my code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#include <iostream>   //std::cout , std::cin , std::streamsize
#include <limits>     //std::numeric_limits
#include <cstdlib>    //rand() , srand()
#include <ctime>      //time
#include <algorithm>  //std::max_element()
#include <vector>     //std::vector<>

//Defining the Gunman Structure
struct Gunman
{
    /**Declaring new values for: *
      *Acuracy , Kills , Deaths ,*
      *Wins , KDR and Win Rate   **/
    unsigned short position ,accuracy ,
    kills , deaths , wins , killDeathRate ,
    winRatio;
    bool alive;

    /**Constructing a new gunman *
      *Also setting default value**/
    Gunman( void ) :
        position( 0 ) , accuracy( 0 ) , kills( 0 ),
        deaths( 0 ) , wins( 0 ) , killDeathRate( 0 ) ,
        winRatio( 0 ) , alive( true ) { }
};

void clearBuff( void )
{
    std::cin.clear();
    std::cin.ignore( std::numeric_limits<std::streamsize>::max() , '\n' );
}

//Defining the MainMenu
const unsigned char mainMenu( void )
{
    //Initializing invalid choice to true
    bool invalid( true );
    //initializing mode to an empty char
    unsigned char selectedMode = char();

    do
    {
        //setting invalid choice to false
        //Getting input
        invalid = false;
        std::cout << "Welcome to the shooting statistics application.\n" << std::flush;
        std::cout << "Which mode would you like?\n"
                  << "1 - Duel between two people\n"
                  << "2 - Multiple people battling\n> " << std::flush;
        std::cin  >> selectedMode;
        clearBuff();

        //invalid selection displaying message and restarting loop
        if( selectedMode != '1' && selectedMode != '2' )
        {
            std::cout << "Invalid selection please make another.\n" << std::flush;
            invalid = true;
        }
    } while( invalid );
    //returning the selected mode
    return( selectedMode );
}

//Setting options
const unsigned char settings( const unsigned int x )
{
    //setting invalid choice to true
    bool invalid( true );
    //input character and short are set to empty
    unsigned char inputChar = char();

    do
    {
        //setting to valid choice and getting input
        invalid = false;
        switch( x )
        {
            //Gettting the way to assign accuracies
        case 1:
            std::cout << "How would you like accuracies assigned?\n"
                      << "1 - Randomly\n"
                      << "2 - Manually\n> " << std::flush;
            std::cin  >> inputChar;
            clearBuff();
            //invalid choice
            if( inputChar != '1' && inputChar != '2' )
            {
                std::cout << "Invalid selection please make another\n" << std::flush;
                invalid = true;
            }
            break;
            //Getting the order to battle in
        case 2:
            std::cout << "Which order would you like them to shoot?\n"
                      << "1 - Descending Accuracy\n"
                      << "2 - Ascending Accuracy\n"
                      << "3 - Descending Position\n"
                      << "4 - Ascending Position\n> " << std::flush;
            std::cin  >> inputChar;
            clearBuff();
            //invalid choice
            if( inputChar != '1' && inputChar != '2' && inputChar != '3' && inputChar != '4' )
            {
                std::cout << "Invalid selection please make another\n" << std::flush;
                invalid = true;
            }
            break;
        case 3:
            std::cout << "Which order would you like them to target?\n"
                      << "1 - Most Accurate\n"
                      << "2 - Least Accurate\n"
                      << "3 - Descending Position\n"
                      << "4 - Ascending Position\n> " << std::flush;
            std::cin  >> inputChar;
            clearBuff();
            if( inputChar != '1' && inputChar != '2' && inputChar != '3' && inputChar != '4' )
            {
                std::cout << "Invalid selection please make another\n" << std::flush;
                invalid = true;
            }
        }
    } while( invalid );
    //returning the settings
    return( inputChar );
}

//setting up the stats for the gunman
void stats( std::vector<Gunman> &gMen , const unsigned short POPULATION , const unsigned short METHOD )
{
    //setting input to an invalid choice , and the iterator to 0
    unsigned short inputShort( 101 ) , i( 0 );
    switch( METHOD )
    {
        //Assigning Random Accuracies
    case 1:
        for( i = 0; i < POPULATION; ++i )
        {
            //assigning accuracy
            gMen[ i ].accuracy = rand() % 100 + 1;
        }
        break;

        //Assigning Manual Accuracies
    case 2:
        for( i = 0; i < POPULATION; ++i )
        {
            do
            {
                std::cout << "Please enter the accuracy for Gunman " << i + 1 << "<1-100>\n> " << std::flush;
                std::cin  >> inputShort;
                clearBuff();
                //invalid
                if( inputShort > 100 )
                {
                    std::cout << "Invalid selection please make another\n" << std::flush;
                }
            } while( inputShort < 1 || inputShort > 100 );
            //assigning accuracy
            gMen[ i ].accuracy = inputShort;
        }
        break;
    //assigning position
    case 3:
        for( i = 0; i < POPULATION; ++i )
        {
            gMen[ i ].position = i;
        }
        break;

    }
}
void positionGunmen( std::vector<Gunman> &gMen , const unsigned short SHOOTORDER )
{
    switch( SHOOTORDER )
    {
    case 1: //Descending Accuracy
        std::stable_sort( gMen.begin() , gMen.end() , []( const Gunman &lhs , const Gunman &rhs ) { return( lhs.accuracy > rhs.accuracy ); } );
        break;
    case 2: //Ascending Accuacy
        std::stable_sort( gMen.begin() , gMen.end() , []( const Gunman &lhs , const Gunman &rhs ) { return( lhs.accuracy < rhs.accuracy ); } );
        break;
    case 3: //Descending Position
        std::stable_sort( gMen.begin() , gMen.end() , []( const Gunman &lhs , const Gunman &rhs ) { return( lhs.position > rhs.position ); } );
        break;
    case 4: //Ascending Position
        //its already like this by default
        break;
    }
}
const unsigned short targetFunction( const unsigned short TARGET , const std::vector<Gunman> gMen )
{
    unsigned short position = 0;
    const auto cmp1 = []( const Gunman &lhs , const Gunman &rhs ){ return( lhs.accuracy < rhs.accuracy && lhs.alive && rhs.alive ); };
    const auto cmp2 = [ position , cmp1 ]( const Gunman &lhs , const Gunman &rhs ){ return( cmp1( lhs , rhs ) && lhs.position != position && rhs.position != position ); };


    switch( TARGET )
    {
    case 1: //least accurate
        position = std::min_element( gMen.begin() , gMen.end() , cmp1 )->position;
        break;
    case 2: //most Accurate
        position = std::max_element( gMen.begin() , gMen.end() , []( const Gunman &lhs , const Gunman &rhs ){ return( lhs.accuracy < rhs.accuracy && lhs.alive && rhs.alive ); } )->position;
        break;
    case 3:
        //second least
        position = std::min_element( gMen.begin() , gMen.end() , cmp1 )->position;
        position = std::min_element( gMen.begin() , gMen.end() , cmp2 )->position;

    }
    return( position );
}
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
//starting the battle
void battle( /*Gunman *gMen*/ std::vector<Gunman> gMen , const unsigned short SHOOTORDER , const unsigned short TARGETORDER , const unsigned short POPULATION )
{
    //they all start alive.
    //Setting Default gunman to the first
    //Setting Default target to the last
    unsigned short alive = POPULATION ,
    firstAlive = 0 , currentGunman = 0 ,
    target =  POPULATION - 1;

    while( alive > 1 )
        {
           // std::cout << currentGunman << std::endl;
            while( !gMen[ currentGunman ].alive )
            {
                ++currentGunman;
                if( currentGunman > target )
                {
                    currentGunman = firstAlive;
                }
            }


            //if( currentGunman == target )
           // {
               // std::cout << "Gunman " << gMen[ currentGunman ].position + 1 << " shooting at " << gMen[ firstAlive ].position + 1 << std::endl;
           // } else {
               // std::cout << "Gunman " << gMen[ currentGunman ].position + 1 << " shooting at " << gMen[ target ].position + 1 << std::endl;
           // }


            if( rand() % 100 + 1 <= gMen[ currentGunman ].accuracy )
            {
                if( currentGunman == target )
                {
                    gMen[ firstAlive ].alive = false;
                    ++gMen[ firstAlive ].deaths;
                    ++firstAlive;
                } else {
                    gMen[ target ].alive = false;
                    ++gMen[ target ].deaths;
                    --target;
                }
                ++gMen[ currentGunman ].kills;
                --alive;
            }
            ++currentGunman;
            //std::cout << currentGunman << std::endl;
        }
        //std::cout << "Selected gunman is: " << currentGunman << std::endl;
        ++gMen[ currentGunman - 1 ].wins;
        //std::cout << "Least accurate is gunman " << targetFunction( 1 , gMen , POPULATION ) << " has an accuracy of " << gMen[ targetFunction( 1, gMen , POPULATION ) ].accuracy << std::endl;
           // std::cout << "Most accurate is gunman " << targetFunction( 2 , gMen , POPULATION ) << " has an accuracy of " << gMen[ targetFunction( 2 , gMen , POPULATION ) ].accuracy << std::endl;
}

int main( int argc , char **argv )
{
    srand( ( unsigned ) time( NULL ) );
    const unsigned short DUELPOPULATION = 2;
    const unsigned char selectedMode( mainMenu() );
    unsigned short numberOfGunmen = short() , accuracyType = short() , battleOrder = 4 , targetOrder = 1;

    //Gunman *gMen = nullptr; //will change to a vector
    switch( selectedMode )
    {
        //duel
    case '1':
        //setting gunmen to 2
        numberOfGunmen = DUELPOPULATION;
        break;

        //more than 2 people battle
    case '2':
        //getting number of gunmen
        std::cout << "How many people do you want shooting?\n> " << std::flush;
        std::cin  >> numberOfGunmen;
        clearBuff();
        break;
    }

    //Adding gunmen to the world
    std::vector<Gunman> gMen( numberOfGunmen );
    //get settings/stats
    accuracyType = settings( 1 ) - '0';
    stats( gMen , numberOfGunmen , accuracyType );
    /**battleOrder  = settings( 2 ) - '0';**/
    /**targetOrder  = settings( 3 ) - '0';**/
    stats( gMen , numberOfGunmen , 3 );
    //set up the battle
    positionGunmen( gMen , battleOrder );
    const unsigned short target1 = targetFunction( 1 , gMen ) ,
    target2 = targetFunction( 2 , gMen ) ,
    target3 = targetFunction( 3 , gMen );

    std::cout << "Least accurate is gunman " << target1 << " has an accuracy of " << gMen[ target1 ].accuracy << std::endl;
    std::cout << "Second Least accurate is gunman " << target3 << " has an accuracy of " << gMen[ target3 ].accuracy << std::endl;
    std::cout << "Most accurate is gunman " << target2 << " has an accuracy of " << gMen[ target2 ].accuracy << std::endl;


    //start the battle of the titans
    //battle( gMen , battleOrder , targetOrder , numberOfGunmen );
    //for( unsigned int i = 0; i < numberOfGunmen; ++i )
    //{
      //  std::cout << "Gunman " << i + 1 << " has " << gMen[ i ].kills << " kills "
      //            << gMen[ i ].deaths << " deaths " << gMen[ i ].wins << " wins " << std::flush;
    //}

}
Welcome to the shooting statistics application.
Which mode would you like?
1 - Duel between two people
2 - Multiple people battling
> 2
How many people do you want shooting?
> 3
How would you like accuracies assigned?
1 - Randomly
2 - Manually
> 2
Please enter the accuracy for Gunman 1<1-100>
> 50
Please enter the accuracy for Gunman 2<1-100>
> 60
Please enter the accuracy for Gunman 3<1-100>
> 70
Least accurate is gunman 0 has an accuracy of 50
Second Least accurate is gunman 0 has an accuracy of 50
Most accurate is gunman 2 has an accuracy of 70

Process returned 0 (0x0)   execution time : 7.248 s
Press any key to continue.


It's not finished but right now I am just working on the targeting mode then I have to work on the battle
Thanks again for your time
Updated the code slightly using vector instead of pointer now
Last edited on
Okay I got the finding second least accuracy working here is the code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
       std::vector<Gunman> temp( gMen.begin() , gMen.end() ) ;
       std::sort( temp.begin(), temp.end(), cmp1 ) ;
       while( !temp[ count ].alive )
       {
           ++count;
       }
       position = temp[ count + 1].position;
Welcome to the shooting statistics application.
Which mode would you like?
1 - Duel between two people
2 - Multiple people battling
> 2
How many people do you want shooting?
> 4
How would you like accuracies assigned?
1 - Randomly
2 - Manually
> 1
Least accurate is gunman 3 has an accuracy of 1
Second Least accurate is gunman 2 has an accuracy of 20
Most accurate is gunman 1 has an accuracy of 79
Second Most accurate is gunman 0 has an accuracy of 72

Welcome to the shooting statistics application.
Which mode would you like?
1 - Duel between two people
2 - Multiple people battling
> 2
How many people do you want shooting?
> 4
How would you like accuracies assigned?
1 - Randomly
2 - Manually
> 1
Least accurate is gunman 0 has an accuracy of 4
Second Least accurate is gunman 3 has an accuracy of 29
Most accurate is gunman 1 has an accuracy of 97
Second Most accurate is gunman 2 has an accuracy of 95


Thanks again for your help.
Last edited on
1
2
> const auto cmp1 = []( const Gunman &lhs , const Gunman &rhs )
> { return( lhs.accuracy < rhs.accuracy && lhs.alive && rhs.alive ); };


works for std::min_element() (assuming that there are at least two gunmen who are alive),
but it is not ok for std::sort() (strict weak ordering)
(What would happen when lhs is alive, but rhs is not alive?)

This happens to work because you have added extra checks with the while loop:
1
2
3
4
5
6
7
std::vector<Gunman> temp( gMen.begin() , gMen.end() ) ;
       std::sort( temp.begin(), temp.end(), cmp1 ) ;
       while( !temp[ count ].alive )
       {
           ++count;
       }
       position = temp[ count + 1].position;

Technically, std::sort( temp.begin(), temp.end(), cmp1 ) ; leads to undefined behaviour.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
 
struct gunman
{
   int accuracy ;
   bool alive ;
   int position ;
};
 
std::ostream& operator<< ( std::ostream& stm, const gunman& g )
{
    return stm << "{ " << "accuracy:" << g.accuracy << ", position:" << g.position
               << ", alive:" << std::boolalpha << g.alive << " }" ;
}
 
int main()
{
    std::vector<gunman> gmen { {7,true,0}, {0,false,1}, {3,true,2}, {5,true,3},
                                {2,false,4}, {4,true,5}, {0,false,6}, {7,true,7} } ;
    for( const auto& g : gmen ) std::cout << g << '\n' ;
    std::cout << "-----------------\n" ;
 
    const auto cmp1 = [] ( const gunman &lhs , const gunman &rhs )
    {
        if( lhs.alive && rhs.alive ) return lhs.accuracy < rhs.accuracy ;
        else return lhs.alive ;
    };
 
    auto position1 = std::min_element( gmen.begin() , gmen.end() , cmp1 )->position ;
    std::cout << "position of least accurate and alive: " <<  position1 << '\n' ;
 
    const auto cmp2 = [position1,cmp1] ( const gunman &lhs , const gunman &rhs )
                       { return cmp1(lhs,rhs) && ( lhs.position != position1 ) ;  };
    auto position2 = std::min_element( gmen.begin() , gmen.end() , cmp2 )->position ;
    std::cout << "position of second-least accurate and alive: " <<  position2 << '\n' ;
 
    std::cout << "-----------------\n" ;
 
    std::vector< std::reference_wrapper<gunman> > tvec( gmen.begin() , gmen.end() ) ;
    std::sort( tvec.begin(), tvec.end(), cmp1 ) ;
    for( const auto& g : tvec ) std::cout << g << '\n' ;
}

http://ideone.com/af6T3C
Last edited on
what the heck? I need to relook at my code...because I put almost the same exact compare functions on mine and it did not work.
1
2
3
    const auto cmp1 = []( const gunman &lhs , const gunman &rhs ){ return( lhs.accuracy < rhs.accuracy && lhs.alive && rhs.alive ); };

    const auto cmp2 = [ position1 , cmp1 ]( const gunman &lhs , const gunman &rhs ){ return( cmp1( lhs , rhs ) && lhs.position != position1 && rhs.position != position1 ); };

When I swap those out for yours on your program it does the same thing
I must of misstyped something or put cmp1 where cmp2 was meant I feel dumb now lol
And cool I was wondering how to use that reference_wrapper I was thinking it was like that where it creates a copy of the old vector.

Thanks again for all your time I appreciate it =]

JLBorges wrote:

What would happen when lhs is alive, but rhs is not alive?

Nothing should happen because wouldn't it still have the value from before it tried to get the lower value with the dead guys?
Also I had no idea you could overload like that
1
2
3
4
5
std::ostream& operator<< ( std::ostream& stm, const gunman& g )
{
    return stm << "{ " << "accuracy:" << g.accuracy << ", position:" << g.position
               << ", alive:" << std::boolalpha << g.alive << " }" ;
}
Last edited on
Topic archived. No new replies allowed.