赢得虚拟击剑比赛（针对您的堆叠交换器）

16

``````FLAVOR TEXT
``````

Bill和Steve决定进行一次“友好的”决斗，但是又如此富有和聪明，决定让他们最好的程序员尝试自己的代码，以相互竞争。你说的是程序员。

``````OBJECTIVE
``````

``````MOVES
``````

``````SCORING POINTS
``````

``````HEIGHT OF ACTION
``````

``````CODE REQUIREMENTS
``````

``````WINNER
``````

``````AGAINST OTHER PLAYERS
``````

1

NRGdallas 2012年

vsz 2012年

3

5

蟒蛇

``````from random import choice, random

def cleverly_pick_move(me_allowed,op_allowed,opp_last_move=None) :
""" Behold the genius you're up against!
Pretty much everything else is just flavour text or match rules
so you'll probably only want to read this...
"""
rand_choice = lambda a,h : {'type':choice([t for t in a if a[t]]),
'height':choice(h)}

if opp_last_move is None or feeling_like_a_lucky_punk():
return rand_choice(me_allowed,heights)

if sum(1 for x in op_allowed if op_allowed[x]) == 3 :
for i in op_allowed:
if not op_allowed[i] :
weakness = i
break
return {'type':exploit_weakness(weakness,me_allowed),
'height':choice(heights)}
return rand_choice(me_allowed,heights)

def exploit_weakness(weakness,me_allowed) :
moves = ['attack','parry','lunge','block']
for i,move in enumerate(moves) :
if move == weakness :
if me_allowed[moves[(i+1) % 4]] :
return moves[(i+1) % 4]
break
if me_allowed[weakness] :
return weakness
return choice([x for x in me_allowed if me_allowed[x]])

def feeling_like_a_lucky_punk() :
return random() > 0.8

def main():

this_round = 1
opp_last_move = None
score   = {'myself':0, 'the blaggard':0}
quips   = ['blaggard', 'fool', 'scum', 'raggamuffin']
adverbs = ['deftly', 'skillfully', 'gracefully', 'clumsily']

me_allowed = {'attack':True,'block':True,'lunge':True,'parry':True}
op_allowed = {'attack':True,'block':True,'lunge':True,'parry':True}

while (this_round <= 50 and
all([points < 3 for points in score.values()])) :

if this_round == 1 :
move = cleverly_pick_move(me_allowed,op_allowed)
else:
move = cleverly_pick_move(me_allowed,op_allowed,
opp_last_move=opp_last_move)

print "Our hero %s %ss at the %s's %s" % (
move['type'],
choice(quips),
move['height']
)
print "We await the %s's response..." % choice(quips)
print "Our hero's move: " + (move['type'][0]+move['height'][0]).upper()

opp_move = parse_move(raw_input("Opponent's move: "))

outcome,me_allowed,op_allowed = get_outcome(move,opp_move,me_allowed,
op_allowed)
if outcome == 'WIN' :
print "Our hero pulls off an excellent round!"
score['myself'] += 1
elif outcome == 'LOSE' :
print "Never before have we seen such blatant cheating!"
score['the blaggard'] += 1
else :
print "Our hero is clearly toying with his opponent as he allows \
a drawn round."

print ("""The score after round %d:\nOur hero:\t%d\nHis opponent:\t%d"""
% (this_round, score['myself'], score['the blaggard']))
opp_last_move = opp_move
this_round += 1

print "Match over, surely the victory is mine!"
print """Final score:\n
Our hero:\t%d\nOpponent:\t%d""" % (score['myself'],
score['the blaggard'])

if score['myself'] > score['the blaggard'] :
print "My victory was inevitable!"
elif score['myself'] == score['the blaggard'] :
print "An even match! Huzzar!"
else :
print ""
return

def reset_allowed(dictionary) :
return dict((x,True) for x in dictionary)

def get_outcome(mymove,opmove,me_allowed,op_allowed) :
result = ''

if not me_allowed[mymove['type']] :
print "Whoops, I forgot I couldn't do that..."
result = 'LOSE'

if not op_allowed[opmove['type']] :
print "Haha! What a clutz!"
result = 'WIN'

if mymove['height'] != opmove['height'] :
print "The combatants flail at each other with little effect!"
print "They'll have to try something else next round!"
result = 'DRAW'

if mymove['type'] == opmove['type'] :
if mymove['type'] in ['attack','lunge']:
print "The combatants' blades clash dramatically!"
else :
print "Both combatants take a moment to practice their \
defensive stance..."
result = 'DRAW'

