Làm cách nào để tăng một biến mà không vượt quá giá trị tối đa?


89

Tôi đang làm một chương trình trò chơi điện tử đơn giản cho trường học và tôi đã tạo ra một phương pháp mà người chơi nhận được 15 điểm sức khỏe nếu phương pháp đó được gọi. Tôi phải giữ sức khỏe ở mức tối đa là 100 và với khả năng lập trình hạn chế của mình tại thời điểm này, tôi đang làm một việc như thế này.

public void getHealed(){
    if(health <= 85)
        health += 15;
    else if(health == 86)
        health += 14;
    else if(health == 87)
    health += 13; 
}// this would continue so that I would never go over 100

Tôi hiểu cú pháp của tôi về không hoàn hảo nhưng câu hỏi của tôi là, có thể là cách tốt hơn để làm điều đó, bởi vì tôi cũng phải làm điều tương tự với các điểm thiệt hại và không được xuống dưới 0.

Đây được gọi là số học bão hòa .


7
Lưu ý thêm, tôi sẽ chọn một tên khác cho phương pháp này. Theo tiêu chuẩn Java (và hầu hết các ngôn ngữ khác mà tôi biết), tên phương thức bắt đầu bằng "get" sẽ trả về một giá trị và không thay đổi bất kỳ điều gì. Tương tự như vậy, các tên phương thức bắt đầu bằng "set" sẽ thay đổi một giá trị và thường không trả về bất kỳ thứ gì.
Darrel Hoffman

Câu trả lời:


225

Tôi sẽ chỉ làm điều này. Về cơ bản, nó cần tối thiểu giữa 100 (máu tối đa) và máu sẽ là bao nhiêu với 15 điểm cộng thêm. Nó đảm bảo rằng sức khỏe của người dùng không vượt quá 100.

public void getHealed() {
    health = Math.min(health + 15, 100);
}

Để đảm bảo rằng hitpoints không giảm xuống dưới mức zero, bạn có thể sử dụng một chức năng tương tự: Math.max.

public void takeDamage(int damage) {
    if(damage > 0) {
        health = Math.max(health - damage, 0);
    }
}

71

chỉ cần thêm 15 vào sức khỏe, do đó:

health += 15;
if(health > 100){
    health = 100;
}

Tuy nhiên, như nhạt nhẽo đã lưu ý, đôi khi với đa luồng (nhiều khối mã thực thi cùng một lúc) có sức khỏe vượt quá 100 tại bất kỳ thời điểm nào có thể gây ra vấn đề và việc thay đổi thuộc tính sức khỏe nhiều lần cũng có thể không tốt. Trong trường hợp đó, bạn có thể làm điều này, như đã đề cập trong các câu trả lời khác.

if(health + 15 > 100) {
    health = 100;
} else {
    health += 15;
}

9
Không bao giờ cho phép nó tiếp tục, điều này có thể dẫn đến các vấn đề mới như điều kiện chủng tộc trong đó sức khỏe của nhân vật được giả định là tối đa sức khỏe xác định (100). Tôi đoán là không có khả năng xảy ra với dự án cấp này nhưng nên sớm thực thi các phương pháp hay.
nhạt nhẽo,

6
@bland Nếu sử dụng phương pháp này, một cách để tránh tình trạng chủng tộc như vậy sẽ là sử dụng một biến tạm thời để lưu trữ giá trị sức khỏe mới và sau đó đặt sức khỏe thành giá trị sức khỏe mới này ở một nơi, với đồng bộ hóa nếu cần.
Bob

13
@bland: Điều kiện chủng tộc chỉ có liên quan khi đa luồng. Và nếu anh ta đang thực hiện đa luồng (mà tôi rất nghi ngờ) , giải pháp sẽ là khóa tất cả các truy cập healthhoặc để đảm bảo healthchỉ được truy cập từ một luồng. Ràng buộc "Không bao giờ cho phép sức khỏe vượt quá 100" không phải là một ràng buộc thực tế.
BlueRaja - Danny Pflughoeft,

@ BlueRaja-DannyPflughoeft Tôi đã nói rằng nó không thể xảy ra cho dự án này. Nói chung, khóa không phải lúc nào cũng được sử dụng và nếu bạn có giá trị tối đa thì nó nên được tuân thủ nghiêm ngặt, chơi game hoặc bằng cách khác. Ví dụ: Nếu một sự kiện được gắn với sự thay đổi của một thuộc tính và sử dụng tỷ lệ phần trăm thì bây giờ bạn đã làm sai lệch quá trình xử lý đó rất nhiều, cũng như việc nó được gọi hai lần. Tôi đang cố gắng duy trì tính tổng quát ở đây và đảm bảo OP học được - tôi cảm thấy câu trả lời này, trong khi nó hoạt động, quá hẹp và cụ thể đối với một học sinh vì nó sẽ buộc anh ta không nghĩ đến bức tranh lớn.
nhạt nhẽo

@Bob Tôi nghĩ rằng điều đó là không cần thiết đối với một thứ đơn giản này.
làm lạnh toán học

45

