ก่อนอื่นเรามากำหนดหมายเลขใหม่ ไม่ต้องกังวลมันเป็นเรื่องง่าย
หรือจะนำมันก็: f = √3× ฉันด้วยฉันเป็นหน่วยจินตภาพ ด้วยเหตุนี้การหมุน 60 องศาตามเข็มนาฬิกาเป็นเช่นเดียวกับการคูณโดย1/2 × (1 - ฉ )และการหมุน 60 องศาทวนเข็มนาฬิกาเช่นเดียวกับการคูณโดย1/2 × (1 + F ) หากฟังดูแปลก ๆ โปรดจำไว้ว่าการคูณด้วยจำนวนเชิงซ้อนนั้นเหมือนกับการหมุนในระนาบ 2D เราแค่ "สควอช" จำนวนเชิงซ้อนในทิศทางจินตภาพเล็กน้อย (โดย√3) เพื่อไม่ต้องจัดการกับสแควร์รูท ... หรือไม่ใช่จำนวนเต็มสำหรับเรื่องนั้น
นอกจากนี้เรายังสามารถเขียนจุด (A, B) เป็น A + B × ฉ
สิ่งนี้ทำให้เราหมุนจุดใดก็ได้ในระนาบ ตัวอย่างเช่นจุด (2,0) = 2 + 0 × fหมุนไปที่ (1, -1) จากนั้นถึง (-1, -1), (-2,0), (-1,1), ( 1,1) และในที่สุดก็กลับมาที่ (2,0) เพียงแค่คูณมัน
แน่นอนว่าเราต้องการวิธีในการแปลคะแนนเหล่านั้นจากพิกัดของเราเป็นผู้ที่เราทำการหมุนเวียนแล้วกลับมาอีกครั้ง สำหรับสิ่งนี้จำเป็นต้องใช้ข้อมูลอีกเล็กน้อย: ถ้าจุดที่เราหมุนรอบนั้นคือ "ซ้าย" หรือ "ขวา" ของเส้นแนวตั้ง สำหรับความเรียบง่ายที่เราประกาศว่าจะมี "โยกเยก" ค่าW 0 ถ้ามันไปทางซ้ายของมัน (เหมือนศูนย์กลางของการหมุน [0,0] ในด้านล่างสองภาพของคุณ) และ 1 ถ้ามันไปทางขวา ของมัน สิ่งนี้ขยายคะแนนดั้งเดิมของเราเป็นสามมิติ ( x , y , w ) โดยที่ "w" เป็น 0 หรือ 1 หลังจากการทำให้เป็นมาตรฐาน ฟังก์ชันการทำให้เป็นมาตรฐานคือ:
NORM: ( x , y , w ) -> ( x + floor ( w / 2), y , w mod 2) โดยมีการดำเนินการ "mod" ที่กำหนดไว้ซึ่งจะส่งกลับเฉพาะค่าบวกหรือศูนย์
อัลกอริทึมของเราตอนนี้มีลักษณะดังนี้:
เปลี่ยนคะแนนของเรา ( a , b , c ) เป็นตำแหน่งที่สัมพันธ์กับศูนย์การหมุน ( x , y , w ) โดยการคำนวณ ( a - x , b - y , c - w ) จากนั้นปรับผลลัพธ์ให้เป็นมาตรฐาน นี่ทำให้ศูนย์กลางการหมุนที่ (0,0,0) ชัดเจน
เปลี่ยนคะแนนของเราจากพิกัด "ดั้งเดิม" ของพวกเขาไปเป็นค่าที่ซับซ้อนในการหมุน: ( a , b , c ) -> (2 × a + c , b ) = 2 × a + c + b × f
หมุนจุดของเราด้วยการคูณพวกมันด้วยหนึ่งในจำนวนการหมุนด้านบนตามต้องการ
Ra- เปลี่ยนจุดกลับจากพิกัดการหมุนเป็นคน "ดั้งเดิม" ของพวกเขา: ( r , s ) -> (พื้น ( r / 2), s , r mod 2) โดยมี "mod" กำหนดไว้ข้างต้น
แปลงคะแนนกลับไปที่ตำแหน่งเดิมโดยเพิ่มเข้าไปในศูนย์การหมุน ( x , y , z ) และการทำให้เป็นมาตรฐาน
ตัวเลขแบบง่าย ๆ ของเรา "สามเท่า" ที่ใช้ตัวเลขfใน C ++ จะเป็นดังนี้:
class hex {
public:
int x;
int y;
int w; /* "wobble"; for any given map, y+w is either odd or
even for ALL hexes of that map */
hex(int x, int y, int w) : x(x), y(y), w(w) {}
/* rest of the implementation */
};
class triplex {
public:
int r; /* real part */
int s; /* f-imaginary part */
triplex(int new_r, int new_s) : r(new_r), s(new_s) {}
triplex(const hex &hexfield)
{
r = hexfield.x * 2 + hexfield.w;
s = hexfield.y;
}
triplex(const triplex &other)
{
this->r = other.r; this->s = other.s;
}
private:
/* C++ has crazy integer division and mod semantics. */
int _div(int a, unsigned int b)
{
int res = a / b;
if( a < 0 && a % b != 0 ) { res -= 1; }
return res;
}
int _mod(int a, unsigned int b)
{
int res = a % b;
if( res < 0 ) { res += a; }
return res;
}
public:
/*
* Self-assignment operator; simple enough
*/
triplex & operator=(const triplex &rhs)
{
this->r = rhs.r; this->s = rhs.s;
return *this;
}
/*
* Multiplication operators - our main workhorse
* Watch out for overflows
*/
triplex & operator*=(const triplex &rhs)
{
/*
* (this->r + this->s * f) * (rhs.r + rhs.s * f)
* = this->r * rhs.r + (this->r * rhs.s + this->s * rhs.r ) * f
* + this->s * rhs.s * f * f
*
* ... remembering that f * f = -3 ...
*
* = (this->r * rhs.r - 3 * this->s * rhs.s)
* + (this->r * rhs.s + this->s * rhs.r) * f
*/
int new_r = this->r * rhs.r - 3 * this->s * rhs.s;
int new_s = this->r * rhs.s + this->s * rhs.r;
this->r = new_r; this->s = new_s;
return *this;
}
const triplex operator*(const triplex &other)
{
return triplex(*this) *= other;
}
/*
* Now for the rotations ...
*/
triplex rotate60CW() /* rotate this by 60 degrees clockwise */
{
/*
* The rotation is the same as multiplikation with (1,-1)
* followed by halving all values (multiplication by (1/2, 0).
* If the values come from transformation from a hex field,
* they will always land back on the hex field; else
* we might lose some information due to the last step.
*/
(*this) *= triplex(1, -1);
this->r /= 2;
this->s /= 2;
}
triplex rotate60CCW() /* Same, counter-clockwise */
{
(*this) *= triplex(1, 1);
this->r /= 2;
this->s /= 2;
}
/*
* Finally, we'd like to get a hex back (actually, I'd
* typically create this as a constructor of the hex class)
*/
operator hex()
{
return hex(_div(this->r, 2), this->s, _mod(this->r, 2));
}
};