An Intersection Test for Arbitrary Rectangular Prisms

Have you ever had two arbitrarily rotated and sized rectangular prisms, and wanted to check if they’re intersecting? I know I have! Just an old AABB won’t do the trick, as very snug fitting rectangular prisms need to be detected and dismissed. There are some dastardly configurations (for instance, imagine a very very small rectangular prism sitting just above the surface of a massive and highly skewed rectangular prism) which also need to be sussed out.

It turned out to be a surprisingly tricky problem, and I had to pull a lot of different things from a lot different places together to get it working.

So how does it work? Well first lets think about the problem in 2 dimensions. There’s 3 escalating tests we can run to check if these rotated boxes overlap. The first is to generate two axis-aligned boxes and run a quick AABB check as a broad phase check. The second is to iterate the points of one of the boxes and check the overlap. If there are any points within the box, the box is overlapping. If that is inconclusive, we run the final and most expensive test. First, we pick one of the boxes to define a set of axis in whatever dimensions we’re working with. We basically rotate the whole world in such a way that one box is now perfectly aligned with the axis. Then, we project to each axis. If any of the projections do not overlap, we can guarantee that the boxes do not overlap either.

It’s pretty much a straight shoot up into the third dimension for the first 2 tests. However, for the 3rd, instead of projecting a 1D line from a 2D shape as above, we instead project a 2D shape onto a 2D surface. To do this, we decompose the rotated 3D rectangular prism into its composite triangles.

We can then flatten these triangles against a 2D axis by swizzling their coordinates. We then can do the much simpler test of if a triangle is intersecting an axis aligned rectangle, for each triangle. If any of the triangles succeed, the whole axis succeeds and exits. If all axis succeed, the test is a success and the rectangular prisms absolutely do overlap.

As always let me know if you think I’ve done it wrong, or if there was a simpler way to do this, or if you think I fucked up somewhere.

Get it here.

Automating Tinder.com with JavaScript

As a on-and-off user of this particular form of social masochism, it’s clear that there is an optimal strategy, which is to like absolutely everybody indiscriminately, save your SuperLikes for people who really stand out, and then actually make a judgement on if this is the sort of person you’d be interested in if you do match with them. Of course this strategy suffers from a potential Tragedy of the Commons (although worst case is everyone follows this strategy and matches with everyone else), and requires a premium option (as Likes can’t be a limited resource).

Recently, Tinder released a web version of their site, which got me thinking about ways to automate this pretty simple strategy. I spent about half an hour writing this little script, which does the following:

  • Checks the user for a bio
    • If no bio is found, we either like or dislike, depending on preference.
  • Checks the bio against several positive and negative keywords
    • If a positive keyword is found, we attempt to superlike the user
    • If a negative keyword is found, we dislike the user
  • If no positive or negative keywords are found, we like the user

Pretty simple, pretty easy. Find the JS below. To use, run it in the console of Tinder.com while you’re signed in, and leave it for however long you want. Enjoy your matches! Or getting banned.

Future possible improvements:

  • Move to Chrome/Greasemonkey plugin

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// USER PREFS
var superLikeKeywords = [];
var dislikeKeywords = [ ];
var likeWithNoBio = true;

// TINDER MACRO
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}

function waitTime ()
{
return 5000 + Math.random() * 1000;
}

async function likeLoop()
{
var lastbio = "";
var likeCounter = 0;
var dislikeCounter = 0;
var superlikeCounter = 0;
while(true)
{
console.log("Likes: " + likeCounter);
console.log("Dislikes: " + dislikeCounter);
console.log("SuperLikes: " + superlikeCounter);

await sleep(waitTime());

var loadingCircles = document.getElementsByClassName("beacon__circle Pos(a) Bd Bdrs(50%) T(10px) Start(10px) W(80px) H(80px) Animdur(4s) Animic(i) Animtf(l) Bdc($c-beacon-pink) Bgc($c-beacon-pink) Animdel(2s)");
while(loadingCircles.length != 0)
{
await sleep(1000);
}

var profileButtons = document.getElementsByClassName("recCard__openProfile Bdrs(50%) Cur(p) Ta(c) Fl(end)");
if(profileButtons.length == 0)
{
console.log("Couldn't find profileButton");
return;
}
var profileButton = profileButtons[0];
if(profileButton == null)
{
console.log("Couldn't find profileButton");
return;
}

profileButton.click();
await sleep(waitTime());

var allButtons = document.getElementsByClassName("button__text Pos(r) Z(1)");
var dislikeButton = allButtons[0];
var superLikeButton = allButtons[1];
var likeButton = allButtons[2];

if(dislikeButton == null)
{
console.log("Couldn't find like dislikeButton");
return;
}
if(superLikeButton == null)
{
console.log("Couldn't find like superLikeButton");
return;
}
if(likeButton == null)
{
console.log("Couldn't find like button");
return;
}

var bioContainers = document.getElementsByClassName("Py(10px) Px(16px) profileCard__bio Ta(start) Us(t) C($c-secondary) BreakWord Whs(pl)");
if(bioContainers.length == 0)
{
// No bio
if(likeWithNoBio)
{
likeButton.click();
console.log("No bio, liking.");
}
else
{
dislikeButton.click();
console.log("No bio, disliking.");
}
continue;
}

var bio = bioContainers[0].getElementsByTagName("span")[0].innerHTML;
console.log("Profile: " + bio);
bio = bio.toLowerCase();

if(bio != lastbio)
{
var keywordFound = false;
// Check like keywords
for(var i = 0; i < superLikeKeywords.length; ++i)
{
var keyword = superLikeKeywords[i];
//console.log("Checking positive keyword: " + keyword);
if(bio.includes(keyword))
{
console.log("Keyword "" + keyword + "" found! Attempting superlike.");
lastbio = bio;
keywordFound = true;

superLikeButton.click();
superlikeCounter++;

await sleep(waitTime());

var back = document.getElementsByClassName("modalManager D(f) StretchedBox CenterAlign Bgc(#000.68)")[0];
if(back == null)
{
console.log("Back click element not found");
break;
}
back.click();
break;
}
}

// Check dislike keywords
for(var i = 0; i < dislikeKeywords.length; ++i)
{
var keyword = dislikeKeywords[i];
//console.log("Checking negative keyword: " + keyword);
if(bio.includes(keyword))
{
console.log("Negative keyword "" + keyword + "" found, disliking.");
lastbio = bio;
keywordFound = true;
dislikeButton.click();
dislikeCounter++;
break;
}
}

if(keywordFound)
{
continue;
}
}
else
{
console.log("Out of superlikes, so we just give out a regular ol' like");
}

likeButton.click();
likeCounter++;
}
}

likeLoop();