Bạn không cần một trường hợp riêng biệt cho từng trường hợp inttrên 85. Chỉ cần có một cái else, để nếu sức khỏe đã 86trở lên, thì bạn chỉ cần đặt trực tiếp thành 100.

if(health <= 85)
    health += 15;
else
    health = 100;

25
Một con số kỳ diệu hơi quá đối với tôi (ngay cả khi xem xét cho phép 100) - khi thay đổi 15 thành 16, 85 sẽ cần được điều chỉnh. Thay đổi 85 thành ít nhất 100 - 15(hoặc 100 -HEALED_HEALTH) có phải là một cải tiến?
Maciej Piechotka

37

Tôi nghĩ rằng một cách thành ngữ, hướng đối tượng để làm điều này là có một setHealthtrên Characterlớp. Việc triển khai phương thức đó sẽ giống như sau:

public void setHealth(int newValue) {
    health = Math.max(0, Math.min(100, newValue))
}

Điều này ngăn không cho sức khỏe xuống dưới 0 hoặc cao hơn 100, bất kể bạn đặt nó thành gì.


Việc getHealed()triển khai của bạn chỉ có thể là:

public void getHealed() {
    setHealth(getHealth() + 15);
}

Liệu phương pháp Charactercó-một có ý nghĩa hay không getHealed()là một bài tập được để lại cho người đọc :)


5
+1: Đây là một cách tuyệt vời để thực hiện việc này theo hướng đối tượng! Điều duy nhất tôi có thể đề xuất (và điều này có lẽ sẽ được để lại cho người đọc) là có thể có hai phương thức ( heal(int hp)damage(int hp)) mà mỗi setHealth(int newValue)phương thức gọi phương thức của bạn .
Chris Forrence

18
Có gì sai khi gọi các hàm thư viện? Như các hàm được đặt tên, chúng thể hiện ý định rõ ràng hơn một loạt các logic có điều kiện.
erickson

2
Ngoài ra, nhiều hàm thư viện (và rất có thể là những hàm này) thực sự được tích hợp sẵn và sẽ không thực hiện bất kỳ lệnh gọi nào.
kriss

2
@Matteo Câu trả lời sai - rất có thể chức năng thư viện thực hiện chính xác điều tương tự trong nội bộ, vậy tại sao lại lặp lại chính bạn và làm ô nhiễm mã của bạn? KHÔNG sử dụng các hàm thư viện không tuân theo các nguyên tắc cơ bản của DRY.
NickG

2
@Matteo đây không phải là để tránh một if. Điều này là để tránh việc bạn có thể tự bắn vào chân mình. Nếu quá dài dòng, chỉ cần sử dụng nhập tĩnh. Sau đó, nó trông như thế này: health = max(0, min(100, newValue)) Nếu đó là vẫn không thể đọc được cho bạn, giải nén nó vào một phương thức có tên clampnên vẻ dòng như thế này:health = clamp(0, 100, newValue)
Daniel Kaplan

14

Tôi chỉ sẽ cung cấp một đoạn mã có thể tái sử dụng nhiều hơn, nó không phải là đoạn mã nhỏ nhất nhưng bạn có thể sử dụng nó với bất kỳ số lượng nào nên nó vẫn đáng được nói

health += amountToHeal;
if (health >= 100) 
{ 
    health = 100;
}

Bạn cũng có thể thay đổi 100 thành biến maxHealth nếu bạn muốn thêm số liệu thống kê vào trò chơi của bạn, vì vậy toàn bộ phương pháp có thể giống như thế này

private int maxHealth = 100;
public void heal(int amountToHeal)
{
    health += amountToHeal;
    if (health >= maxHealth) 
    { 
        health = maxHealth;
    }
}

BIÊN TẬP

Để biết thêm thông tin

Bạn có thể làm tương tự khi người chơi bị hư hại, nhưng bạn sẽ không cần minHealth vì dù sao thì đó cũng sẽ là 0. Làm theo cách này, bạn sẽ có thể gây sát thương và chữa lành bất kỳ số tiền nào với cùng một mã.


1
minHealthcó thể là tiêu cực, chẳng hạn như trong D&D ... :)
JYelton

1
Cho đến nay câu trả lời tốt nhất ở đây.
Glitch Desire,

@JYelton, vâng bạn chỉ nói (sức khỏe <= 0) trong câu lệnh if. Bạn có thể xử lý nó theo cách bạn muốn, nếu bạn muốn họ có mạng, bạn chỉ cần trừ 1 từ lifeCount hoặc chỉ cần họ thua cuộc thì nó có thể xử lý điều đó. Nếu bạn muốn, bạn thậm chí có thể khiến họ bắt đầu cuộc sống mới với lượng -HP mà họ có. Bạn có thể dán mã này ở bất cứ đâu và nó sẽ hoạt động tốt, đó là điểm của câu trả lời này.
5tar-Kaster


4

Tôi sẽ tạo một phương thức tĩnh trong một lớp trợ giúp. Bằng cách này, thay vì lặp lại mã cho mọi giá trị cần phù hợp với một số ranh giới, bạn có thể có một phương pháp đa năng. Nó sẽ chấp nhận hai giá trị xác định giá trị tối thiểu và tối đa, và giá trị thứ ba được kẹp trong phạm vi đó.