if result :
me_allowed, op_allowed = (reset_allowed(me_allowed),
reset_allowed(op_allowed))
if mymove['height'] != opmove['height'] :
me_allowed[mymove['type']] = op_allowed[opmove['type']] = False
return (result, me_allowed,op_allowed)
else :
return compare_attacks(mymove,opmove,me_allowed,op_allowed)

def compare_attacks(mymove,opmove,me_allowed,op_allowed) :
"""
0 A > P 1
^  x  v
3 B < L 2
"""
print "Our hero %ss, his opponent %ss!" % (mymove['type'],opmove['type'])

move_val = {'attack':0,'parry':1,'lunge':2,'block':3}
result_num = (move_val[opmove['type']] - move_val[mymove['type']]) % 4
results = ['DRAW','WIN','DRAW','LOSE']

me_allowed, op_allowed = (reset_allowed(me_allowed),
reset_allowed(op_allowed))
if result_num == 1 :
print "Our hero easily outwits his foe! *Huge cheers from crowd*"
return ('WIN',me_allowed,op_allowed)
elif result_num == 3 :
print "Our hero graciously allows his opponent a charity point.\
*A torrent of boos from the crowd*"
return ('LOSE',me_allowed,op_allowed)
else:
# Combatants drew and will have their moves restricted next round.
if mymove['type'] in ['attack','parry'] :
me_allowed['attack'] = me_allowed['lunge'] = False
me_allowed['parry']  = me_allowed['block'] = True
op_allowed['parry']  = op_allowed['block'] = False
op_allowed['attack'] = op_allowed['lunge'] = True
else :
me_allowed['parry']  = me_allowed['block'] = False
me_allowed['attack'] = me_allowed['lunge'] = True
op_allowed['attack'] = me_allowed['lunge'] = False
op_allowed['parry']  = op_allowed['block'] = True
return ('DRAW',me_allowed,op_allowed)

def parse_move(move_string) :
m_types = {'A':'attack','B':'block','L':'lunge','P':'parry'}

move_string = move_string.strip().upper()
if not move_string :
print "Couldn't understand your input: %s" % move_string
return parse_move(raw_input("Opponent's move: "))

if move_string[0] not in m_types :
move_string = move_string[::-1]

try :
move = {'type':m_types[move_string[0]],
'height':m_heights[move_string[1]]}
return move
except KeyError :
print "Couldn't understand your input: %s" % move_string
return parse_move(raw_input("Opponent's move: "))

if __name__ == '__main__' :
main()
``````

NRGdallas

1

ejrb

2

``````// A.I.h
#pragma once

#include "Fencer.h"

#include <algorithm>

Move Fencer::chooseFirstMove() const
{
// Choose first move here.
return Move( Action::Attack , Height::Head );
}

Move Fencer::chooseNextMove() const
{
using namespace std;

// Implement A.I. here.
auto legalActions = match.legalActions();
auto isLegal = [&legalActions]( Action a ) {
return find( begin(legalActions) , end(legalActions) , a ) == end(legalActions);
};

if( isLegal( Action::Attack ) )
return Move( Action::Attack , Height::Head );
if( isLegal( Action::Lunge ) )
return Move( Action::Lunge , Height::Head );
if( isLegal( Action::Block ) )
return Move( Action::Lunge , Height::Head );
if( isLegal( Action::Parry ) )
return Move( Action::Parry , Height::Head );

}

// Fencer.h
#pragma once

#include "Match.h"

class Fencer
{
public:
std::string nextRound( const std::string& oppsMove );
std::string getNextMove() const { return nextMove.toStr(); }
bool matchInProgress() const { return match.inProgress(); }
Fencer( unsigned int targetScore = 3 , unsigned int match_rounds = 50 );
private:
Move chooseNextMove() const;
Move chooseFirstMove() const;
Move nextMove;
Match match;
};

// Match.h
#pragma once

#include <vector>
#include <string>

enum class Action : char
{
Attack,
Parry,
Block,
Lunge,
UNITIALIZED
};

enum class Height : char
{
Chest,
Feet,
UNITIALIZED
};

enum class Result : char
{
Win,
Tie,
Lose,
UNITIALIZED
};

struct Move
{
Action action;
Height height;
Move( Action a , Height h )
: action(a) , height(h) {}
std::string toStr() const;

// For the STL. Please don't use these.
Move() : action( Action::UNITIALIZED ) , height( Height::UNITIALIZED ) {}
Move operator=( const Move& );
};

Result scoreRound( Move me , Move opp );

struct Round
{
Move myMove;
Move oppsMove;
Result result;
Round( Move me , Move opp )
: myMove(me) , oppsMove(opp) , result(scoreRound(me,opp)) {}

// For the STL. Please don't use these.
Round() : myMove() , oppsMove() , result( Result::UNITIALIZED ) {}
Round operator=( const Round& );
};

