إعادة بناء التعليمات البرمجية
عند هذه النقطة، يجب أن يكون لديك الشفرة التالية:
function valyrianSteelSwordAttack(unit) {
return {
action: true,
description:
'Attack a unit in the given direction (forward by default) with your Valyrian steel sword, dealing 5 HP of damage.',
perform(direction = 'forward') {
const receiver = unit.getSpaceAt(direction).getUnit();
if (receiver) {
unit.log(`attacks ${direction} and hits ${receiver}`);
unit.damage(receiver, 5);
} else {
unit.log(`attacks ${direction} and hits nothing`);
}
},
};
}
function iceCrystalSwordAttack(unit) {
return {
action: true,
description:
'Attack a unit in the given direction (forward by default) with your ice blade, dealing 3 HP of damage.',
perform(direction = 'forward') {
const receiver = unit.getSpaceAt(direction).getUnit();
if (receiver) {
unit.log(`attacks ${direction} and hits ${receiver}`);
unit.damage(receiver, 3);
} else {
unit.log(`attacks ${direction} and hits nothing`);
}
},
};
}
function feel(unit) {
return {
description:
'Return the adjacent space in the given direction (forward by default).',
perform(direction = 'forward') {
return unit.getSensedSpaceAt(direction);
},
};
}
function walk(unit) {
return {
action: true,
description: 'Move one space in the given direction (forward by default).',
perform(direction = 'forward') {
const space = unit.getSpaceAt(direction);
if (space.isEmpty()) {
unit.move(direction);
unit.log(`walks ${direction}`);
} else {
unit.log(`walks ${direction} and bumps into ${space}`);
}
},
};
}
const WhiteWalker = {
name: 'White Walker',
character: 'w',
maxHealth: 12,
abilities: {
attack: iceCrystalSwordAttack,
feel: feel,
},
playTurn(whiteWalker) {
const enemyDirection = ['forward', 'right', 'backward', 'left'].find(
direction => {
const unit = whiteWalker.feel(direction).getUnit();
return unit && unit.isEnemy();
},
);
if (enemyDirection) {
whiteWalker.attack(enemyDirection);
}
},
};
const Level1 = {
description:
"You've entered the ancient castle of Eastwatch to escape from a blizzard. But it's deadly cold inside too.",
tip:
"Call `warrior.walk()` to walk forward in the Player's `playTurn` method.",
timeBonus: 15,
aceScore: 10,
floor: {
size: {
width: 8,
height: 1,
},
stairs: {
x: 7,
y: 0,
},
warrior: {
character: '@',
maxHealth: 20,
position: {
x: 0,
y: 0,
facing: 'east',
},
abilities: {
walk: walk,
},
},
},
};
const Level2 = {
description:
'The cold became more intense. In the distance, you see a pair of deep and blue eyes, a blue that burns like ice.',
tip:
"Use `warrior.feel().isEmpty()` to see if there's anything in front of you, and `warrior.attack()` to fight it. Remember, you can only do one action per turn.",
clue:
'Add an if/else condition using `warrior.feel().isEmpty()` to decide whether to attack or walk.',
timeBonus: 20,
aceScore: 26,
floor: {
size: {
width: 8,
height: 1,
},
stairs: {
x: 7,
y: 0,
},
warrior: {
character: '@',
maxHealth: 20,
position: {
x: 0,
y: 0,
facing: 'east',
},
abilities: {
attack: valyrianSteelSwordAttack,
feel: feel,
},
},
units: [
{
...WhiteWalker,
position: {
x: 4,
y: 0,
facing: 'west',
},
},
],
},
};
module.exports = {
name: 'Game of Thrones',
description:
'There is only one war that matters: the Great War. And it is here.',
levels: [Level1, Level2],
};
فكما فعلنا مع تعريف السائر الأبيض، يمكننا إستخراج الحقول الخاصة بالسائر الأبيض إلى مُتَغَير ثم إستعمال خصائص الإنتشار من أجل إضافته إلى كل المستويات:
const Warrior = {
character: '@',
maxHealth: 20,
};
const Level1 = {
description:
"You've entered the ancient castle of Eastwatch to escape from a blizzard. But it's deadly cold inside too.",
tip:
"Call `warrior.walk()` to walk forward in the Player's `playTurn` method.",
timeBonus: 15,
aceScore: 10,
floor: {
size: {
width: 8,
height: 1,
},
stairs: {
x: 7,
y: 0,
},
warrior: {
...Warrior,
abilities: {
walk: walk,
},
position: {
x: 0,
y: 0,
facing: 'east',
},
},
},
};
const Level2 = {
description:
'The cold became more intense. In the distance, you see a pair of deep and blue eyes, a blue that burns like ice.',
tip:
"Use `warrior.feel().isEmpty()` to see if there's anything in front of you, and `warrior.attack()` to fight it. Remember, you can only do one action per turn.",
clue:
'Add an if/else condition using `warrior.feel().isEmpty()` to decide whether to attack or walk.',
timeBonus: 20,
aceScore: 26,
floor: {
size: {
width: 8,
height: 1,
},
stairs: {
x: 7,
y: 0,
},
warrior: {
...Warrior,
abilities: {
attack: valyrianSteelSwordAttack,
feel: feel,
},
position: {
x: 0,
y: 0,
facing: 'east',
},
},
units: [
{
...WhiteWalker,
position: {
x: 4,
y: 0,
facing: 'west',
},
},
],
},
};
فيما يتعلق بالقدرات، يمكننا أن نرى أن كلتا القدرتين الهجوميتين متشابهتين جدا. دعونا نفعل شئ حيال ذالك:
function attackCreator({ power, weapon }) {
return unit => ({
action: true,
description: `Attack a unit in the given direction (forward by default) with your ${weapon}, dealing ${power} HP of damage.`,
perform(direction = 'forward') {
const receiver = unit.getSpaceAt(direction).getUnit();
if (receiver) {
unit.log(`attacks ${direction} and hits ${receiver}`);
unit.damage(receiver, power);
} else {
unit.log(`attacks ${direction} and hits nothing`);
}
},
});
}
const valyrianSteelSwordAttack = attackCreator({
power: 5,
weapon: 'Valyrian steel sword',
});
const iceCrystalSwordAttack = attackCreator({
power: 3,
weapon: 'ice blade',
});
يمكننا أن نسمي هذا النمط "قدرة المبتكر"، حيث نقوم بتعريف دالة (قدرة المبتكر) التي بدورها تقوم بإرجاع دالة أخرى (القدرة) المخصصة مع المتغييرات التي مررناها إلى المبتكر.
من أجل إنهاء إعادة بناء التعليمات البرمجية، دعونا نتخلص من كل تلك السلاسل السحرية التي تمثل الاتجاهات. هناك رزمة رسمية تسمى @warriorjs/geography
التي تعرض مجموعة من الثوابت والأساليب المتعلقة بالتوجيه. دعونا نستخدمها:
const {
EAST,
FORWARD,
RELATIVE_DIRECTIONS,
WEST,
} = require('@warriorjs/geography');
function attackCreator({ power, weapon }) {
return unit => ({
action: true,
description: `Attack a unit in the given direction (forward by default) with your ${weapon}, dealing ${power} HP of damage.`,
perform(direction = FORWARD) {
const receiver = unit.getSpaceAt(direction).getUnit();
if (receiver) {
unit.log(`attacks ${direction} and hits ${receiver}`);
unit.damage(receiver, power);
} else {
unit.log(`attacks ${direction} and hits nothing`);
}
},
});
}
const valyrianSteelSwordAttack = attackCreator({
power: 5,
weapon: 'Valyrian steel sword',
});
const iceCrystalSwordAttack = attackCreator({
power: 3,
weapon: 'ice blade',
});
function feel(unit) {
return {
description:
'Return the adjacent space in the given direction (forward by default).',
perform(direction = FORWARD) {
return unit.getSensedSpaceAt(direction);
},
};
}
function walk(unit) {
return {
action: true,
description: 'Move one space in the given direction (forward by default).',
perform(direction = FORWARD) {
const space = unit.getSpaceAt(direction);
if (space.isEmpty()) {
unit.move(direction);
unit.log(`walks ${direction}`);
} else {
unit.log(`walks ${direction} and bumps into ${space}`);
}
},
};
}
const Warrior = {
character: '@',
maxHealth: 20,
};
const WhiteWalker = {
name: 'White Walker',
character: 'w',
maxHealth: 12,
abilities: {
attack: iceCrystalSwordAttack,
feel: feel,
},
playTurn(whiteWalker) {
const enemyDirection = RELATIVE_DIRECTIONS.find(direction => {
const unit = whiteWalker.feel(direction).getUnit();
return unit && unit.isEnemy();
});
if (enemyDirection) {
whiteWalker.attack(enemyDirection);
}
},
};
const Level1 = {
description:
"You've entered the ancient castle of Eastwatch to escape from a blizzard. But it's deadly cold inside too.",
tip:
"Call `warrior.walk()` to walk forward in the Player's `playTurn` method.",
timeBonus: 15,
aceScore: 10,
floor: {
size: {
width: 8,
height: 1,
},
stairs: {
x: 7,
y: 0,
},
warrior: {
...Warrior,
abilities: {
walk: walk,
},
position: {
x: 0,
y: 0,
facing: EAST,
},
},
},
};
const Level2 = {
description:
'The cold became more intense. In the distance, you see a pair of deep and blue eyes, a blue that burns like ice.',
tip:
"Use `warrior.feel().isEmpty()` to see if there's anything in front of you, and `warrior.attack()` to fight it. Remember, you can only do one action per turn.",
clue:
'Add an if/else condition using `warrior.feel().isEmpty()` to decide whether to attack or walk.',
timeBonus: 20,
aceScore: 26,
floor: {
size: {
width: 8,
height: 1,
},
stairs: {
x: 7,
y: 0,
},
warrior: {
...Warrior,
abilities: {
attack: valyrianSteelSwordAttack,
feel: feel,
},
position: {
x: 0,
y: 0,
facing: EAST,
},
},
units: [
{
...WhiteWalker,
position: {
x: 4,
y: 0,
facing: WEST,
},
},
],
},
};
module.exports = {
name: 'Game of Thrones',
description:
'There is only one war that matters: the Great War. And it is here.',
levels: [Level1, Level2],
};
أفضل بكثير! أكمل القراءة لتتعلم كيفية اختبار و نشر برجك بحيث يستطيع اللاعبين الأخرين اللعب!