class HelperClass
{
    // Some other methods

    public static int clamp( int min, int max, int value )
    {
        if( value > max )
            return max;
        else if( value < min )
            return min;
        else
            return value;
    }
}

Đối với trường hợp của bạn, bạn sẽ khai báo sức khỏe tối thiểu và tối đa của mình ở đâu đó.

final int HealthMin = 0;
final int HealthMax = 100;

Sau đó, gọi hàm chuyển theo trạng thái tối thiểu, tối đa và điều chỉnh của bạn.

health = HelperClass.clamp( HealthMin, HealthMax, health + 15 );

3

Tôi biết đây là một dự án trường học, nhưng nếu bạn muốn mở rộng trò chơi của mình sau này và có thể nâng cấp sức mạnh chữa bệnh của mình, hãy viết hàm như sau:

public void getHealed(healthPWR) {
    health = Math.min(health + healthPWR, 100);
}

và gọi ra hàm:

getHealed(15);
getHealed(25);

...Vân vân...

Hơn nữa, bạn có thể tạo HP tối đa của mình bằng cách tạo một biến không phải là cục bộ của hàm. Vì tôi không biết bạn đang sử dụng ngôn ngữ nào nên tôi sẽ không hiển thị ví dụ vì nó có thể sai cú pháp.


2

Có lẽ điều này?

public void getHealed()
{
  if (health <= 85)
  {
    health += 15;
  } else
  {
    health = 100;
  }
}

2

Nếu bạn muốn trở nên táo bạo và phù hợp với mã của mình trên một dòng, bạn có thể sử dụng toán tử bậc ba :

health += (health <= 85) ? 15 : (100 - health);

Lưu ý rằng một số người sẽ cau mày với cú pháp này do (được cho là) ​​khả năng đọc kém!


4
Tôi thấy health = (health <= 85)?(health+15):100dễ đọc hơn (nếu bạn thực sự muốn sử dụng một nhà điều hành ternary)
Matteo

1

Tôi tin rằng điều này sẽ làm được

if (health >= 85) health = 100;
else health += 15;

Giải trình:

  • Nếu khoảng cách hồi máu là 15 hoặc ít hơn, máu sẽ trở thành 100.

  • Ngược lại nếu khoảng cách lớn hơn 15, nó sẽ cộng thêm 15 vào máu.

Vì vậy, ví dụ: nếu sức khỏe là 83, nó sẽ trở thành 98 chứ không phải 100.


Bạn có thể mở rộng về cách thức hoạt động của di chúc này để giải quyết câu hỏi của người yêu cầu không?
Ro Yo Mi

Nếu khoảng cách hồi máu là 15 hoặc ít hơn sẽ trở thành 100. Nếu khoảng cách lớn hơn 15 thì sẽ cộng thêm 15 máu. vì vậy đối với Ví dụ sức khỏe là 83 sẽ trở thành 98 chứ không phải 100. Nếu bất kỳ mối quan tâm cụ thể xin vui lòng cho tôi biết, cảm ơn bạn đã bình luận.
MarmiK

Điều && health < 100kiện là không cần thiết. Nếu nó là 100, nó sẽ được đặt thành 100, không thay đổi. Lý do duy nhất bạn cần đó là nếu nó đã có thể để có được> 100 bằng cách nào đó và chúng tôi không muốn chữa bệnh để giảm lại cho bạn xuống 100.
Darrel Hoffman

@DarrelHoffman Tôi nghĩ bạn đúng nếu trò chơi không cung cấp thêm 100 máu thì bạn đúng, tôi đã sửa câu trả lời của mình :) cảm ơn bạn
MarmiK

1

Nếu tôi muốn an toàn cho chuỗi, tôi sẽ làm theo cách này hơn là sử dụng một khối được đồng bộ hóa.

So sánh nguyên tử đạt được kết quả tương tự như được đồng bộ hóa mà không có chi phí.

AtomicInteger health = new AtomicInteger();

public void addHealth(int value)
{
    int original = 0;
    int newValue = 0;
    do
    {
        original = health.get();
        newValue = Math.min(100, original + value);
    }
    while (!health.compareAndSet(original, newValue));
}

1

Cách đơn giản nhất bằng cách sử dụng toán tử mô đun.

máu = (máu + 50)% 100;

sức khỏe sẽ không bao giờ bằng hoặc vượt quá 100.


Nhưng nếu bạn thực hiện thao tác đó khi health100, bạn sẽ kết thúc với 50 máu.
Parziphal

0
   private int health;
    public void Heal()
    {
        if (health > 85)
            health = 100;
        else
            health += 15;
    }
    public void Damage()
    {
        if (health < 15)
            health = 0;
        else
            health -= 15;
    }

nếu bạn định tạo các hàm, ít nhất bạn nên đặt số 15 là một tham số :)
Jordan

@Jordan: Nó phụ thuộc vào ngữ cảnh tôi đang viết mã. :-)
hôn nách của tôi
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.