class Match
{
public:
// Constructor.
Match( unsigned int winningScore, unsigned int rounds );

// Generate a list of legal actions.
std::vector<Action> legalActions() const;

// Get a copy of all previous rounds.
std::vector<Round> getHistory() const { return results; }

// Gets the scores
unsigned int myScore() const;
unsigned int oppsScore() const;
bool inProgress() const { return in_progress; }

// Perform next round. Returns the TTY for the round.
std::string nextRound( const std::string& myMove , const std::string& oppsMove );
private:
const unsigned int winning_score;
const unsigned int n_rounds;
std::vector<Round> results;
bool in_progress;
};

// Fencer.cpp
#include "AI.h"

#include <algorithm>

using namespace std;

Fencer::Fencer( unsigned int target , unsigned int rounds ) :
match( target , rounds ) , nextMove( chooseFirstMove() )
{}

string Fencer::nextRound( const string& oppsMove )
{
string output = match.nextRound( nextMove.toStr() , oppsMove );
if( match.inProgress() ) {
nextMove = chooseNextMove();
vector<Action> legalActions = match.legalActions();
auto it = find( legalActions.begin() , legalActions.end() , nextMove.action );
auto it2 = legalActions.end();
if( legalActions.end() == it ) {
output += "\n\nWARNING! Chosen move is illegal!\n\n";
}
output += " Action for next round is " + getNextMove() + ".";
}
return output;
}

// Match.cpp
#include "Match.h"

#include <algorithm>
#include <sstream>
#include <cassert>
#include <functional>

using namespace std;

string Move::toStr() const
{
string str;
switch( action )
{
case Action::Attack:
str.push_back( 'A' );
break;
case Action::Block:
str.push_back( 'B' );
break;
case Action::Lunge:
str.push_back( 'L' );
break;
case Action::Parry:
str.push_back( 'P' );
break;
default:
assert( false );
break;
}
switch( height )
{
str.push_back( 'H' );
break;
case Height::Chest:
str.push_back( 'C' );
break;
case Height::Feet:
str.push_back( 'F' );
break;
default:
assert( false );
break;
}
return str;
}

Move Move::operator=( const Move& rhs )
{
action = rhs.action;
height = rhs.height;
return *this;
}

Result scoreRound( Move me , Move opp )
{
if( me.height != opp.height ) {
return Result::Tie;
}
if( me.action == opp.action ) {
return Result::Tie;
}
switch ( me.action ) {
case Action::Attack:
switch( opp.action ) {
case Action::Parry:
return Result::Win;
case Action::Lunge:
return Result::Tie;
case Action::Block:
return Result::Lose;
default:
assert( false );
}
case Action::Lunge:
switch( opp.action ) {
case Action::Block:
return Result::Win;
case Action::Attack:
return Result::Tie;
case Action::Parry:
return Result::Lose;
default:
assert( false );
}
case Action::Parry:
switch( opp.action ) {
case Action::Lunge:
return Result::Win;
case Action::Block:
return Result::Tie;
case Action::Attack:
return Result::Lose;
default:
assert( false );
}
case Action::Block:
switch( opp.action ) {
case Action::Attack:
return Result::Win;
case Action::Parry:
return Result::Tie;
case Action::Lunge:
return Result::Lose;
default:
assert( false );
}
default:
assert( false );
}
return Result::Tie;
}

Round Round::operator=( const Round& rhs )
{
myMove = rhs.myMove;
oppsMove = rhs.oppsMove;
result = rhs.result;
return *this;
}

Match::Match( unsigned int targetScore , unsigned int rounds ) :
winning_score( targetScore ) , n_rounds( rounds) , results() , in_progress( true )
{
results.reserve( rounds );
}

