O'Reilly Forums: Lab 2 - Mace Attack() Method - O'Reilly Forums

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

Lab 2 - Mace Attack() Method Did anyone come up with a clever solution for this method?

#1 User is offline   JJJenkins 

  • New Member
  • Pip
  • Group: Members
  • Posts: 8
  • Joined: 22-May 11

Posted 29 May 2011 - 10:02 AM

I was just curious if anyone came up with a clever solution for this method that did not involve typing nearly identical code over and over. The first solution that popped into my head for this method was easy in concept, but a pain to type out because I ended up typing almost the same thing over and over for each direction. It works, it's just...well...ugly. :)

Ugly, Redundant Code that Makes My Eyes Hurt:

        public override void Attack(Direction direction, Random random)
        {
            bool hit;
            if (direction == Direction.Up)
            {
                hit = DamageEnemy(direction, 20, 6, random);
                if (!hit)
                {
                    hit = DamageEnemy(Direction.Left, 20, 6, random);
                    if (!hit)
                    {
                        hit = DamageEnemy(Direction.Down, 20, 6, random);
                        if (!hit)
                        {
                            DamageEnemy(Direction.Right, 20, 6, random);
                        }
                    }
                }
            }
            else if (direction == Direction.Left)
            {
                hit = DamageEnemy(direction, 20, 6, random);
                if (!hit)
                {
                    hit = DamageEnemy(Direction.Down, 20, 6, random);
                    if (!hit)
                    {
                        hit = DamageEnemy(Direction.Right, 20, 6, random);
                        if (!hit)
                        {
                            DamageEnemy(Direction.Up, 20, 6, random);
                        }
                    }
                }
            }
            else if (direction == Direction.Down)
            {
                hit = DamageEnemy(direction, 20, 6, random);
                if (!hit)
                {
                    hit = DamageEnemy(Direction.Right, 20, 6, random);
                    if (!hit)
                    {
                        hit = DamageEnemy(Direction.Up, 20, 6, random);
                        if (!hit)
                        {
                            DamageEnemy(Direction.Left, 20, 6, random);
                        }
                    }
                }
            }
            else
            {
                hit = DamageEnemy(Direction.Right, 20, 6, random);
                if (!hit)
                {
                    hit = DamageEnemy(Direction.Up, 20, 6, random);
                    if (!hit)
                    {
                        hit = DamageEnemy(Direction.Left, 20, 6, random);
                        if (!hit)
                        {
                            DamageEnemy(Direction.Down, 20, 6, random);
                        }
                    }
                }
            }
        }



It seems like a more elegant solution should be possible. I thought about it for a minute and came up with another solution. It allows me to use the same block of code for all the different directions. But one problem is the annotation in the book says something about making the mace swing in a nice circle. My solution could cause the mace to swing otherwise. Also, this solution seems over complicated, and kind of janky. I'm creating a list and using it in a weird way. It's kind of a creative solution I guess, but just feels wrong to me and feels like it might be hard to decipher.

Creative Solution that's Overcomplicated and Bogus:

public override void Attack(Direction direction, Random random)
        {
            List<int> directions = new List<int>();

            for (int i = 0; i < 4; i++)
            {
                directions.Add(i);
            }
            DamageEnemy(direction, 20, 6, random);
            directions.RemoveAt((int)direction);

            while (directions.Count > 0)
            {
                DamageEnemy((Direction)directions[directions.Count - 1], 20, 6, random);
                directions.RemoveAt(directions.Count - 1);
            }
        }


Finally I came up with something that feels right. I organized my Direction enum so the directions followed a clockwise order starting at the top with 'Up':

 enum Direction
    {
        Up,
        Right,
        Down,
        Left,        
    } 


Then I implemented the following solution that allows me to use the same block of code for all 4 directions and hit each direction with a nice arcing motion:

Nifty Solution that's Easy to Read:

public override void Attack(Direction direction, Random random)
        {
            int attackDirection = (int)direction;
            while (true)
            {
                DamageEnemy((Direction)attackDirection, 20, 6, random);
                attackDirection++;

                if (attackDirection > 3)
                    attackDirection = 0;
                if (attackDirection == (int)direction)
                    break;                
            }
        }


I haven't totally tested it yet (except for on some scrap paper) so if you spot any holes please let me know! Also, I'd be really interested to hear if anyone came up with some other solutions. This one took me a few minutes to figure out, so I'm just wondering if anyone else had to spend some time on it as well.

Thanks!

-Justin

This post has been edited by JJJenkins: 29 May 2011 - 10:06 AM

0

#2 User is offline   bng1234 

  • New Member
  • Pip
  • Group: Members
  • Posts: 3
  • Joined: 25-July 11

Posted 25 July 2011 - 12:41 PM

What I did for mace was to create a private method, GetNextDirection, that takes a direction and returns the next one to try in a clockwise motion.


private Direction GetNextDirection(Direction direction)
        {
            switch (direction)
            {
                case Direction.Up:
                    return Direction.Right;                    
                case Direction.Right:
                    return Direction.Down;                    
                case Direction.Down:
                    return Direction.Left;                    
                case Direction.Left:
                    return Direction.Up;                    
                default:
                    return direction;

            }
        }


And then in my Mace.Attack method, I create a Direction variable, set it to the direction passed, call the DamageEnemy method, then made a loop to check for the next 3 positions like so. Made a slight change to it as I went along:

 for (int i = 0; i < 3; i++)
			{
                //If a hit succeeds, max damage decreases by 1 for the next hit
                if (hitSuccess)
                    damage -= 1;
                newDirection = GetNextDirection(newDirection);
                hitSuccess = DamageEnemy(newDirection, 20, damage, random);
			}  


Seemed like an easy way to solve the attack in a smooth circle problem for me.
0

#3 User is offline   Josh_T 

  • New Member
  • Pip
  • Group: Members
  • Posts: 3
  • Joined: 31-January 13

Posted 31 January 2013 - 03:07 AM

After researching the issue of rotating through Enums and cycling back to the beginning, I was able to piece together:

The ? at the end of Direction in the method declaration allows it to be a null value.
        public static Direction? Next(this Direction direction, Turn turn)
        {
            switch (direction)
            {
                case Direction.Left:
                    return turn == Turn.Clockwise ? Direction.Up : Direction.Down;
                case Direction.Up:
                    return turn == Turn.Clockwise ? Direction.Right : Direction.Left;
                case Direction.Right:
                    return turn == Turn.Clockwise ? Direction.Down : Direction.Up;
                case Direction.Down:
                    return turn == Turn.Clockwise ? Direction.Left : Direction.Right;
                default:
                    return null;
            };
        }


Arrange your Direction enum variables as clockwise. The return statements are just shorthand If/Then statements. Seems to work.

Turn is an enum that has 2 values:
    public enum Turn
    {
        CounterClockwise,
        Clockwise
    }


Getting the next enum:
Direction? enumOne = Next(Direction.Down, Turn.Clockwise);
Direction? enumTwo = Next(Direction.Left, Turn.CounterClockwise);

You can then recast the Direction? enum to Direction by:
Direction enumOneConverted = (Direction)enumOne;



Probably overly complicated it but that's generally what happens in my code.

This post has been edited by Josh_T: 31 January 2013 - 03:15 AM

0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users