vector<Action> Match::legalActions() const
{
typedef unsigned int ActionBits;

// Make a bitfield representing the four legal actions.
const ActionBits ATTACK = 0x1;
const ActionBits PARRY = 0x2;
const ActionBits BLOCK = 0x4;
const ActionBits LUNGE = 0x8;

const auto actionBitsToVector = [=](ActionBits ab) -> vector<Action> {
vector<Action> vec;
if( ab == 0 ) // Nothing is allowed
ab = ATTACK | PARRY | BLOCK | LUNGE; // So allow all actions
if( (ATTACK & ab) == ATTACK )
vec.push_back( Action::Attack );
if( (PARRY & ab) == PARRY )
vec.push_back( Action::Parry );
if( (BLOCK & ab) == BLOCK )
vec.push_back( Action::Block );
if( (LUNGE & ab) == LUNGE )
vec.push_back( Action::Lunge );
return vec;
};

auto availableActions = ATTACK | PARRY | BLOCK | LUNGE;

const auto lastResult = *results.rbegin();

// If a point was scored in the last round all actions are available.
if( lastResult.result != Result::Tie ) {
return actionBitsToVector( availableActions );
}

// If the heights do not match, both players may no longer
// select the same action (height is not restricted)
// as the previous tying rounds, until a point is scored,
// or all 4 actions have been filled.
if( lastResult.myMove.height != lastResult.oppsMove.height ) {
for( auto it = results.rbegin() ; it!= results.rend() ; ++it ) {
if( it->result != Result::Tie )
break;
else {
switch( it->myMove.action )
{
case Action::Attack:
availableActions &= ~ATTACK;
break;
case Action::Parry:
availableActions &= ~PARRY;
break;
case Action::Block:
availableActions &= ~BLOCK;
break;
case Action::Lunge:
availableActions &= ~LUNGE;
break;
default:
break;
}
}
}
return actionBitsToVector( availableActions );
}

// Attack vs. Lunge
if( lastResult.myMove.action == Action::Attack &&
lastResult.oppsMove.action == Action::Lunge ) {
return actionBitsToVector( PARRY | BLOCK );
}
if( lastResult.myMove.action == Action::Lunge &&
lastResult.oppsMove.action == Action::Attack ) {
return actionBitsToVector( ATTACK | LUNGE );
}

// Block vs Parry
if( lastResult.myMove.action == Action::Block &&
lastResult.oppsMove.action == Action::Parry ) {
return actionBitsToVector( ATTACK | LUNGE );
}
if( lastResult.myMove.action == Action::Parry &&
lastResult.oppsMove.action == Action::Block ) {
return actionBitsToVector( BLOCK | PARRY );
}
return actionBitsToVector( availableActions );
}

unsigned int Match::myScore() const
{
return count_if( begin(results) , end(results) ,
[=](const Round& r) {
return r.result == Result::Win;
});
}

unsigned int Match::oppsScore() const
{
return count_if( begin(results) , end(results) ,
[=](const Round& r) {
return r.result == Result::Lose;
});
}

string Match::nextRound( const string& myMove , const string& oppsMove )
{
if( !in_progress )

stringstream output;
output << "Round " << results.size()+1 << ": ";
bool parseSuccessful = true;
auto getMove = [&]( const string& s ) {
if( s.length() < 2 ) {
output << "\nError: Move " << s << " does not have enough characters.";
return Move();
}
Action a = Action::UNITIALIZED;
switch( s[0] )
{
case 'a':
case 'A':
a = Action::Attack;
break;
case 'b':
case 'B':
a = Action::Block;
break;
case 'l':
case 'L':
a = Action::Lunge;
break;
case 'p':
case 'P':
a = Action::Parry;
break;
default:
parseSuccessful = false;
output << "\nFailed to parse action part (" << s[0] << ") of " << s;
break;
}

Height h = Height::UNITIALIZED;
switch( s[1] )
{
case 'h':
case 'H':
break;
case 'c':
case 'C':
h = Height::Chest;
break;
case 'f':
case 'F':
h = Height::Feet;
break;
default:
parseSuccessful = false;
output << "\nFailed to parse height part (" << s[1] << ") of " << s;
break;
}

if( a == Action::UNITIALIZED || h == Height::UNITIALIZED )
return Move();
else
return Move( a , h );
};

Round thisRound( getMove( myMove ),  getMove( oppsMove ) );

if ( parseSuccessful ) {
output << "Previous round: " << myMove << " vs " << oppsMove << " - ";
switch( thisRound.result )
{
case Result::Win:
output << myMove + " Wins! ";
break;
case Result::Lose:
output << oppsMove + " Wins! ";
break;
case Result::Tie:
output << "Tie! ";
break;
default:
assert( false );
break;
}

results.push_back( thisRound );
const auto score_me = myScore();
const auto score_opp = oppsScore();
output << "Score is now " << score_me << "-" << score_opp << ".";

if( score_me >= winning_score ) {
output << "\n\tI win! ";
in_progress = false;
}
if( score_opp >= winning_score ) {
output << "\n\tI lose. ";
in_progress = false;
}
if( results.size() >= n_rounds ) {
output << "\n\tTime's up. ";
if( score_me == score_opp )
output << "Match drawn. ";
else
output << "I " << (score_me > score_opp ? "win! " : "lose. " );
in_progress = false;
}

if (!in_progress ) {
output << "Final score: " << score_me << "-" << score_opp << endl;
}
}
return output.str();
}
``````

1

1

`UNITIALIZED`？！