<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Posts from joshshipton.com</title>
<description>the latest and greatest ramblings</description>
<link>https://joshshipton.com</link>
<atom:link href="https://joshshipton.com/api/rss.xml" rel="self" type="application/rss+xml"/>
<item>
<guid isPermaLink="true">https://www.joshshipton.com/post/best-personal-websites</guid>
<title>some of my favorite personal websites</title>
<link>https://joshshipton.com/post/best-personal-websites</link>
<description><![CDATA[<ul><li><a href="https://guzey.com/">https://guzey.com/</a></li><li><a href="https://www.benkuhn.net/">https://www.benkuhn.net/</a></li><li><a href="https://gwern.net/">https://gwern.net/</a></li><li><a href="https://moretothat.com/">https://moretothat.com/</a></li><li><a href="https://near.blog/">https://near.blog/</a></li><li><a href="https://www.george-mack.com/">https://www.george-mack.com/</a></li><li><a href="https://www.joelonsoftware.com/">https://www.joelonsoftware.com/</a></li><li><a href="https://blog.codinghorror.com/">https://blog.codinghorror.com/</a></li><li><a href="https://sive.rs/">https://sive.rs/</a></li><li><a href="https://milan.cvitkovic.net/">https://milan.cvitkovic.net/</a></li></ul>]]></description>
<pubDate>Sun, 01 Dec 2024 00:00:00 GMT</pubDate>
</item><item>
<guid isPermaLink="true">https://www.joshshipton.com/post/person-website-good-idea</guid>
<title>why i think having a personal website is a good idea</title>
<link>https://joshshipton.com/post/person-website-good-idea</link>
<description><![CDATA[<p>reasons i think that having a personal website is a good idea </p>
<ul><li>like minded people can quickly vibe check and learn a lot about you</li><li>easy way to share ideas and send them to friends </li><li>written log of your thoughts and posts, adds credibility when someone has been writing about something for x amount of years</li><li>can show off your taste, you control how every part of the website functions and looks (if you don&#39;t thats a skill issue) can express more than just words (the goat of this is <a href="https://gwern.net/"> gwern </a>  </li><li>high variance low stakes. pretty low stakes and easy to set up a personal website (takes 1 hr MAX), but adds the possiblity for some pretty cool tail end events e.g meet a future good friend, job offer, etc. high expected value activity imo.</li></ul><p>you can find a record of the best personal websites i have found <a href="https://joshshipton.com/post/best-personal-websites">here</a></p>
]]></description>
<pubDate>Sun, 01 Dec 2024 00:00:00 GMT</pubDate>
</item><item>
<guid isPermaLink="true">https://www.joshshipton.com/post/hashtable-in-prolog</guid>
<title>hash table from scratch in prolog (boo)</title>
<link>https://joshshipton.com/post/hashtable-in-prolog</link>
<description><![CDATA[<p>i&#39;m currently taking <a href="https://en.wikipedia.org/wiki/Knowledge_representation_and_reasoning">knowledge representation</a> at university, a core part of this unit is logic programming for which we use <a href="https://en.wikipedia.org/wiki/Prolog">Prolog</a>. i seriously dislike Prolog as a programming language. i find it unnatural to work with and it&#39;s quirks irritate me. but this definitely a skill issue (see below image) in an attempt to try to mend my broken relationship with the language i decided to build a data structure from scratch in it (aka procrastinate from actually studying for my exams). i chose hash maps because theyre easy to understand, i like them and O(1) insertion and retrieval time is sexy.</p>
<p><img class="center" src="/images/shared/skill-issue-always.jpg" alt="everything is a skill issue"></img></p>
<p>before i dive into my hash table here are some of my FAVORITE Prolog quirks /s</p>
<h3>&quot;=&quot; is different</h3><pre><code class="language-prolog">% = is for unification, not assignment
X = 5.         % Unifies X with 5

% is is for arithmetic evaluation
Sum is 2 + 3.  % Evaluates 2 + 3 and unifies Sum with 5

% =:= for arithmetic equality
5 =:= 2 + 3.   % true
5 = 2 + 3.     % false! Because it doesnt evaluate 2 + 3
</code></pre>
<h3>no loops, everything is recursive (this one is my least favorite)</h3><pre><code class="language-prolog">print_numbers(0).
print_numbers(N) :-
    N &gt; 0,
    write(N), nl,
    N1 is N - 1,
    print_numbers(N1).
</code></pre>
<h3>negation as failure</h3><pre><code class="language-prolog">% Let&#39;s define some simple facts
likes(john, pizza).
likes(mary, sushi).
likes(john, sushi).

% You might think this would work to find who doesn&#39;t like pizza:
find_pizza_hater(Person) :-
    \+ likes(Person, pizza). % &quot;\+&quot; is the negation operator

% But this fails:
% ?- find_pizza_hater(mary).
% false    &lt;-- confusion??

% You need this thing instead:
find_pizza_hater(Person) :-
    likes(Person, _),         % first find a person that exists
    \+ likes(Person, pizza).  % then check if they don&#39;t like pizza

% This works:
% ?- find_pizza_hater(mary).
% true
</code></pre>
<br>

<h1><div class="center"> ~~~ hash table time ~~~ </div></h1><br>

<p>ok now lets start with the hashtable, i think this will be easiest if we break the code down into it&#39;s main parts.</p>
<h3>the basics of our hash table</h3><pre><code class="language-prolog">:- dynamic hash_bucket/3.  % stores (hash value, key, value)
:- dynamic table_size/1.   % keeps track of table size
:- dynamic item_count/1.   % counts our stuff
</code></pre>
<p>this tells prolog &quot;hey, these things are gonna change while we run&quot;. think of it like creating variables that can actually change (which is weird in prolog). the /3 and /1 just mean how many parameters each one takes.</p>
<h3>initialization (setting up our table)</h3><pre><code class="language-prolog">init_hash_table(size) :-
    retractall(hash_bucket(_, _, _)),    % clear any old junk
    retractall(table_size(_)),           % out with the old size
    retractall(item_count(_)),           % reset our counter
    assertz(table_size(size)),           % set new size
    assertz(item_count(0)).              % start fresh at 0
</code></pre>
<p>this is like our constructor. retractall is basically &quot;delete everything matching this pattern&quot; and assertz is &quot;add this new fact&quot;. the _ is prolog for &quot;i don&#39;t care what this value is&quot;.</p>
<h3>the hash function (where the magic happens)</h3><pre><code class="language-prolog">hash_function(key, size, hashvalue) :-
    string_codes(key, codes),            % convert string to ascii numbers
    sum_codes(codes, sum),               % add them up
    a is 0.69420,                        % completely arbitrary constant...
    product is sum * a,                  % multiply
    fractional is product - floor(product), % get decimal part
    hashvalue is floor(size * fractional). % scale to table size
</code></pre>
<p>this is our hash function - nothing too fancy, just:<br>converts string to ascii numbers -&gt; adds them up -&gt; multiplies them by a completely random constant -&gt; takes the decimal part and scales it to fit our table size</p>
<h3>handling collisions</h3><p>prolog actually makes this super easy. when multiple items hash to the same spot, they just... exist there. the backtracking system handles it automatically. when we look something up:</p>
<pre><code class="language-prolog">get(key, value) :-
    table_size(size),
    hash_function(key, size, hashvalue),
    hash_bucket(hashvalue, key, value).  % magic happens here
prolog will find the right one automatically by matching both the hash AND the key.
</code></pre>
<h3>load factor and resizing</h3><pre><code class="language-prolog">check_load_factor :-
    item_count(count),
    table_size(size),
    loadfactor is count / size,
    (loadfactor &gt; 0.7 -&gt;                 % if too full
        resize_table                     % make it bigger
    ;   true                            % else do nothing
    ).
</code></pre>
<p>when the table gets too full (&gt;70%), we: double the size, grab all our current items and  rehash everything into the bigger table</p>
<h3>the recursive parts (because prolog)</h3><pre><code class="language-prolog">rehash_all([]).                          % base case: empty list = done
rehash_all([key-value|rest]) :-          % for each item:
    table_size(size),
    hash_function(key, size, newhash),   % get new position
    assertz(hash_bucket(newhash, key, value)),
    rehash_all(rest).                    % do the rest
</code></pre>
<p>this is classic prolog recursion:</p>
<p>base case: empty list? doneski<br>otherwise: handle first item, then recurse on the rest</p>
<p>testing it out:</p>
<pre><code class="language-prolog">main :-
    init_hash_table(10),
    insert(&quot;key1&quot;, value1),
    insert(&quot;meaning_of_life&quot;, 42),
    % ... more insertions ...
    print_stats.
</code></pre>
<p>and that&#39;s our hash table!</p>
<p>here&#39;s the implementation in it&#39;s entirety. is it the most efficient implementation ever? probably not. but its cool how working with prolog can lead to a decent outcome.</p>
<pre><code class="language-prolog">% tell prolog these predicates will change during runtime
:- dynamic hash_bucket/3.  % stores triplets of (hash value, key, value)
:- dynamic table_size/1.   % keeps track of how big our table is
:- dynamic item_count/1.   % counts how many items we&#39;ve stored

% sets up a fresh hash table with a given size
init_hash_table(size) :-
    retractall(hash_bucket(_, _, _)),    % clear out any old data
    retractall(table_size(_)),           % remove old size
    retractall(item_count(_)),           % reset item counter
    assertz(table_size(size)),           % set new table size
    assertz(item_count(0)).              % start with zero items

% our hash function - converts keys into table positions
hash_function(key, size, hashvalue) :-
    string_codes(key, codes),            % convert string to ascii numbers
    sum_codes(codes, sum),               % add up all the ascii values
    a is 0.69420,                        % pick a fun decimal number
    product is sum * a,                  % multiply sum by our number
    fractional is product - floor(product), % get just the decimal part
    hashvalue is floor(size * fractional). % scale to fit table size

% adds up a list of ascii codes recursively
sum_codes([], 0).                        % empty list sums to zero
sum_codes([code|rest], sum) :-           % for non-empty list:
    sum_codes(rest, restsum),            % sum up the rest
    sum is code + restsum.               % add current code to sum

% puts a new key-value pair into the hash table
insert(key, value) :-
    table_size(size),                    % get current table size
    hash_function(key, size, hashvalue), % calculate where to put it
    retractall(hash_bucket(hashvalue, key, _)), % remove old value if any
    assertz(hash_bucket(hashvalue, key, value)), % store new value
    update_count(1),                     % increment item counter
    check_load_factor.                   % see if table needs to grow

% finds the value associated with a key
get(key, value) :-
    table_size(size),                    % get table size
    hash_function(key, size, hashvalue), % calculate position
    hash_bucket(hashvalue, key, value).  % look up the value

% removes a key-value pair from the table
remove(key) :-
    table_size(size),                    % get table size
    hash_function(key, size, hashvalue), % find where it should be
    retract(hash_bucket(hashvalue, key, _)), % remove it
    update_count(-1).                    % decrease item count

% updates the count of items in the table
update_count(delta) :-
    retract(item_count(count)),          % get current count
    newcount is count + delta,           % adjust it
    assertz(item_count(newcount)).       % store new count

% checks if the table is getting too full
check_load_factor :-
    item_count(count),                   % get number of items
    table_size(size),                    % get table size
    loadfactor is count / size,          % calculate fullness
    (loadfactor &gt; 0.7 -&gt;                 % if more than 70% full
        resize_table                     % make table bigger
    ;   true                            % otherwise do nothing
    ).

% makes the table bigger when it gets too full
resize_table :-
    table_size(oldsize),                 % get current size
    newsize is oldsize * 2,              % double it
    findall(key-value,                   % collect all current items
            (hash_bucket(_, key, value)),
            pairs),
    retractall(hash_bucket(_, _, _)),    % clear the table
    retractall(table_size(_)),           % update size
    assertz(table_size(newsize)),
    rehash_all(pairs).                   % put items back in new spots

% puts all items back after resizing
rehash_all([]).                          % done if no items left
rehash_all([key-value|rest]) :-          % for each item:
    table_size(size),                    % get new table size
    hash_function(key, size, newhash),   % calculate new position
    assertz(hash_bucket(newhash, key, value)), % store it
    rehash_all(rest).                    % handle remaining items

% shows current table statistics
print_stats :-
    item_count(count),                   % get number of items
    table_size(size),                    % get table size
    loadfactor is count / size,          % calculate fullness
    format(&#39;table size: ~w~n&#39;, [size]),
    format(&#39;item count: ~w~n&#39;, [count]),
    format(&#39;load factor: ~2f~n&#39;, [loadfactor]).

% prints all items in the table
print_all :-
    hash_bucket(hash, key, value),       % find each item
    format(&#39;hash: ~w, key: ~w, value: ~w~n&#39;,
           [hash, key, value]),          % print it
    fail.                                % backtrack to find more
print_all.                               % succeed when done

% test the implementation
main :-
    init_hash_table(10),
    insert(&quot;key1&quot;, value1),
    insert(&quot;meaning_of_life&quot;, 42),
    insert(&quot;first_prime&quot;, 2),
    insert(&quot;random&quot;, 3498),
    remove(&quot;key1&quot;),
    print_all,
    print_stats,
    remove(&quot;first_prime&quot;),
    print_all,
    print_stats.

% tell prolog to run main when loaded
:- initialization(main).
</code></pre>
<p>cool prolog features that make this work:</p>
<ul><li>automatic backtracking: helps with collisions</li><li>dynamic predicates: lets us modify the table</li><li>pattern matching: makes lookups clean</li><li>recursion: because prolog loves recursion</li><li>fact-based storage: using prolog&#39;s database-like features</li></ul>]]></description>
<pubDate>Thu, 24 Oct 2024 00:00:00 GMT</pubDate>
</item><item>
<guid isPermaLink="true">https://www.joshshipton.com/post/goals-for-the-rest-of-the-year2024</guid>
<title>Goals for the rest of the year</title>
<link>https://joshshipton.com/post/goals-for-the-rest-of-the-year2024</link>
<description><![CDATA[<h3>How I set goals</h3><p>My goals for the rest of the year, when I like to set goals I prefer to set goals for systems not results, if I set a goal like &quot;I want to get an A in x unit&quot; this is a bad goal, since there are things about this goal I can&#39;t control. I could study super hard, do everything perfectly, all for my professor to crack the shits and fail the entire class with an impossible exam. </p>
<p>Instead I would set a goal like, </p>
<ol><li>Study 2 hours a night </li><li>Go to office hours</li><li>Do all homework on time</li></ol><p>etc. etc. </p>
<p>These goals set up a system that if I follow I am extremely likely to get an A in x unit. </p>
<h3>Goal 1 Destroy opponent in grappling super fight</h3><p>I&#39;ve got another grappling super fight booked for the 28th of September. I don&#39;t rate my opponent at all so I really want to make a statement and walk through him. In order to achieve this here&#39;s my system </p>
<ol><li>Cultivate a weekly training schedule with good training partners that works around my university and other commitments. (done) </li><li>Stick to the training plan for the next ~8 weeks</li><li>spend 30-60 minutes before every training session watching <a href="https://submeta.io/">submeta</a> in order to make sure I am improving technically. </li><li>Use <a href="https://kenku.org">Kenku</a> to log all training sessions, use problems I log as study points and don&#39;t let the same issue happen twice. e.g didn&#39;t finish a daarce choke I&#39;m looking up that defense before my next session and making sure that I know how to deal with it. </li><li>Pursue excellence in every part of the training session, warm up with excellence, drill with excellence, roll with focus and excellence. I&#39;m not going to be able to spam mat time this camp so this is especially important.</li></ol><h3>Goal 2 Straight Hd&#39;s at Uni</h3><p>My last semester of undergrad, make sure that I&#39;m finishing with a bang, got some fire units this semester, make sure I&#39;m making the most of them. </p>
<ol><li>Do all homework <u> on time </u> (don&#39;t cheat)</li><li>Go to office hours and labs if I don&#39;t understand </li><li>Make friends with people in my units (This is so OP, I only started doing this last semester but the ROI is insane)</li></ol><p>It&#39;s not a lot but to be honest I think doing this will be more than enough to get straight HD&#39;s ^_^</p>
<h3>Goal 3 Figure out what I want to do with my life</h3><p>idk man, this is a WIP, for now I think the best thing I can do is </p>
<ol><li>Cultivate curiosity, keep learning cool shit and doing cool stuff for the sake of doing cool stuff.  </li><li>Apply for as many grad roles as possible (get goated at interviewing) </li><li>Research and apply for postgraduate study</li><li>Take whatever option is the coolest</li></ol>]]></description>
<pubDate>Sat, 27 Jul 2024 00:00:00 GMT</pubDate>
</item><item>
<guid isPermaLink="true">https://www.joshshipton.com/post/life-hacks</guid>
<title>Life hacks</title>
<link>https://joshshipton.com/post/life-hacks</link>
<description><![CDATA[<p class=" py-[-2] text-small italic"> Inspired by <a href="https://guzey.com/lifehacks/"> alexey</a></p>
<br>

<ol><li>lot&#39;s of alpha in low status</li><li>go first</li><li>assume that everyone is a friend </li><li>indifference</li><li><a href="https://sive.rs/kimo">there&#39;s no speed limit</a> </li><li>risks are less risky than you think. take as many as you can.</li><li>spend 10-20% of your time reorienting</li><li>everything is power-law distributed </li><li>you can make yourself more lucky</li><li>lot&#39;s of roi in being a good person </li><li>you can learn anything</li><li>everything is figure-out-able</li><li>suffering is good </li><li>always select for excellence over specificity </li><li>drink water</li></ol>]]></description>
<pubDate>Sat, 27 Jul 2024 00:00:00 GMT</pubDate>
</item><item>
<guid isPermaLink="true">https://www.joshshipton.com/post/chasing-excellence-book-review-quotes</guid>
<title>Chasing Excellence book best quotes</title>
<link>https://joshshipton.com/post/chasing-excellence-book-review-quotes</link>
<description><![CDATA[<p>On a recent plane ride I read <a href="https://www.goodreads.com/book/show/35713474-chasing-excellence">Chasing Excellence</a> by Ben Bergon. I really liked the book and resonated with a lot of ideas discussed. It was one of those reads that manages to articulate some of your intuitions and then build on top of them in ways you hadn&#39;t managed to get to by yourself. </p>
<p>Here&#39;s some of my favorite excerpts and quotes, I like <a href="https://joshshipton.com/collected-words">collecting words</a> so see this as a collection of words with the common theme being they come from the same place. </p>
<h3>On the mentality of <a href="https://en.wikipedia.org/wiki/Mat_Fraser_(athlete)">Mat Fraser</a> (the Crossfit GOAT)</h3><blockquote><p>Mat consciously, every day, seeks out things he might be bad at. When he finds weaknesses, he doesn’t just work on them—he eviscerates them. One of the events he struggled with at the 2013 North East Regional was “Jackie,” a CrossFit benchmark workout of rowing, barbell thrusters, and pull-ups. He got dusted on the row—the other men were pulling 1:40 splits, and he was struggling to hold on to 1:50. That put him twenty seconds slower than the leaders, which was an enormous, unsurmountable gap. Relative to his competitors, he straight-up sucked at rowing. After Regionals, he went home, bought a rower, and for the next year, he rowed 4,000 to 5,000 meters of intervals—every day.</p>
</blockquote><h3>On mental reframes</h3><blockquote><p>Down on the beach, the complaining continues. Games documentarian Sevan Matossian asks one of the women, a three-year Games veteran, how she’s feeling after yesterday’s slugfest at the Ranch. Her response was included in the CrossFit-produced behind-the-scenes 2016 Games documentary: Waiting in the airport for so long at night, then having to get up really early, was really tiring. It’s already a lot harder than it was two years ago. The first day—everything from getting up early to three workouts in one day—that was a lot harder than what we did in 2014, when all we did on the first day was an ocean swim and then an overhead squat. I felt a lot better going into Thursday. And now we’re swimming on Thursday, so we don’t even get a rest day.</p>
</blockquote><blockquote><p>A few minutes later, Sevan finds Katrín, who is emerging from a warm-up dip in the surf. He asks her the same question. Here’s what she says I feel good! I was able to sleep a lot yesterday. I slept on the airport floor, I slept the whole plane ride, then I slept for five hours when I got into bed. I feel really good. I’m happy about that. Love that we get to go straight through with no rest day, love that. The more volume, the better. That’s great. So far it’s been amazing.</p>
</blockquote><h3>On Stoicism</h3><blockquote><p>At my gym, there’s an unbreakable threefold policy:</p>
</blockquote><blockquote><p>NEVER WHINE.NEVER COMPLAIN.NEVER MAKE EXCUSES.</p>
</blockquote><blockquote><p>If you talk about (or worse,complain about) things that are outside of your control, things that could diminish performance, you will see and experience more of those things.</p>
</blockquote><blockquote><p>As Ryan Holiday writes in The Obstacle Is the Way, “There is no good or bad without us, there is only perception. There is the event itself and the story we tell ourselves about what it means.” If your story is telling you you’re not good enough, not smart enough, too old, too young, or can’t do it, your subconscious will believe you.</p>
</blockquote><h3>On adversity</h3><blockquote><p>Elite athletes know something that most people don’t—adversity is the best thing that can happen to you. The competitors here at the Games know that humans only improve through adversity by embracing short-term pain. Ensuring there is no struggle, no challenge, and staying in your wheelhouse is a recipe for spinning your wheels without improving. It’s the days when you have to do things that scare you, when you have to take risks, when you have to push against challenge and difficulty—those are the days that make you stronger, faster, and better overall.</p>
</blockquote><h3>On autonomy</h3><blockquote><p>Racehorses are special. They’re not like just any other horse—they’re elite athletes, and they know it. They train with heart monitors, they do interval workouts, they have coaches and massage therapists, they eat a special diet, and they have recovery protocols. It sounds like I’m describing a human athlete, and I very well could be, because top racehorses and top human athletes are similar in just about every way but one. That one difference is crucial, and it gives racehorses a huge advantage over us: racehorses can’t think for themselves.</p>
</blockquote><blockquote><p>I get it; that doesn’t sound like an advantage. But think about it: racehorses are incapable of second-guessing their coaches, overanalyzing their performance, or logging junk miles. They’re unable to sandbag a workout if they’re not feeling up for training on a particular day. They don’t look at the other racehorses and compare themselves, or wonder if they’re with the right coach and training program. On race day, they don’t walk by the stalls of their competitors and think, Holy crap, look at the legs on him! How am I going to compete with that? Racehorses just perform. They can’t second-guess anything, and they have no biological choice but to have a laser focus on the task at hand. They’re able to do what we try to get our human athletes to do, as naturally as breathing. When they win, they don’t change anything about their routine, and they aren’t fundamentally changed. The next day is just another training day because winning (or losing) is part of the process, not the endpoint.</p>
</blockquote><blockquote><p>Racehorses aren’t biologically capable of understanding what their competitors are doing. They’re completely focused on themselves. That’s where I want my athletes. If an athlete’s goal is to beat their competitor, then, by definition, they’re not reaching their full potential—they’re simply clearing the bar of the next guy’s potential.</p>
</blockquote><h3>On deliberate practice</h3><blockquote><p>Deliberate practice can be characterized by the following four elements:</p>
</blockquote><blockquote><ol><li><ol><li>It’s designed specifically to improve performance.</li></ol></li><li><ol><li>It is repeated a lot.</li></ol></li><li><ol><li>Feedback on results is continuously available.</li></ol></li><li><ol><li>It’s highly demanding mentally, and not necessarily or particularly enjoyable, because it means you are focusing on improving areas in your performance that are not satisfactory.</li></ol></li></ol></blockquote><blockquote><p>The requirement for concentration is what sets deliberate practice apart from both mindless routine performance and playful engagement. The takeaway here is that while hard work is instrumental to success, it’s not enough. Obviously, the CrossFit Games does not hand out medals based on who spent the most time in the gym. Katrín didn’t win the Games last year because she logged more hours in the gym than all the other women. She won the Games because of the quality of those hours</p>
</blockquote><blockquote><p>I know you want me to let you in<br>on some big secret to success in the NBA. The secret is there is no secret. It’s just boring old habits.</p>
</blockquote><h1>On goals</h1><blockquote><p>Mat and Katrín have figured out the secret: that there is no secret. The process is about doing your job to the best of your ability, and Katrín and Mat wield it like a weapon. Do they want to win the CrossFit Games? Absolutely. But we don’t talk about it, and we certainly don’t make it a goal. Because what’s more important to success than a bold and courageous goal is developing a system—a process—to get there</p>
</blockquote><h3>On accepting what you cannot control</h3><blockquote><p>I listen to the buzz with growing content. This is the part of the process from which my athletes derive a considerable competitive advantage. As an elite athlete, there are only five things that you can truly control—your training, nutrition, sleep, recovery, and mindset. If it doesn’t fall into one of those categories, I tell my athletes, forget about it. Control the things you can control, and ignore everything else.</p>
</blockquote><blockquote><p>All of this is summed up by the tattoo on Mat’s left arm—the Serenity Prayer. You’ve heard it before: God grant me the serenity to accept the things I cannot change, the courage to change the things I can, and the wisdom to know the difference. It doesn’t matter whether you believe in God or not—this is exactly the mantra you want to lean in to. Let go of what you can’t change. Make room for the things you can.</p>
</blockquote><h3>Chapter Openings</h3><p>The book opens every chapter with a quote, some of the quotes were absolute bangers, here they are</p>
<blockquote><p>Opportunity is missed by most people because it is dressed in overalls and looks like work. —THOMAS EDISON</p>
</blockquote><blockquote><p>Sometimes when you’re in a dark place you think you’ve been buried, but<br>you’ve actually been planted. —UNKNOWN</p>
</blockquote><blockquote><p>When you have confidence, you can have a lot of fun. And when you have<br>fun, you can do amazing things. —JOENAMATH</p>
</blockquote><blockquote><p>One can have no smaller or greater mastery than mastery of oneself.<br>—LEONARDO DA VINCI</p>
</blockquote><blockquote><p>Only those who have the patience to do things perfectly will acquire the<br>skills to do difficult things easily. —FRIEDRICH SCHILLER</p>
</blockquote>]]></description>
<pubDate>Tue, 16 Jul 2024 00:00:00 GMT</pubDate>
</item><item>
<guid isPermaLink="true">https://www.joshshipton.com/post/cellular-automata-disease-simulation</guid>
<title>Small Shapes go brrr, dipping my toes into the world of Cellular Automata</title>
<link>https://joshshipton.com/post/cellular-automata-disease-simulation</link>
<description><![CDATA[<h3><a href="https://www.joshshipton.com/projects/cellular-automata-disease.html">Simulation Link</a></h3><p>I was watching this <a href="https://www.youtube.com/watch?v=p3lsYlod5OU&t=3889s">video</a> when the guest started talking about <a href="https://en.wikipedia.org/wiki/Cellular_automaton">Cellular Automata</a>. Earlier in the year I wasted quite a few hours on <a href="https://playgameoflife.com/">this site</a> playing around with gliders, spaceships, ladders and other kinds of automata. </p>
<p>With more time on my hands I decided I wanted to play around and learn more about cellular automata. I have no idea why I find them so fascinating but I could watch them for hours. During the course of development for this project I lost a lot of time starting and re-running the simulation. There&#39;s something about such simple rules being able to create such vivid patterns that creates a psychedelic experience. </p>
<p>After researching practical applications for cellular automata I can upon <a href="https://link.springer.com/article/10.1140/epjs/s11734-022-00619-1">this</a> paper. Where someone used cellular automata to model the spread of COVID. </p>
<p>This didn&#39;t seem as sophisticated as other ideas that I was interested in like <a href="https://uu.diva-portal.org/smash/get/diva2:483914/FULLTEXT01.pdf">traffic flow</a> (I&#39;m coming for this later) so I decided to tackle it. </p>
<p>Here&#39;s an example run through</p>
<div class="center">
<iframe width="560" height="315" src="https://www.youtube.com/embed/Cga37Bg91Lo?si=qYNbxxLu1n8p9bZh" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div>
<br/>
<br/>

<h4>How it Works</h4><p>The Simulation runs as a 75x75 grid in which each cell represents a person. There are four states represented by different colors as seen in the key on the right hand side of the simulation.</p>
<p>Each cell at any time can either be infected, recovered (but not immune), immune or normal (no state)</p>
<p>The simulation begins with the amount of <em>&quot;initial infected&quot;</em> being randomly distributed in the grid and then the days begin incrementing. </p>
<p>On each consecutive day infected cells can either recover with or without immunity, or infect their neighbors, as a neighbor to an infected cell your probability of being infected increased exponentially based on how many infected neighbors you have</p>
<p>Once a cell has been sick for the length of infection then they &quot;recover&quot; with a probability p of becoming immune for n days (all variables are adjustable by the user)</p>
<p>If you want to play around with the disease simulation yourself I&#39;m hosting it <a href="https://www.joshshipton.com/projects/cellular-automata-disease.html">here</a>, plug in whatever values you want and go crazy. </p>
<p>If you&#39;re interested in the code and how everything works you can find that <a href="https://github.com/joshshipton/cellular_automata_disease">here</a>. Any obvious bugs/huge errors feel free to make a PR or contact me. </p>
<h3>Next steps</h3><p>I enjoyed/am enjoying this project. But I don&#39;t know how far I can push it. I&#39;m going to start reading <a href="https://www.goodreads.com/work/quotes/47988064-designing-beauty-the-art-of-cellular-automata-emergence-complexity-an"><em>&quot;Designing Beauty: The Art of Cellular Automata&quot;</em></a> by Andrew Adamatzky and see what I learn/what inspiration I get. More Cellular Automata art/simulations are definitely on the cards.</p>
]]></description>
<pubDate>Wed, 19 Jun 2024 00:00:00 GMT</pubDate>
</item><item>
<guid isPermaLink="true">https://www.joshshipton.com/post/bouncing-ball</guid>
<title>Making a ball bounce cost me my sanity, but forced me to learn maths</title>
<link>https://joshshipton.com/post/bouncing-ball</link>
<description><![CDATA[<p>Recently <a href="https://www.youtube.com/watch?v=Mu6hloC7ty8&ab_channel=GreenCode">this video</a> came up on my YouTube, I liked the idea of making satisfying simulations with code and had some post-exams free time on my hands so I thought I would try it for myself.</p>
<p>This was <strong>far</strong> more tricky that I thought it was going to be and also ended up being the first time I ever used high school maths in real life. I really enjoyed the project and learning, so here&#39;s a post to share them with my friends and cement my understandings.</p>
<p>I&#39;m going to walk through the steps that it took to get the foundation of these simulations going, it&#39;s not perfect but the meat and potatoes are there. By the end you&#39;ll be able to simulate some basic physics and have something that looks like this.</p>
<br>
<div class='center'>
<iframe width="560" height="315" src="https://www.youtube.com/embed/Zm6qoxx0uEs?si=AF25Bkn3ymroonXE" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div>
<br>

<p>For this simulation I&#39;m going to be using pygame, pygame is a nifty little library that makes it really easy to run simulations like these ones and get visual stuff up on the screen super quick whilst using all that python syntax that we all know and love.</p>
<p>Here&#39;s some boiler plate code, to initialize pygame, draw a screen and define some colors. This isn&#39;t really too relevant or interesting but I&#39;ve included it for transparency.</p>
<pre><code class="language-python">import pygame
import math

# init pygame
pygame.init()

# draw a 600 x 600 window
screen = pygame.display.set_mode((600,600))
</code></pre>
<p>Now we have pygame, and a basic screen but we now want to start drawing stuff on the screen. Let&#39;s create a new Class to draw the large circle that will contain our ball.</p>
<pre><code class="language-python">class DrawCircle:
    def __init__(self):
        self.center = (300,300)
        self.radius = 255
        self.width = 3

    def draw(self):
        pygame.draw.circle(screen,WHITE, self.center,self.radius,self.width)
</code></pre>
<p>Look how easy that was! We&#39;ve now got a screen with a nice white circle.</p>
<p>Now come&#39;s the tricky (but interesting!) part of this project. We need to make the ball bounce. Easy right???....</p>
<p>Lets start by creating our BouncingBall object and initializing some variables</p>
<pre><code class="language-python">class BouncingBall:
    def __init__(self):
        self.x = 300
        self.y = 300
        self.velocity = [1, 2]
        self.radius = 15
        # Elasticity is the amount of energy the ball loses when it hits something
        self.elasticity = 0.9
        # constant for gravity
        self.gravity = 0.5
</code></pre>
<p>Going through the variables, </p>
<p>The x and y coordinates will &quot;spawn&quot; our ball in the middle of the screen.</p>
<p>The ball&#39;s velocity is represented as a list [1,2] and controls the speed and direction that the ball moves in, it&#39;ll change over time to reflect the ball&#39;s differing speeds and directions. The first value (1) is the initial horizontal speed (changing x-velocity) of the ball and the second value (2) is the initial vertical speed (changing y-velocity) of the ball.</p>
<p>This means that the ball will start moving downwards and to the right. There&#39;s no specific reason for this apart from the fact that it give&#39;s it that nice arc as it bounces from left to right.</p>
<p>Elasticity is the amount of energy the ball is going to retain after it collides with the edge&#39;s of the outer-circle. An elasticity of 0.9 means that every time the ball collides it loses 10% of it&#39;s energy. Giving it a realistic bounce.</p>
<p>And then we have a constant for gravity. Gravity acts as a constant downwards acceleration on the ball and makes the simulation look far more &quot;real&quot;.</p>
<p>Simple enough!</p>
<p>Now for the real fun part! Let&#39;s get this bad boy moving! </p>
<pre><code class="language-python">    def move(self):
        # Apply gravity
        self.velocity[1] += self.gravity
        self.x += self.velocity[0]
        self.y += self.velocity[1]
</code></pre>
<p>Simple enough, we apply gravity to the y value of the velocity (thus pulling it down a bit) and then move the x and y values of the ball depending on the ball&#39;s current velocity in each of the directions.</p>
<p>But currently we don&#39;t check if the ball has hit the edge of the circle. So it&#39;s just going to move in one direction forever, let&#39;s change that and add some collision detection!</p>
<p>To figure out if the ball has collided with the edge of the circle we can imagine the ball&#39;s coordinate and the center of the big circle forming two points of a perfect right-angled triangle. We can then use Pythagoras theorem to calculate how far the ball is from the center and use this information to check if it&#39;s at the edge. </p>
<img src="/images/bouncy-bouncy/distance_from_the_center.png">

<p>In code</p>
<pre><code class="language-python">if self.distance_to_center() + self.radius &gt; 255:
    # The ball collided with the edge of the circle

def distance_to_center(self):
    # Pythagoras
    return math.sqrt((self.x - 300) ** 2 + (self.y - 300) ** 2)
</code></pre>
<p>Now that we know we have hit an edge we need to get (and thus calculate) that sweet, but so ever so elusive <em>&quot;bounce&quot;</em>.</p>
<p>In order to do this we are going to have to go back to high school and refresh our knowledge of <em><strong>vectors</strong></em>.</p>
<p>A vector is a quantity that has both magnitude (length) and direction. In our case the ball&#39;s velocity is a vector because it describes how fast the ball is moving and the direction that it is moving in.</p>
<p>A normal vector is just a vector that&#39;s perpendicular (90 degrees) to a surface. In this case the normal vector is going to represent the direction from the point of collision towards the center of the circle.</p>
<p>But how do we calculate the normal vector?</p>
<p>We first have to find the vector pointing from the ball towards the center, we can do this quickly by subtracting 300 (recall that the center of the large circle is 300,300) from both the x and y coordinates of the ball. Which will get the same point on the opposite side of the circle. As seen in the image below. </p>
<img src="/images/bouncy-bouncy/simply.png">

<pre><code class="language-python">normal = [self.x - 300, self.y - 300]
</code></pre>
<p>Then once we have the vector pointing directly from the ball to the center we need to calculate the magnitude (length) of the current vector. This is the length from the ball to the center of the circle. Again we can use good old Pythagoras to do this.</p>
<pre><code class="language-python">normal_length = math.sqrt(normal[0] ** 2 + normal[1] ** 2)
</code></pre>
<p>But you may have realised a problem, this is gonna get really big really fast, and we don&#39;t actually care about the length, we only care about the direction so we can <a href="https://www.khanacademy.org/computing/computer-programming/programming-natural-simulations/programming-vectors/a/vector-magnitude-normalization#:~:text=To%20normalize%20a%20vector%2C%20therefore,the%20unit%20vector%20readily%20accessible.">normalize</a> this value. To make it more normal and avoid things like <a href="https://en.wikipedia.org/wiki/Buffer_overflow">buffer overflow</a> and let&#39;s us have more accurate, less exaggerated velocities. </p>
<p>We can do this by dividing each component of the vector by its magnitude again this will keep the overall direction of the vector the same, whilst managing the overall length. </p>
<pre><code class="language-python">normal = [normal[0] / normal_length, normal[1] / normal_length]
</code></pre>
<p>In fancy terms this is now called a <em>unit vector</em> because it has a length of 1.</p>
<p>Ok cool, now we have the normal vector, that wasn&#39;t so hard but how is this going to help us bounce? Intuitively we can&#39;t just make the ball exactly from the point and back, this isn&#39;t how bouncing works. When I throw a ball at an edge it doesn&#39;t just move straight back towards me, but how it bounces should be impacted by the angle and speed that the ball collided with the target. </p>
<p>To do this we first we need to calculate the dot product between the velocity and normal vectors, the dot product is a way to multiply two vectors that results in a single number. It combines the corresponding components of the vectors and then sums the products to do so.</p>
<p>In this scenario the dot product between the velocity and normal vector&#39;s tells us how much of the velocity is directed towards the collision point. A positive dot product means that the ball is moving towards the collision point, and a negative means it is moving away.  </p>
<p>Here&#39;s an example that skip&#39;s normalization for simplicity sake.</p>
<img src="/images/bouncy-bouncy/dot-product.png">

<p>In the code this looks like so</p>
<pre><code class="language-python">dot_product = self.velocity[0] * normal[0] + self.velocity[1] * normal[1]
</code></pre>
<p>The dot product is going to determine how much of the ball&#39;s velocity is directed towards the center of the circle (the normal direction).</p>
<p>We now also need to reflect the new Velocity vector, to give the new direction that the ball is going to move in.</p>
<p>We can use a nice math trick here to reflect the velocity vector.</p>
<p>If we multiply the normal vector by twice the dot product the code essentially flips the component of the velocity vector that&#39;s parallel to the surface (represented by the normal vector). This effectively changes the direction of the ball based on the angle of impact.</p>
<p>In the code</p>
<pre><code class="language-python">self.velocity[0] -= 2 * dot_product * normal[0]
self.velocity[1] -= 2 * dot_product * normal[1]
</code></pre>
<p>We can&#39;t forget about adding elasticity, if we forget this the ball will just bounce forever, this isn&#39;t really realistic so we will multiply the ball&#39;s velocity by the elasticity constant to take away 10% of the balls speed every collision.</p>
<pre><code class="language-python">self.velocity[0] *= self.elasticity
self.velocity[1] *= self.elasticity
</code></pre>
<p>Now we have a bit of a problem. As the code currently stands the ball will get stuck inside the boundary and break everything. We can add a small amount of overlap to the ball to prevent it from getting stuck in the curvature of the boundary.</p>
<pre><code class="language-python">overlap = self.distance_to_center() + self.radius - 255
self.x -= normal[0] * overlap
self.y -= normal[1] * overlap
</code></pre>
<p>And that&#39;s all the maths and physics done. Easy peasy! Now to get things cooking let&#39;s quickly add a draw method to draw the bouncing ball to the screen. </p>
<pre><code class="language-python">def draw(self):
    pygame.draw.circle(screen, RED, (int(self.x), int(self.y)), self.radius)
</code></pre>
<p>Now create instances of the outer circle and bouncing ball and add a game loop.</p>
<pre><code class="language-python">circle = DrawCircle()
ball = BouncingBall()

# Game loop
while 1==1:
    # Move the ball
    ball.move()

    # Clear the screen
    screen.fill(BLACK)

    # Draw the circle and the ball
    circle.draw()
    ball.draw()

    # Update the display
    pygame.display.flip()

    # Cap the frame rate
    pygame.time.Clock().tick(60)
</code></pre>
<p>Done!</p>
<p>Here&#39;s the full code if you want to try it on your machine or play around with the values. Just <code>pip install pygame</code> if you haven&#39;t already and it&#39;ll work out the box :))).</p>
<pre><code class="language-python">import pygame
import math


# init pygame

pygame.init()

# draw a 600 x 600 window
screen = pygame.display.set_mode((600,600))
pygame.display.set_caption(&quot;BOUNCY BOUNCY!&quot;)

BLACK = (0,0,0)
WHITE = (255,255,255)
RED = (255,0,0)


class DrawCircle:
    def __init__(self):
        self.center = (300,300)
        self.radius = 255
        self.width = 3

    def draw(self):
        pygame.draw.circle(screen,WHITE, self.center,self.radius,self.width)

class BouncingBall:
    def __init__(self):
        self.x = 300
        self.y = 300
        self.velocity = [1, 2]
        self.radius = 15
        # Elasticity is the amount of energy the ball loses when it hits something
        self.elasticity = 0.9
        # constant for gravity
        self.gravity = 0.5

    def move(self):
        # Apply gravity
        self.velocity[1] += self.gravity
        self.x += self.velocity[0]
        self.y += self.velocity[1]

        # Check for collision with the boundary of the larger circle
        if self.distance_to_center() + self.radius &gt; 255:
            # Calculate the normal vector at the point of collision
            normal = [self.x - 300, self.y - 300]
            normal_length = math.sqrt(normal[0] ** 2 + normal[1] ** 2)
            normal = [normal[0] / normal_length, normal[1] / normal_length]

            # Reflect the ball&#39;s velocity around the normal vector
            dot_product = self.velocity[0] * normal[0] + self.velocity[1] * normal[1]
            self.velocity[0] -= 2 * dot_product * normal[0]
            self.velocity[1] -= 2 * dot_product * normal[1]

            # Apply elasticity
            self.velocity[0] *= self.elasticity
            self.velocity[1] *= self.elasticity

            # Move the ball slightly outside the circle to prevent sticking
            overlap = self.distance_to_center() + self.radius - 255
            self.x -= normal[0] * overlap
            self.y -= normal[1] * overlap

    def distance_to_center(self):
        return math.sqrt((self.x - 300) ** 2 + (self.y - 300) ** 2)

    def draw(self):
        pygame.draw.circle(screen, RED, (int(self.x), int(self.y)), self.radius)

# Create instances
circle = DrawCircle()
ball = BouncingBall()

# Game loop
while 1==1:
    # Move the ball
    ball.move()

    # Clear the screen
    screen.fill(BLACK)

    # Draw the circle and the ball
    circle.draw()
    ball.draw()

    # Update the display
    pygame.display.flip()

    # Cap the frame rate
    pygame.time.Clock().tick(60)
</code></pre>
]]></description>
<pubDate>Wed, 12 Jun 2024 00:00:00 GMT</pubDate>
</item><item>
<guid isPermaLink="true">https://www.joshshipton.com/post/quick-select-eurkea</guid>
<title>Quick Select Makes Sense</title>
<link>https://joshshipton.com/post/quick-select-eurkea</link>
<description><![CDATA[<p>I was studying for an exam and came upon this question </p>
<blockquote><p> Design an algorithm for finding the k-th smallest element in an unsorted array of length n that is faster than O(n log n) amortized. Analyse the complexity of your algorithm assuming k as a constant. (5 marks)</p>
</blockquote><p>This really stumped me, I couldn&#39;t figure out how do this in <em>less than</em> O(n * log(n)) time. But now after researching, I know. And I think the algorithm is pretty cool. So for your enjoyment and my retention here it is. </p>
<p>We can use <em><strong>Quick Select</strong></em> to find the K-th smallest element in an unsorted array in average linear O(n) time. </p>
<h3>Here&#39;s the steps to the algo</h3><p>You pick a random element to partition. For simplicity sake I will just always select the last element in the array but in order to achieve the average complexity of o(n) you&#39;re going to be better off choosing random elements. </p>
<p>The goal of the partition is to adjust the array so every element greater than the element you selected is to the left of the array and every element greater than or equal to the element is to the right. </p>
<p>The way this works is by using two pointers initially both set to the first index of the array and increment the one of the pointers, (the j one in the graph below) at every step. Every time we increment J we are looking if the J element is greater than the partition. If it is then we swap j with wherever i is and increment i as well. We do this until we are at the partition. When we are at the partition element we swap it with wherever i currently is. Here&#39;s a visual example I drew up. (note the Exalidraw skillz). </p>
<img src="/images/quick-select/graph1.png" alt="graph1">


<p>Obviously it&#39;s pretty unlikely that we find the correct index at the first element. But what we do know after the first element is that all elements to the left of wherever the partition ended up are less than the element and all elements greater than the partition are to the right. So we can just call the function recursively on either the right or left side of the array and do so repeatedly until the index where the element ended up is correct to the k-th smallest element (with 0-based indexing this is just going to be k-1). </p>
<h3>Time complexity</h3><p>The worst case time complexity of the algorithm is going to occur when we repeatedly pick the largest or smallest element unsorted elements as the pivot, leading to one partition having n-1 elements and the other partition having 0 elements. As then we are going to have to sort the entire array to find our answer. </p>
<p>  T(n) = T(n-1) + cn <br><br>  = T(n-1) + T(n-2) + cn + c(n-1) <br><br>  = T(n−2)=T(n−3)+c(n−2)<br>  <em>we can observe a general pattern in the expansions</em><br>  = T(n)=T(n−k)+c(n−k+1)+c(n−k+2)+…+cn<br>  <em>which can be summarised as</em><br>  = T(n)=T(1)+c⋅* ((n(n+1)) / 2 )<br>  = O(n<sup>2</sup>)</p>
<p>If you haven&#39;t seen this notation before T(n) is the time to solve the problem for an array of size n, and T(n-1) is the time to solve the problem for an array of size T(n-1), which is now the case since this is the side of the partition we are going to look at next. Here <code>cn</code> represents the linear time (c for constant) to partition the array of size n. Expanding and summarising the recurrence relation shows that the worst case time complexity is going to be quadratic O(n<sup>2</sup>). This is obviously unlikely though as we would have to continuously choose the worst options. </p>
<p>The best case occurs when we partition the list into two roughly equal halves and continue with half the array.</p>
<p>  T(n) = T(n/2) + cn <br><br>  = T(n/4) + c(n/2) + cn <br><br>  = n (1 + 1/2 + 1/4 + ...) <br><br>  = 2n <br><br>  = O(n)</p>
<p>The average case (and thus the amortized complexity) of quick select can be shown to be O(n) (linear time) as we will partition log(n) times on average.</p>
<p>  T(n) = T(n/2) + O(n)</p>
<p>Solving this recurrence relation:</p>
<p>  T(n) = T(n/2) + cn <br><br>  = T(n/4) + c(n/2) + cn <br><br>  = T(n/8) + c(n/4) + c(n/2) + cn <br><br>  = ... <br><br>  = T(1) + c(n + n/2 + n/4 + ...)</p>
<p>The sum inside the parentheses is a geometric series:</p>
<p>  n + n/2 + n/4 + ... = 2n</p>
<p>which will sum up to:</p>
<p>  T(n) = O(n)</p>
<p>Showing that on average quick select takes linear time, super cool.</p>
<h3>Here&#39;s the python implementation ^_^</h3><pre><code class="language-python">
# The code for the partition

def partition(arr, l, r):
  # for simplicity we will set the partition to the last element in the array
  pivot = arr[r]
  # set i to the leftmost element of the current partition
  i=l
  # increment j one step at a time
  for j in range(l,r):
    # if the current element is less than the pivot we need to swap it with i and increment i
    if arr[j] &lt;= pivot:
      arr[i], arr[j] = arr[j], arr[i]
      i+=1
  # once we are at the partition element we swap it with wherever i currently is
  arr[i], arr[r] = arr[r], arr[i]
  # return the index of the parition element (that is now in its correct spot)
  return i


def quick_select(arr, l, r, k):
  # partition relevant part of the array
  pivot = partition(arr, l, r)
  # if the pivot is in the correct spot return the element
  if pivot == (k-1):
    return arr[pivot]
  
  # if its greater than then we need to look at the left hand side of k
  if pivot &gt; (k-1):
    return quick_select(arr, l, pivot-1,k)
  # else we need to check the right hand side
  else:
    return quick_select(arr,pivot+1,r,k)
</code></pre>
<p><a href="https://www.youtube.com/watch?v=AqMiMkPOutQ&ab_channel=CSRobot">Very Useful video</a> (whose code I stole and explains this far better than I do)</p>
]]></description>
<pubDate>Thu, 30 May 2024 00:00:00 GMT</pubDate>
</item><item>
<guid isPermaLink="true">https://www.joshshipton.com/post/exponential-opportunity-linear-improvement</guid>
<title>Opportunities increase exponentially. Skill increases linearly</title>
<link>https://joshshipton.com/post/exponential-opportunity-linear-improvement</link>
<description><![CDATA[<p>Something I have come to realise in my athletic career that is an important north star to keep in mind is that opportunities come to you when you deserve them the least. They increase on an exponential level in response to the opportunities you have gotten beforehand (granted that you made the most of them). Getting your first <a href="https://www.youtube.com/watch?v=wWO9TbT2OOk">super-fight</a> is hard but have a good performance and then the next one is easy. Have a few good performances, market yourself in a way that makes people take note and then you&#39;ll be able to teach seminars, do more private lessons, get invited to teach classes etc. etc. One opportunity can cascade into more opportunities, in which each opportunity can cascade into even more, ad-infinitum.</p>
<img src="/images/eopp-lskill/graph1.png" alt="Graph Image 1"> 

<p>The catch here is that the opportunities come when it&#39;s easiest to keep working towards them, or in other words. You get rewarded long after you&#39;ve done the hard work and sacrifice not during or directly after. The hardest time to train a combat sport consistently is either when you have just started (in which you&#39;re going to get no opportunities, recognition or anything of the like) or when you haven&#39;t seen the fruits of your labor for a long time. Any combat sports athlete whose trained at a high level for a long enough period of time will have experienced this. You&#39;re training your ass off, you&#39;re getting better than ever, but there&#39;s just nowhere to show off your skills. This can be disheartening and that&#39;s why it&#39;s so important to remember that the opportunities and fruits of your labor are going to be far far far upstream of where you are now. </p>
<blockquote><p>The longer you can do the work without getting anything in return the greater the upside will be in your return</p>
</blockquote><p>On the other hand although opportunities increase exponentially skill increases pretty linearly. (I know there are peaks and troughs but let&#39;s average it out ok), the best way to capitalize on opportunities is by having a high degree of skill, preferable a much higher degree of skill relative to the amount of opportunities you currently get. </p>
<img src="/images/eopp-lskill/graph2.png" alt="Graph Image 2"> 

<p>If you&#39;re familiar with the <a href="https://en.wikipedia.org/wiki/Elo_rating_system">elo rating system</a> you can think of skill as your &quot;true skill&quot; and the opportunities you get (super fights, seminars, etc.) as the amount of elo you have. If your true skill is far higher than your elo, then when someone gives you an opportunity (a super fight) or you create one yourself (fly to America to compete in worlds) you&#39;re going to have a much higher chance of capitalizing on it. Since your skill is much higher than your perceived level. </p>
<p>This should be the main focus for athletes, just focus on getting better. Getting better is never going to hurt your career or the amount of opportunities you get, in fact it&#39;s going to significantly increase what you can do and make of the opportunities you get.</p>
<h3>tldr:</h3><ol><li><p>Getting good is the best way to get more opportunities</p>
</li><li><p>Opportunities will present themselves far downstream of the hard-work. It&#39;s important to remember this and consistently get better. </p>
</li><li><p>Working hard while getting nothing in return will increase the upside when you eventually do get an opportunity.</p>
</li></ol>]]></description>
<pubDate>Fri, 24 May 2024 00:00:00 GMT</pubDate>
</item><item>
<guid isPermaLink="true">https://www.joshshipton.com/post/Disjoint-Set-Union-Find-Summary</guid>
<title>Disjoint Sets are really cool</title>
<link>https://joshshipton.com/post/Disjoint-Set-Union-Find-Summary</link>
<description><![CDATA[<p>Quick little post to consolidate knowledge and quickly talk about a new algorithm and data-structure that I think is really cool. </p>
<p>Disjoint set&#39;s are set&#39;s in which the union of said set&#39;s results in the empty set. Or in more normal speak, if you take all the common element&#39;s from both sets and try to create a new set then this set will be empty (the set&#39;s have no common elements). </p>
<p>We can use disjoint set&#39;s to represent things like social media networks or a network of trains. The train example is a good one to use to understand the idea. If each interconnected group of train stations is a set then these set&#39;s are going to be disjoint. It&#39;s easy to see that if we can somehow get to train station x, then we can also get to every train station from train station x. So if we can get to train station x we should add train station x (and all the stations connected to train station x) to the station that can get there (which we represent as a disjoint set). After we do this for every train station, each set is going to represent a network of interconnected trains. From this we can easily tell if you can or cannot get from one train station to another by seeing if two stations are in the same set. If they are, we can get from one to the other, if they aren&#39;t, <strong>no bueno</strong>. </p>
<p>But now the switched on observer (not me), might exclaim. But Josh! This is going to take quadratic N^2 time! First you&#39;re going to take O(N) time looking at each element and then for each element you&#39;re going to have to look at every element to see what it&#39;s connected to! This is just a naive solution with extra steps!</p>
<p>If this is you stop reading now, you&#39;re only going to get dumber reading joshshipton.com, this is way below your pay grade. </p>
<p>But that&#39;s a good point! One potential optimisation is to represent the set as a tree, and then look up the tree towards the root to see if the two elements have the same root, this is a good optimisation and would lead the find operation to take O(h) time where h is the time of the tree. But we can do even better. </p>
<p>This is where the real magic of the Union-Find part of the solution comes in, when we union our set&#39;s together we can do something magical called <em>path compression</em> which represents the nodes/elements in the set as a flat graph in which we arbitrarily choose a representative to act as the &quot;root&quot; of the graph. Or in other words, pick an element. Make every element in the set point to that element.  </p>
<img class="center" src="/images/disjoint-sets-are-cool/path-compression.png" alt="path-compression-visual"> 
  <b class="center"><figcaption>Path Compression Visual</figcaption></b>

<p>This means that if we want to check if two elements are in the same set instead of having to go all the way back up to the root, we only have to go up one element and check that two sets have the same representative. This is really fast, we are talking <a href="https://www.geeksforgeeks.org/inverse-ackermann-function/">inverse Ackerman</a> O(α(n) time. And means that the whole solution takes O(N+M * α(n)) time, where n is the amount of elements, and m is the amount of operations. This is for all practical applications constant time. (borat voice) <em>Very nice!</em>. </p>
<img src="/images/disjoint-sets-are-cool/union-find.png" alt="union-find"> 
  <b><figcaption class="center">Union Find Visual</figcaption></b>


<h4>Post Script</h4><p>I found these links really helpful when trying to understand Union-Find.</p>
<p><a href="https://l.messenger.com/l.php?u=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DayW5B2W9hfo%26ab_channel%3DPotatoCoders&h=AT2TcfdPWNsvmeONdqErMkpXt2Q99PWB9LNZH7KDfPE2PHJ41iFGXgNymPkv0hc9zCqQf-OEXsrSCX53T1OxhohmaomaoZe9C9iNanQOg8bVw0J8wzx93vnSV38ztLaUMvbIJgA">great video</a></p>
<p><a href="https://l.messenger.com/l.php?u=https%3A%2F%2Fwww.geeksforgeeks.org%2Fintroduction-to-disjoint-set-data-structure-or-union-find-algorithm%2F&h=AT2TcfdPWNsvmeONdqErMkpXt2Q99PWB9LNZH7KDfPE2PHJ41iFGXgNymPkv0hc9zCqQf-OEXsrSCX53T1OxhohmaomaoZe9C9iNanQOg8bVw0J8wzx93vnSV38ztLaUMvbIJg">handy article</a>(W3 schools goated)</p>
<h3>Here&#39;s some example code from one of my university labs</h3><pre><code class="language-python">
class UnionFind:
    def __init__(self):
        # Initialize the parent and rank sets
        self.parent = {}
        self.rank = {}

    def find(self, city):
        # Recursively find the root of the city with path compression
        # if the self.parent[city] is not the city itself then we need to find the root of the city
        # and set the parent of the city to the root of the city
        # this is done to reduce the height of the tree and make the find operation faster taking inverse Ackermann function time
        if self.parent[city] != city:
            self.parent[city] = self.find(self.parent[city])
        return self.parent[city]

    def union(self, city1, city2):
        # Find the roots of the two cities
        root1 = self.find(city1)
        root2 = self.find(city2)

        # If they are in different sets (have different roots), then you merge them together
        # we can merge the two sets by attaching the root of the smaller tree to the root of the larger tree
        # this works because the root of the tree is the representative of the set
        # and the rank of the tree is the height of the tree
        if root1 != root2:
            # Attach the smaller tree under the root of the larger tree
            if self.rank[root1] &gt; self.rank[root2]:
                # If the rank of the first city is greater than the rank of the second city, then we set the parent of the second city to the first city
                self.parent[root2] = root1
            elif self.rank[root1] &lt; self.rank[root2]:
                # If the rank of the first city is less than the rank of the second city, then we set the parent of the first city to the second city
                self.parent[root1] = root2
            else:
                # If ranks are the same, arbitrarily choose one and increment its rank
                self.parent[root2] = root1
                self.rank[root1] += 1

    def add(self, city):
        # Add a city as a new set if it&#39;s not already present
        if city not in self.parent:
            # Set the parent of the city to itself and the rank of the city to 0
            self.parent[city] = city
            self.rank[city] = 0

def trains_planes(trains, planes):
    &quot;&quot;&quot;
    Find what flights can be replaced with a rail journey.

    Initially, there are no rail connections between cities. As rail connections
    become available, we are interested in knowing what flights can be replaced
    by a rail journey, no matter how indirect the route. All rail connections
    are bidirectional.

    Target Complexity: O(N lg N) in the size of the input (trains + planes).

    Args:
        trains: A list of `(date, lcity, rcity)` tuples specifying that a rail
            connection between `lcity` and `rcity` became available on `date`.
        planes: A list of `(code, date, depart, arrive)` tuples specifying that
            there is a flight scheduled from `depart` to `arrive` on `date` with
            flight number `code`.

    Returns:
        A list of flights that could be replaced by a train journey.
    &quot;&quot;&quot;
    # Initialize the UnionFind data structure
    uf = UnionFind()

    # Sort trains and planes by date
    trains.sort(key=lambda x: x[0])
    planes.sort(key=lambda x: x[1])

    # Initialize the train index and the result list
    train_index = 0
    result = []

    # Iterate through all the planes
    for code, date, depart, arrive in planes:
        # Process all trains that are available by this date
        while train_index &lt; len(trains) and trains[train_index][0] &lt;= date:
            # Add the cities to the UnionFind data structure
            _, lcity, rcity = trains[train_index]
            uf.add(lcity)
            uf.add(rcity)
            # Merge the cities into the same set
            uf.union(lcity, rcity)
            # Increment the train index
            train_index += 1

        # Check if this flight can be replaced
        # If the departure and arrival cities are in the same set, then the flight can be replaced
        uf.add(depart)
        uf.add(arrive)
        # Use the find operation to check if the departure and arrival cities are in the same set
        if uf.find(depart) == uf.find(arrive):
            # If they are in the same set, then the flight can be replaced
            # Add the flight to the result list
            result.append((code, date, depart, arrive))

    # Return the result list
    return result
</code></pre>
]]></description>
<pubDate>Fri, 24 May 2024 00:00:00 GMT</pubDate>
</item><item>
<guid isPermaLink="true">https://www.joshshipton.com/post/knight-bfs</guid>
<title>Min Knight Moves Bfs</title>
<link>https://joshshipton.com/post/knight-bfs</link>
<description><![CDATA[<p>Lately I&#39;ve been doing a lot of dsa in preparation for technical interviews. My favorite algorithm and solution at the moment is using <a href="https://en.wikipedia.org/wiki/Breadth-first_search">bfs</a> (breadth first search) to find the optimal amount of steps to get from point A to point B following a specific rule or sequence. Examples of good problems where this solution is applicable are the <a href="https://leetcode.com/problems/coin-change/">coin change problem</a> and the classic <a href="https://leetcode.ca/all/1197.html">Min Knights</a> which I&#39;ll discuss more here. </p>
<p>The beauty of the solution lies in its simplicity. It will never search through more steps than the optimal amount of steps since it will try every single possible solution up to n (where n is the amount of steps in the best case solution). I love the fact that even though the algorithm doesn&#39;t know the solution by trying every possible solution one step in a time it will always stumble upon the best solution. It will never waste time computing steps past the optimal solution (if an optimal solution exists).</p>
<p>Take the Min knight moves problem as an example. I&#39;ll attach some sample code and walk through the solution.</p>
<pre><code class="language-python">
# Import the deque data structure from the python standard library
from collections import deque

# for simplicty sake lets assume an infite sized board, lets start at 0,0 and try to get to our destination
def find_min_moves(dest_x,dest_y):

# define all the possible moves a knight can make
    possible_moves = [(2,1), (2,-1), (1,2), (1, -2), (-1, 2), (-1, -2), (-2, 1), (-2,-1)]

    # initialize a set to keep track of squares visited
    visited = set()
    # initalize the queue with the starting point the third value is the amount of steps we are currently at  
    q = deque([(0,0,0)])

    # while there are elements in the queue we have positions to look at 
    while q:
    # get the x and y coordinates and the current amount of steps from the left of the queue
        x,y,steps = q.popleft()

    # if we have already seen x and y we don&#39;t need to look at it again
        if (x,y) in visited:
            continue
    # if we are at our destination we can return
        if x == dest_x and y == dest_y:
            return steps
    # add the current destination to visited
        visited.add((x,y))

    # try every possible move from where we currently are and append it to the queue to be looked at later
        for move_x, move_y in possible_moves:
            dx = move_x + x
            dy = move_y + y
            q.append((dx,dy,steps+1))
  
    # if we haven&#39;t found a solution we can return -1.
    # for an infinite sized board however there will always be a solution if the coordinates are valid
    return -1

# feel free to test the function
print(find_min_moves(5,3))
</code></pre>
<p>I also tried to build a way to visualize this, but my javascript is a bit rusty and it didn&#39;t work out too well. But <a href="https://min-knights-bfs-visualization.vercel.app/">here</a> it is anyway.</p>
]]></description>
<pubDate>Fri, 26 Apr 2024 00:00:00 GMT</pubDate>
</item><item>
<guid isPermaLink="true">https://www.joshshipton.com/post/bombing-technical-interview</guid>
<title>What I learnt from bombing a technical interview</title>
<link>https://joshshipton.com/post/bombing-technical-interview</link>
<description><![CDATA[<p>Today I absolutely bombed a technical interview. We are talking about levels of stuttering and brain-fog that I didn&#39;t know I was capable of. But determined to make this a learning experience and not something that happens ever again I thought I would write down the experience and what I&#39;ve learnt. </p>
<h3>About the interview</h3><p>The interview was for a summer internship (software dev) at a pretty large trading firm. This interview was the first interview after the online assessments. It was described as purely behavioural but ended up being half-behavioral half-technical (amazing bait).</p>
<h3>What went wrong</h3><p>The interview started off alright. The behavioral section was pretty standard. &quot;why do you want to work here&quot;, &quot;tell me about x&quot; , &quot;tell me about a time when...&quot; etc. I don&#39;t think it went amazing but I also don&#39;t think it went terribly. I glossed over some things, that in retrospect I should have said but had fairly-decent answers for everything. But then we got to the technical stage of the interview, and this is where I fumbled <b>hard</b>. </p>
<p>After finishing off her behavioral questions the interviewer asked me for my favorite programming language (I said python please don&#39;t judge me) and told me we would do a quick exercise. </p>
<p>The task was seemed pretty simple. The interviewer shared her screen told me to summarize what the code was doing. For context we are probably talking about 30 or so lines consisting of two classes with around 6 functions in total and a constructor. My brain stopped working immediately.  </p>
<p>Seeing a bunch of unfamiliar syntax like <code>@abc.abstractproperty</code> decorators, and words to do with network protocols that I only had a vague understanding of immediately put me in a &quot;I don&#39;t know what this is mindset&quot;. I freaked out over not understanding every aspect of the code when in retrospect I probably knew enough to give a decent answer. </p>
<p>What I should have done and what I think would have been perfectly fine would be to answer the question as best as I could whilst telling my interviewer that I didn&#39;t understand some parts of the syntax and code but make an educated guess as to what it was probably doing. This would have been far better than what I actually did (feel free to laugh or tease me), which was ummmm, ahhh and say &quot;sorry I don&#39;t know&quot;.  </p>
<p>Eventually after bombing the first 3 questions I found my stride, still answering in an unsure tone but giving more coherent answers that were probably correct. But by then it was too late, the interviewer gave curt replies and it was clear that the rest of the interview was nothing but a formality. </p>
<h3>What I learnt</h3><ul><li><p>If you don&#39;t know you don&#39;t know. But try to answer anyways. Asking questions and giving an educated guess is far better than giving up</p>
</li><li><p>Be confident the entire time, don&#39;t let things phase you or lose your stride</p>
</li><li><p>Your entire &quot;story&quot; for behavioral interviews should be written out to make sure that you communicate yourself, your achievements and your background to the interviewer in the most clear, efficient way possible.</p>
</li></ul><h3>What I&#39;m doing for next time</h3><ul><li><p>In the past I&#39;ve practiced my replies for common behavioural questions (<a href="%22/behavourial_questions%22">list here</a>) but never for questions like &quot;tell me about your background&quot; , &quot;tell me about x club at university&quot; etc. assuming that if asked these questions I would just be able to answer them. But writing out model answers really helps improve the clarity of your response. So I&#39;m going to be more thorough with this next time. </p>
</li><li><p>More mock-interviews with friends that isn&#39;t just DSA. <b>Big one</b>, been going hard on the DSA for a while, time to branch out a bit more.</p>
</li><li><p>Practice communicating technical ideas, I&#39;m giving some lectures on algorithms at my university in the next few weeks. I&#39;m going to use this as an opportunity to get more competent with formal technical discussion. Shooting the shit about my favorite web-framework with the lads = easy peasy, doing it formally != easy peasy. I talk rubbish and give strong opinions about things I saw once on Reddit with my friends all the time but communicating formally is something I do far less often. To improve this I&#39;m going to look for more opportunities to be forced to talk formally about technology.</p>
</li></ul>]]></description>
<pubDate>Tue, 09 Apr 2024 00:00:00 GMT</pubDate>
</item><item>
<guid isPermaLink="true">https://www.joshshipton.com/post/Ad-Santel</guid>
<title>Heroes from History: Ad Santel</title>
<link>https://joshshipton.com/post/Ad-Santel</link>
<description><![CDATA[<p>Stumbled upon this guy when doing some research into the origins of catch-wrestling and thought he was awesome.</p>
<p>Ad Santel or his real name Adolph Ernst was one of the greatest practitioners of catch wrestling. The coolest aspects of his life can be summarised as </p>
<ul><li>World Light Heavyweight Catch Wrestling Champion</li><li>Wants to challenge himself more</li><li>Decides to challenge the best judoka in the world <strong>in their own rule set</strong> </li><li>Wins</li><li>Declares himself Judo World Champion</li><li><a href="https://en.wikipedia.org/wiki/Kan%C5%8D_Jigor%C5%8D">Jigiro Kano</a> gets irritated and sends more of his best practitioners </li><li>Santel <u><strong>keeps winning</strong></u></li><li>Kano gives up and stops sending people</li><li>So Santel decides to travel to Japan to fight more judoka</li><li>He wins one match and draws another. But the Japanese people are so fascinated that is sparked a new age of catch-wrestling in Japan.</li></ul><p>Highly recommend his <a href="https://en.wikipedia.org/wiki/Ad_Santel">Wikipedia page</a> as a starting point if you want to read up on him. A great example of a well rounded grappler with crazy confidence. Somehow I had never heard about this guy but now he&#39;s my new hero</p>
<div class="flex justify-center">
  <img src="https://upload.wikimedia.org/wikipedia/commons/1/1b/Ad_Santel.jpg" alt="Picture of Ad Santel">
</div>

<p class="flex justify-center font-bold text-md" >The chad himself</p>]]></description>
<pubDate>Tue, 02 Apr 2024 00:00:00 GMT</pubDate>
</item><item>
<guid isPermaLink="true">https://www.joshshipton.com/post/software-for-grappling</guid>
<title>Software for grappling</title>
<link>https://joshshipton.com/post/software-for-grappling</link>
<description><![CDATA[<p>Grappling is my obsession and has been for the last few years. I’m also very interested in software, especially in how software can be used to improve human performance .</p>
<p>I am convinced that there are numerous ways that software can improve human performance in combat sports, since my focus is grappling sports such as wrestling, submission grappling and Judo I’ll focus my scope on these rule-sets. </p>
<p>All software can be condensed as processing and presenting information, what information can we process and present to help athletes improve faster and train smarter? Here are some examples of projects I know of and projects that I would like to see. </p>
<p>Current projects that i know of </p>
<h4>Learning management platforms</h4><p>There are countless examples of these, I feel at the moment <a href="https://submeta.io">submeta</a> is leagues above everyone else with its roadmaps and super crisp front-end. </p>
<h4>Move databases</h4><p><a href="https://outlierdb.com/">Outlier Database</a></p>
<p>Projects like this are tedious to create but I could see them providing a ton of value. Some things to improve would be accessibility and consistent UI and labeling. </p>
<h4>Graphical</h4><p><a href="https://github.com/Eelis/GrappleMap">code</a><br><a href="https://eel.is/GrappleMap/index.html">Try it here</a></p>
<p>Cool graphical tool to experiment with different move combinations. Not sure how useful this is but its super cool to play around with</p>
<h4>Digital (smart journals)</h4><p><a href="https://kenku.org">Kenku</a> was built by me. It offers a digital training journal. Digital journals have the benefit of being far more indexable than traditional paper journals. Is still a work in progress but is available for anyone to try. If you want to learn more read <a href="https://www.joshshipton.com/post/kenku-13-01-2024">this</a></p>
<h4>Elo ranking systems</h4><p>People have scraped BJJ heroes and other sites that store match results and then used some math to create an elo rating to objectively rank the top BJJ practitioners. I think that projects like this have a lot of potential. </p>
<p>Good use cases I can think of are in sports like Judo were qualifying points are very important. Projects like this could be used to calculate the average elo at certain competitions and then optimize for the competition that has the highest amount of qualifying points with the lowest elo competitors. </p>
<p><a href="https://github.com/rdreese89/Analysis-on-2022-BJJ-Fight-Data">code</a></p>
<h2>Projects that I would love to see</h2><h4>AI referees for Judo</h4><p>Simple, train a model on a ton of Judo throws. Get the model to a point where it can classify a throw as no-score, wazari or Ippon. There is way too much subjectivity at high-level judo competition for an aspect of the rule set which I believe has some of the most objective criteria. (1-shoulder = wazari, 2 shoulders = ippon, no shoulders = no score )</p>
]]></description>
<pubDate>Sun, 31 Mar 2024 00:00:00 GMT</pubDate>
</item><item>
<guid isPermaLink="true">https://www.joshshipton.com/post/allocating-tasks-based-on-mental-energy</guid>
<title>Allocating tasks based on mental energy</title>
<link>https://joshshipton.com/post/allocating-tasks-based-on-mental-energy</link>
<description><![CDATA[<p>One of the things I&#39;ve found trying to train like an elite athlete and still grind personal projects and code cocurrently is sometimes I&#39;m dead tired which leads me to be less productive behind my keyboard. One of the ways I&#39;ve worked around this is by allocating tasks based on my mental energy, this assures that there is always &quot;something to do&quot; and no time that could be spent programming is wasted. Here are the 5 categories that I believe make up 95% of projects, sorted by taking the most mental energy to the least.  </p>
<h3>Thinking about what features to implement/add</h3><p>I think that this is the hardest thing to actually sit and do, it seems easy but you need to make sure that what you&#39;ve decided on is worth invested time into and also that it&#39;s something that is actually needed. Big decision so I don&#39;t try and do it unless I have the energy to do so. </p>
<h3>Thinking about how to implement a feature</h3><p>Quite hard depending on the feature but I really feel as though this is the brunt of the work and bears the most cognitive load. Involves doing research, reading other peoples code that achieves something similar and playing around with different posibilities. During this step its important to map out every thing that needs to be done to achomplish the task sequentially and in detail. You dont want to just leave this information in your brain you want to put it somewhere.</p>
<h3>Actually implementing the feature</h3><p>If you;ve done the prior step well this is actually really easy. If its not easy you need to go back and spend more time in the previous step. This might be a hot take but I believe that if the implementation isnt easy you havent spent enough time thinking about the implemenation and its a sign that things are going to go downhill very fast very soon. </p>
<h3>Fixing little backend bugs</h3><p>Through me and my users using my projects I find little bugs from time to time, nothing breaking but things that would just be nice to fix. These are usually quite easy to fix so as long as theyre not breaking the application I save them for when I&#39;m tired as nice easy wins to keep momentum. </p>
<h3>Fixing front-end or UI bugs</h3><p>Same as the previous point but even easier. Nowadays most front-end bugs can be fixed by describing what you want in good detail and asking a certain tech-overlord very nicely. Of course review the code nicely and iterate on it either by yourself or with more prompts but this is quite easy. If they&#39;re not complying just figure it out youtself or steal some components. It&#39;s more of a &quot;take some time and patience thing&quot; than a &quot;think logically and use your brain intensly thing&quot; so I do this when I&#39;m my most tired.</p>
]]></description>
<pubDate>Fri, 09 Feb 2024 00:00:00 GMT</pubDate>
</item><item>
<guid isPermaLink="true">https://www.joshshipton.com/post/hormozi-confidence-notes</guid>
<title>Notes on confidence</title>
<link>https://joshshipton.com/post/hormozi-confidence-notes</link>
<description><![CDATA[<p>Today I was watching <a href="https://www.youtube.com/watch?v=pt50QF6al8g&ab_channel=AlexHormozi">this video</a> from Alex Hormozi, Alex is a bit of a &quot;business guru&quot; on YouTube but personally I see him more of a philosopher and see his advice as beneficial to general life instead of to the specific endeavor of Business. I thought the video had some great ideas. Since I don&#39;t want to forget these good ideas I started taking notes on some of the ones that stuck out to me the most. These are those notes.</p>
<h3>Don&#39;t build confidence without evidence</h3><p>Confidence without evidence is an illusion, you&#39;re tricking yourself into being confident even though you don&#39;t have the backing to support your beliefs. This is pretty much lying to yourself. Confidence without evidence is an illusion, you should do things so you become confident, <u>You shouldn&#39;t wait until you&#39;re confident to do things</u>. Fake it till you make it should become &quot;walk it before you talk it&quot; prove it to yourself so you don&#39;t have to prove it to others, let your path do your talking for you.</p>
<h3>Solve for proof</h3><p>The message is 10% of how people perceive what you say. <u>Context is everything else</u>. Example of Elon being able to tweet whatever he wants and it going crazy. The context of Elon and everything he has achieved allows him to do this. Solve for evidence over everything else. If a billionaire is giving business advice someone can&#39;t say &quot;you don&#39;t know anything about business&quot; because objectively they do. Even if what they&#39;re saying is wrong, people or someone else is saying the same thing without the credentials but communicating it better will listen to them just because of what they&#39;ve done.</p>
<h3>Measuring</h3><p>Don&#39;t measure by results, measure by effort. If someone is doing better than you, compare your input to their input (what they&#39;re doing to get that result) and not their output. The output is irrelevant because it&#39;s the input that really matters. If you&#39;re putting in a greater amount of input than someone else over a long enough time period the output&#39;s will start to reflect the relative inputs. The greater the difference between the inputs the faster the outputs will change.</p>
<h3>Lagging metrics vs lagging metrics</h3><p>lagging metrics = what happens (outputs)<br>leading metrics = the inputs that create the outputs</p>
<p>Track leading metrics not lagging metrics. Don&#39;t track your weight, track your calories. etc. etc.</p>
<h3>the Delta between what you did and what you could have done</h3><p>Focus on the delta between how hard you try and how hard you can possibly try. The gap between these two values is all that matters because it&#39;s all that you can control. You should redefine your concept of  &quot;winning&quot; to how small the difference between these two deltas is. Because at the end of the day that&#39;s all you can control. It&#39;s also more immediate, you see results straight away, this makes it far more motivating to stick with.</p>
<h3>By default if you don&#39;t give up, you win</h3><p>The best games are ones where there isn&#39;t an end goal.The goal is just to keep playing business, marriage, being healthy are all like this. So by definition if you stay in the game you&#39;re winning. He uses an example of Kobe being asked &quot; do you think you&#39;re someone who is afraid of winning or someone who loves losing&quot; and him replying &quot;I just love playing to the best of my ability&quot;. There aren&#39;t two frames “winning&quot; or &quot;losing&quot; this is a false dichotomy. As long as you&#39;re playing you&#39;re winning by default. If you change your definition of winning to be reliant on your character, and judge your days based on this, as long as you contributed to the character of the person that you wish to become, then you won the day.</p>
<h6>Bunch of great one liners in this section</h6><blockquote><p>if you have the menu item of things you can do in life, just remove quitting as one of them and then try your next thing.<br>The rocky cut scene in the move lasts 2 minutes in real life it lasts a lot longer<br>this is where most people stop, and this is why they don&#39;t win<br>if you play to win you&#39;ll be out first. play to outlast and you&#39;ll win.</p>
</blockquote><h3>Other people&#39;s opinions</h3><p>The best thing you can do for your own life is not to listen to other people&#39;s opinions about your life. Most people don&#39;t want the best version of you. They want the version of you who best suits them. More people root for you when you have succeeded than people who rooted for you along the way.</p>
<p>Whenever someone gives you an opinion of what you should do with your life it&#39;s really what they want to do with their life. People make statements to release their discomfort e.g &quot;you should train less&quot; &quot;your standards are too high”  etc etc. and that&#39;s their problem not yours so dont worry about it.</p>
<h3>I am statements</h3><p>People like saying they are things and then love giving a &quot;because&quot; reason...</p>
<p>The “because” adds nothing, and most of the time you don&#39;t even know why you are that way and you&#39;re just guessing. All you know is that you do a certain type of behavior. By giving these “because” statements power you put things in the past. if you change the mentality to &quot;I do x&quot;. then you just change your day to day behavior and give the control to your present self.</p>
<h3>Epic stories razor</h3><p>When choosing between two or more options choose whatever will create the cooler story. Reframe &quot;these are all the reasons that i can&#39;t succeed&quot; to. &quot;These are all the reasons why when I succeed it will be awesome.</p>
<h3>Heroes vs villains</h3><p>heroes and villains in stories always have the same backstory - pain. The difference is what they choose to do about it. The villain says &quot;the world hurt me, i&#39;ll hurt it back&quot;. The hero says &quot;the world hurt me, I&#39;m not gonna let it hurt anyone else&quot; Heroes use pain. Villains are used by pain.</p>
<p>Everyone inevitably feels pain. It&#39;s a constant of life, you just have to choose how you deal with it. </p>
<h3>Document your life</h3><p>Document your life when it sucks, not when it&#39;s great. Because these are the moments that you can use in the future to prove who you really are. Quote from the matrix </p>
<blockquote><p>I stand here truthfully unafraid. Not because of the path that lies before me but because the path that lies behind me - Morpheus</p>
</blockquote><p>The struggle or hardship that you might be facing right now is the path that your successful future self looks back on to be confident in whatever path lies in front of them.</p>
]]></description>
<pubDate>Fri, 02 Feb 2024 00:00:00 GMT</pubDate>
</item><item>
<guid isPermaLink="true">https://www.joshshipton.com/post/post-content-clarity</guid>
<title>Post Content Clarity</title>
<link>https://joshshipton.com/post/post-content-clarity</link>
<description><![CDATA[<h3>Post content clarity</h3><p>Short summary of a framework from <a href="https://www.youtube.com/@ChrisWillx">Chris Willaims</a> that&#39;s been super useful in my day to day life.</p>
<p>I all too often find myself consuming content that I don&#39;t actually want to be consuming or that I regret watching afterwards. Chris explains that the reason this happens is because the heuristic most people use when deciding what content to consume is &quot;is this captivating or not&quot;. Not only does this optimize for the wrong thing (short term pleasure &gt; long term benefit) but also anything you&#39;re watching is always going to be captivating because if it wasn&#39;t then you wouldn&#39;t be watching it. </p>
<p>The framework Chris suggests to use to combat the problem of content captivity is to either before consuming or whilst consuming content <u>project yourself into the future to after you&#39;ve consumed the content</u>. He calls this &quot;Post Content Clarity&quot; as only after you&#39;ve consumed a piece of content and it&#39;s stopped grabbing your attention can you really assess its impact. I&#39;ve found this super useful in order to stop my attention being stolen by whoever is the most bold, eccentric and aggressive and instead make sure it&#39;s being given to whoever is the most interesting and beneficial.</p>
<h4>Example</h4><p>I start watching something, I realize that after watching this I&#39;m probably going to feel worse about the future of our species. I turn it off. I see another video, I realize that after watching it I&#39;ll be more informed about a topic I care about. I press on the video.  </p>
<p>I&#39;ll end this little summary with one of my favorite quotes from Chris.</p>
<blockquote><p>“Your content diet should be spirulina for the soul, not fast food for your amygdala.”</p>
</blockquote>]]></description>
<pubDate>Wed, 31 Jan 2024 00:00:00 GMT</pubDate>
</item><item>
<guid isPermaLink="true">https://www.joshshipton.com/post/spaced-repetition-kenku</guid>
<title>How I&apos;m doing spaced repetition for grappling at kenku.org</title>
<link>https://joshshipton.com/post/spaced-repetition-kenku</link>
<description><![CDATA[<p>To be totally honest, at the moment, I don&#39;t really know what I&#39;m doing. I&#39;ve got a rough version working, but it&#39;s far from optimal. I thought I would write this to try to figure it out for myself, consolidate my knowledge and see if anyone else has any ideas. </p>
<h3>What is <a href="https://en.wikipedia.org/wiki/Spaced_repetition">spaced repetition</a>?</h3><p>If you&#39;ve ever used anki. That&#39;s spaced repetition. If you&#39;ve never used anki, think of spaced repetition as the most effective way to remember things. Flashcards on algorithmically enhanced steroids that make sure you review things at the optimal intervals to deliver <a href="https://www.edapp.com/blog/evidence-around-spaced-repetition/">enhanced learning</a>. </p>
<h3>How it works</h3><p>If you&#39;re trying to learn something by committing it to memory, it&#39;s been proven that the best time to review something is <strong>just</strong> before you forget it; if you review something straight after learning, that&#39;s too easy, but wait too long, and you can&#39;t review it at all. </p>
<p>Our brain forgets things on a curve, appropriately called the <a href="https://en.wikipedia.org/wiki/Forgetting_curve">forgetting curve</a>. In our use-case we are recommending grappling techniques to the user. We can use this forgetting curve to figure out when to recommend users review techniques at the optimal time. To do this we need to model the forgetting curve. This can be broken down into two steps.</p>
<ul><li><p>One. Model how memorable that a certain technique is to a user(the more memorable, the longer they will remember it without review).</p>
</li><li><p>Two. Figure out how good a certain user is at remembering things. Some people are going to have inherently worse or better memories than others; for them, I will have to adjust the <a href="https://en.wikipedia.org/wiki/Decay_theory">rate of decay</a> in the algorithm accordingly.</p>
</li></ul><p>Ultimately, a good spaced repetition algorithm would quickly determine how memorable something is to a user and how good the user&#39;s memory is based on how well they have recalled techniques in past reviews. It would then use this information to recommend techniques at the optimal time.</p>
<h3>Why is this useful for Sports?</h3><p>Good question. Unlike sports where the win condition is based purely on physical prowess (think swimming, running etc), grappling is a sport with a large cognitive component. Being analytical and cerebral is an important asset and to cultivate these attributes athletes study for hours outside of training, they also practise and play around with moves until they understand every small detail. Just like studying for academic subjects, consistency plays a huge role. It doesn’t make much sense to study one thing for 10 hours straight and never touch it again. But knowing when to work on what is difficult. This feature of kenku.org hopes to direct users when they should study and review certain techniques to help them learn faster and better.</p>
<h3>Problems with relation to Kenku.org</h3><ul><li><p>I&#39;m working with skills that aren’t strictly cognitive but also have a kinesthetic component. The forgetting curve for kinesthetic skills <a href="https://pubmed.ncbi.nlm.nih.gov/36321731/">is slightly different</a> and depends heavily on how the skill is learned and practised.</p>
</li><li><p>I don&#39;t have quantitative data; I can&#39;t just look at the user doing the technique and tell them if they&#39;re doing it right or wrong. I can&#39;t even look at them, period. I need to rely on their self-reporting of how well they believe they practised the technique.</p>
</li></ul><h3>What data I do have.</h3><p>I can infer quite a bit of data based on the single rating users give after they have reviewed a technique given in the form of a self-report from 0-100. From this single rating, I store data on; average rating, amount of time successfully reviewed (reviews higher than 65/100. Communicated to the user through the UI), amount of times reviewed in total, user average review score, time since last review and more.</p>
<p>Using this data I calculate a “review score” This is  used to rank how well the user knows a specific technique in comparison to their other techniques. Additionally I run a cron job daily that simulates memory decay, this is an exponential function that recalculates the review-score taking into account memory decay over time. The idea being that techniques that you know better will decay slower than techniques that you don’t know as well. That part of the function looks something like this:</p>
<div class="bg-gray-100 p-4 rounded shadow py-2 px-1"> <code> review_score = review_score * e^(-(user_decay_rate) * time_since_last_review) </code> </div>

<div class=”pt-4”>
To finish it off and make this accessible to the user when they set their intentions for their training sessions I simply fetch the 6 techniques with the lowest review score and suggest these for review before a session. Of course, the user can also select any of the techniques they have recorded within the application to review themselves. Reviewing any techniques whether they were suggested or not impacts their review score. At the end of the day this algorithm is nothing more than a way of suggesting techniques to the user, it’s not meant to replace a coach or their own intuition but I hope it can provide some sort of value to my users.
</div>

<h3>In conclusion</h3><p>This is a hard problem. A problem that might not even have a solution. But for now, I&#39;m enjoying thinking about and working on it. It feels good to have no restraints and take a problem in whatever direction I want to. If you have any ideas or insights, please email me <a href="mailto:shiptonjosh@gmail.com">here</a>. I would love to hear from you.</p>
]]></description>
<pubDate>Thu, 18 Jan 2024 00:00:00 GMT</pubDate>
</item><item>
<guid isPermaLink="true">https://www.joshshipton.com/post/kenku-13-01-2024</guid>
<title>Every feature kenku.org currently has</title>
<link>https://joshshipton.com/post/kenku-13-01-2024</link>
<description><![CDATA[<p>This post is intended to talk about what <a href="https://www.kenku.org/">kenku.org</a> offers; it also acts as an onboarding guide for new beta-users. I expect this to change over time as I continue working on the project. For those who don&#39;t know what kenku.org is, it&#39;s my current project that intends to be a kind of smart-journal for grappling sports. Helping athletes keep track of, and manage their training sessions. It&#39;s currently in private beta. </p>
<h2><a href="https://www.kenku.org/pre-session">Pre-Session</a></h2><p>Designed for use before a training session, this section helps set <a href="https://www.thespotathletics.com/blogpage/training-with-intention">intentions</a> before a session to help you train with a structured purpose. Features include:</p>
<h3>Set your drilling techniques</h3><p>Here you can set your techniques for the session (what you want to drill/work on). If you haven’t logged any techniques yet go to <a href="https://www.kenku.org/log-new-technique">kenku.org/log-technique</a> to add some of your techniques to the application. Once you’ve done that you can go back and set the techniques that you have saved as things you want to work on in the session. Over time as you log more and review more techniques kenku.org will start to get better at recommending what you should drill based on a <a href="https://www.kpu.ca/sites/default/files/Learning%20Centres/Think_SpacedRepetition_LA.pdf">spaced-repetition algorithm</a> that models <a href="https://en.wikipedia.org/wiki/Decay_theory">memory decay</a> over time. This is intended to save you from forgetting things and also help new techniques stick faster. </p>
<h3>Set your goals</h3><p>Here you can also set your goals for the training session. If you don’t know what goals to set you can also “generate Ai goals” these can be finicky but get better over time the more sessions you log. Particularly the more you log “things to work on” in your post session. </p>
<h2><a href="https://www.kenku.org/log-new-session">Post-Session</a></h2><p>Here you can record a bunch of data about your session, if you filled out a pre-session form this is the time to reflect on how you went with the techniques you wanted to work on and goals you set. This data will be used in future “pre-session” forms to give you more accurate recommendations for techniques and goals</p>
<p>Here you can also log sparring rounds, you can log quantitative data about the rounds, things like how many rounds you did, how long the rolls were or the intensity of the rolls. You can also log qualitative data about certain positions or certain partners, things like ideas for certain partners in the future, or what you struggled with from a certain position. </p>
<p> At the moment the qualitative data only exists for personal review and can be accessed any time in the “session-bank” section of the application. Eventually I’ll work on drawing insights from this kind of data for you. </p>
<h2><a href="https://www.kenku.org/insights">Insights</a></h2><p>Get quantitative data about your sessions. Can sort by time periods to see quantitative data over a set time period. Things like sessions done over the last month, time spent sparring in the last week, etc. </p>
<h2><a href="https://www.kenku.org/log-new-technique">Log-technique</a></h2><p>Used to save techniques, you can add things like tags, concepts and steps to make sure the technique is findable later and also so you can detail every aspect of the technique to make sure your record is accurate. This is editable later so you can always come back and add more detail or change stuff around. </p>
<h2><a href="https://www.kenku.org/session-bank">Session-bank</a></h2><p>Storage of every session you have ever done, can use the search bar in the top right to find a specific session. </p>
<h2><a href="https://www.kenku.org/technique-bank">Technique-bank</a></h2><p>Storage of every technique you have ever recorded, can use the search bar in the top right to find and edit a specific technique. </p>
<h2>Other</h2><p>Mobile friendly<br>Unlimited sessions and technique storage for everyone<br>Secure data, your data is yours and yours only (also feel free to request a copy of it at any time)</p>
<h2>Future features</h2><p><strong>things I am working on or am planning to add in the future</strong></p>
<h3>Weekly recap</h3><p>A weekly recap of your training sessions with suggestions for the next week</p>
<h3>What to work on with certain techniques</h3><p>Based off your comments on reviewing the technique in the past we will give you things you need to work on when you review a technique</p>
<h3>Flow-charts</h3><p>Create flow charts and game-plans with your logged techniques for positions, partners or just in general</p>
<h2>Thank You</h2><p>A huge thank you to all the beta-testers. You make this worth it, thanks for being so patient and kind. Your insightful suggestions blow me away. If you aren&#39;t a beta-tester but would like to be one please <a href="mailto::shiptonjosh@gmail.com">email me</a></p>
]]></description>
<pubDate>Sat, 13 Jan 2024 00:00:00 GMT</pubDate>
</item><item>
<guid isPermaLink="true">https://www.joshshipton.com/post/pots-by-hand</guid>
<title>I miss making pots by hand</title>
<link>https://joshshipton.com/post/pots-by-hand</link>
<description><![CDATA[<p>I miss coding pre-chatpgt. It&#39;s an amazing technology but I’ve realized that using it over the last year has severely negatively impacted my skills as a programmer. Moreso,  it seems like we’re heading into a future where the large majority of code is AI generated. To me this seems like going from artisans making pots by hand to Ikea making thousands of (almost) indistinguishable pots at the same time. And although the end-product is usually totally removed from the code (the user doesn’t care how you implemented the search function) <u>I care</u>.</p>
<p> As a result I’m going back to programming by hand, canceling my gpt-4 subscription and only using gpt as a time-saver for menial tasks, not as something to come up with ideas or write functions for me. Most of the time when I use chat gpt to do things for me it&#39;s not perfect but it’s “good enough” and I’ll accept the impacted quality or confusing-roundabout way of doing something for the sake of convenience and fact that I don’t care enough about the sanity of my future self trying to understand what something does. </p>
<p>You might argue that there’s no point in any of this, even learning to program is a waste of time because there&#39;s a chance that programming as we know it won&#39;t even exist in 10 years. Personally I don’t think anyone can predict the future but even if that’s true I can&#39;t imagine any possible future were someone that can think logically, focus for long periods of time and has a strong knowledge of programming concepts (DSA, software architecture, computer systems, etc) will be worse off than someone who doesn’t. If you’re really autistic you can even turn this into a sort of <a href="https://en.wikipedia.org/wiki/Pascal%27s_wager">Pascal&#39;s Wager</a></p>
<h3>Scenario 1, AI takes over</h3><p>No change and nothing you did beforehand really matters anyways, do whatever you want</p>
<h3>Scenario 2, Humans still contribute to society</h3><p>Person who actually spent time learning &gt;&gt; smoothbrain prompt engineer </p>
<p>And at the end of the day It’s also just so much more fun and rewarding to program and solve problems on your lonesome, instead of begging some tech overlord to give a coherent answer.</p>
]]></description>
<pubDate>Tue, 09 Jan 2024 00:00:00 GMT</pubDate>
</item><item>
<guid isPermaLink="true">https://www.joshshipton.com/post/caffeine-psychedelic</guid>
<title>Using Caffeine as a psychedelic</title>
<link>https://joshshipton.com/post/caffeine-psychedelic</link>
<description><![CDATA[<p>For context: I drink a lot of caffeine and like a lot of people have developed a bit of a tolerance. I estimate my daily intake is anywhere from 120-300mg everyday.</p>
<h4>There were a couple things that started to annoy me about developing a tolerance.</h4><ul><li>Caffeine was less effective</li><li>I needed a certain amount of caffeine to hit my “baseline”</li></ul><p>I realized that if I need something to hit baseline then it’s not really helpful anymore. Sick of my reliance on and tolerance of caffeine I decided to take a two week cold-turkey break from all sources including things like chocolate and soft-drink.</p>
<p>The first few days were surprisingly difficult. I felt like a bit of a vegetable but it didn’t take long (maybe 3-4 days) for my body to adapt and after that I was functional. </p>
<p>Two weeks later I decided to reintroduce caffeine. I had been stuck on a conceptual problem with kenku.org for the last few weeks and didn’t know the best way to solve the problem. Armed with a cup of coffee and hopefully less <a href="https://pubmed.ncbi.nlm.nih.gov/1888264/">adenosine receptors</a> I decided that today was going to be the day. I opened my laptop, booted up my editor (vim btw) and started sipping the elixir of the gods. I was ready to get to work. The first sip was a crescendo of pleasure, my senses rejoiced at their favorite molecule entering the system and I quickly had another sip, and another, and another. The coffee didn’t last very long. It only took a few minutes to feel the effects and oh my, was it beautiful. I felt like a cognitive god. I’ve never taken meth but this is what I assume meth would feel like. My brain was running at 100km/h and almost instantly I saw a solution to the problem I had grown so frustrated with. I had spent so much time on this problem that it started to hurt to think about in depth but now it was so simple. I can just do x, y and z and then it’s done, that fixes everything. I instantly got to work and within two hours I was done. What shocked me was how quickly I had come up with a solution, it must have already been at the back of my mind but the caffeine had brought what was in the subconscious into the conscious, I imagine that this is how psychedelics work.</p>
<p>I think that the best thing I did here was that</p>
<p> I went into drinking the cup of coffee with the intention of solving this problem</p>
<p>which i think was super important and something I want to try again in the future. </p>
<p>now that I have less of a tolerance I also want to try to keep it this way for longer so heres</p>
<h4>what i’m doing in the future to get the most out of caffeine</h4><ul><li><a href="https://www.liveholos.com/blogs/journal/the-90-minute-rule-that-could-change-your-mornings">waiting 90 minutes</a> before consuming it in the morning</li><li>not consuming caffeine two days in a row, i can consume whenever i want and in whatever dosage, but I can’t drink caffeine more than two days in a row. I&#39;m hoping this stops my brain from developing too much tolerance.  <em><strong>life hack for this</strong></em>. just drink decaf. Not totally caffeine free but has 1/10th of the amount of caffeine and your brain thinks it’s the same thing. Amazing.</li></ul>]]></description>
<pubDate>Thu, 04 Jan 2024 00:00:00 GMT</pubDate>
</item><item>
<guid isPermaLink="true">https://www.joshshipton.com/post/kenku-week0</guid>
<title>What I&apos;ve learnt the first week of programming my &quot;startup&quot;</title>
<link>https://joshshipton.com/post/kenku-week0</link>
<description><![CDATA[<p>I wanted to write a post about what I&#39;ve been doing in my first week of university break.</p>
<p><a href="https://kenku.org">Kenku</a> (Currently Beta testers only) is an application that I&#39;m busy developing that hopes to help combat sports athletes better manage their training sessions and streamline their learning and skill acquisition. I see it as a mobile app in the future but for now I&#39;m building it on the web with the SuKit stack (hosted on Vercel) to minimize developer rage and maximize iteration speed. I really believe that iteration speed is everything when building a project, you need to be able to pivot or abandon features whilst losing as little time as possible.</p>
<h3>Key Takeaways From the first week</h3><ul><li><p>Nothing feels better than making something, solving problems and being engrossed in a problem for hours on end</p>
</li><li><p>If you think AI is going to replace you, you have a skill issue. Chat-GPT is a child with instant access to the internet who can also talk really fast. It knows a lot but it makes stupid mistakes and often gives sub-optimal solutions to simple problems. I&#39;ve found using it for anything more than boiler-plate to be more time-consuming than just writing the code by myself.</p>
</li><li><p>You can never go wrong with reading the docs</p>
</li></ul><h3>Things im struggling with,</h3><ul><li><p>UI design. This is hard, like really hard. Going to have to invest a good amount of time into learning how to make an intuitive, user friendly frontend.</p>
</li><li><p>Treading the line between complexity and simplicity. Great software has value in its ability to do complex things, doing complex things simply is the goal but doing complex things simply is hard. It&#39;s usually far easier and faster to do complex things in a complex way. Not sure what the solution is here, probably just a skill issue to be honest.</p>
</li><li><p>Direction. It&#39;s hard to figure out what features I want to invest the most time into fleshing out. Or what I should be working on at any given moment. Probably need to take some time to really plan out the entirety of the application instead of just having a rough idea in my head.</p>
</li></ul>]]></description>
<pubDate>Fri, 10 Nov 2023 00:00:00 GMT</pubDate>
</item><item>
<guid isPermaLink="true">https://www.joshshipton.com/post/opinions</guid>
<title>Why you should outsource your opinions</title>
<link>https://joshshipton.com/post/opinions</link>
<description><![CDATA[<p>Epistemology is fucked. Knowing things, and knowing that you know things is really hard. After learning about <a href="https://en.wikipedia.org/wiki/Philosophical_skepticism">philosophical skepticism</a>, <a href="https://plato.stanford.edu/entries/induction-problem/">induction</a> and other brain-breaking <a href="https://plato.stanford.edu/entries/perception-episprob/">epistemological problems</a> in university. I adamantly decided that since knowing things was impossible I was just going to start believing in whatever I thought was cooler. I quickly became a flat earther just because I thought the notion that <a href="https://en.wikipedia.org/wiki/World_Turtle">the world rested on a turtle&#39;s back</a> was way cooler than whatever round-earth solar-system jargon nasa was perpetuating. Since I thought no one could prove that they knew anything at all, let alone that the world was round I was perfectly at ease with my new opinion.</p>
<p>However I&#39;ve since matured (marginally so), and now believe that it&#39;s sometimes best to throw philosophy out the window if you want to be a functioning member of society. Sometimes it makes sense to have opinions that are rooted in facts. But the problem is that even if you forget the induction, skepticism and the rest of the brain-fuckery, it&#39;s still insanely hard to justify any one opinion over another. Who do you believe? Is this food good or bad for me? Is this study method more effective than this one? Should I learn Rust? Ad infinitum. Where do you get your opinions from? How do you know that what you&#39;re consuming is grounded in fact and not propaganda. Before I explain my current framework for opinions there&#39;s something, you should think about to think about.</p>
<p><u><div class="center underline font-bold text-xl py-2 my-2">Think about if you really need to have an opinion about this thing.</div></u></p>
<p>An idea that has immensely increased my wellbeing is that you don&#39;t need to have an opinion about everything. Sometimes it makes the most sense to just not have an opinion about said thing. There are a number of reasons for this, sometimes it&#39;s just not worth the time and energy researching the topic. Sometimes you don&#39;t really care about the topic. Or sometimes it&#39;s a polarizing topic that you don&#39;t want to be on either side of. If you don&#39;t feel strongly about a controversial issue, you don&#39;t have to pick a side. You can be Switzerland, understand that the issue is delicate and people feel strongly about both sides. Recognize both opinions, but don&#39;t hold one in higher regard than the other. There&#39;s also a huge social benefit to this. By not having an opinion about a polarizing topic you don&#39;t run the risk of adding unnecessary friction between yourself and someone with an opposing opinion. If you don&#39;t feel strongly about something what&#39;s the point of risking that friction anyways?1</p>
<p>But sometimes you want, or maybe you even need an opinion. I might need an opinion as to whether or not I should take a certain medication, or whether I should put time and energy into learning a new technology. How am I meant to figure out where to get my opinions? I argue that 98.7% of opinions should be outsourced (I made that number up, but it feels about right). You don&#39;t have the time to become an expert in everything. If you&#39;re lucky you might become an expert at one or two things in your lifetime. So why not just find an expert you trust, and agree with all of their opinions in their domain without resistance. You can assume that even if they&#39;re occasionally wrong they&#39;re probably going to be wrong less of the time than you are.</p>
<div class="center font-bold py-2 my-2 text-xl">Here's my current framework for outsourcing my opinions</div>

<ul><li>Find someone you think you can trust, who has a substantial amount of experience in the field that you&#39;re looking into, but still seems as though they keep up with new developments in their space. This could be by using new technologies, still reading papers or just keeping up with current trends.</li><li>See what people who disagree with that person disagree with them about.</li><li>Decide which side seems as though they have put more time, energy and critical thinking into their opinion.</li><li>Mindlessly make that opinion your own, until it either stops working for you, or more information comes to light</li></ul><p>Now you might not like that last point, but bear with me for a second. Unless you&#39;re also an expert in that field are you ever going to put as much time and energy into learning about that specific topic as that person has? Probably not. You can also assume that they are as intelligent, more intelligent or at least close to as intelligent as you. So why disagree with them? You can trust that their opinions are well thought out and lay on the foundation of years of work in the field. Years of foundation that you don&#39;t have. Make their opinion your own. It&#39;ll do wonders for your wellbeing. You no longer have to worry about who to believe or what to think as you&#39;ve now outsourced your thinking on that topic to someone you know is more qualified than yourself.</p>
<p>For an example of someone I outsource my thinking to. I outsource most of my health and wellbeing opinions to <a href="https://en.wikipedia.org/wiki/Andrew_D._Huberman">Andrew Huberman</a>. I trust as a phd from Stanford he probably knows a bit more about the human body than me, so I&#39;ll trust that what he says is good for me probably is.</p>
<p>Do I see the irony of voicing my opinion on not having opinions? Yes…</p>
]]></description>
<pubDate>Fri, 03 Nov 2023 00:00:00 GMT</pubDate>
</item><item>
<guid isPermaLink="true">https://www.joshshipton.com/post/bored</guid>
<title>Maybe being bored isn&apos;t so bad</title>
<link>https://joshshipton.com/post/bored</link>
<description><![CDATA[<p>Most people look at being bored as wasted time, time that could have been spent experiencing, making memories or learning. Sure. Sometimes that’s true but by embracing and seeking intentional boredom I believe that boredom can become a high ROI activity.</p>
<p>When you don’t give your brain any stimulation it starts to create its own. This often manifests as either organizational or creative thought patterns. Only when you’re bored and not being stimulated can you really digest the information you’ve been consuming. You’re forced to think about the things you’ve been avoiding and have no choice but to sort your shit out.</p>
<p>You also don’t need to know more things to have more good ideas you just need to connect what you know in a new way. You’ll notice that a lot of your great ideas happen in the shower, or just before bed. That&#39;s because these are some of the only times of the day that we aren’t stimulated and give ourselves time to think. Being bored is what allows your brain to have the chance to use what it knows to come up with new creative solutions and ideas.</p>
<p>Another big thing that I’ve used boredom for is resetting when I find myself either not knowing what to do next or when I’m just fed up and want to stop working. There&#39;s a difference between relaxing and rejuvenating activities. and although sitting back and watching an episode of a TV show might seem like a great way to rest after a long study or work block it&#39;s actually a horrible thing to do. Sure it’s relaxing, but it&#39;s not rejuvenating and afterwards you’ll feel lethargic and won’t want to get back into your workflow, which makes sense. You’re going from an enjoyable activity to a less enjoyable one. But after being intentionally bored for 20-30 minutes you’ll start to miss your work and the stimulation it provides you with. Making it much easier to get back into being productive. This works for almost anything, when you’re doing nothing a lot more things suddenly become more fun than what you’re doing right now. Intentionally being bored is a good way to get yourself to start doing something.</p>
<h4>My Current Framework for being intentionally bored</h4><p>Get a timer, set it anywhere from 10-30 minutes, choose a wall, stare at said wall. Don’t look anywhere but straight and move as little as possible.</p>
<p>I’ve really found doing this a few times a week to be super beneficial for my mental if you found any value from this or want to talk about it, send me an email.</p>
]]></description>
<pubDate>Sat, 21 Oct 2023 00:00:00 GMT</pubDate>
</item><item>
<guid isPermaLink="true">https://www.joshshipton.com/post/why-blog</guid>
<title>All the best posts about why you should start a blog right now</title>
<link>https://joshshipton.com/post/why-blog</link>
<description><![CDATA[<p>These two posts pushed me over the edge when i was tossing up about whether or not to start a blog<br><a href="https://www.benkuhn.net/writing/">Ben khun</a><br><a href="https://guzey.com/personal/why-have-a-blog/">Alex Guzey</a></p>
<p>And also great writing advice from Scott Alexander <a href="https://slatestarcodex.com/2016/02/20/writing-advice/">here</a></p>
]]></description>
<pubDate>Thu, 12 Oct 2023 00:00:00 GMT</pubDate>
</item><item>
<guid isPermaLink="true">https://www.joshshipton.com/post/hello-world</guid>
<title>Hello World!</title>
<link>https://joshshipton.com/post/hello-world</link>
<description><![CDATA[<p>I&#39;ve finally decided to go ahead and start a blog. &quot;Blog&quot; is probably pushing it, to be honest. You can think of this as a collective home for all of my ramblings that won&#39;t get me canceled.</p>
<p>I&#39;ve been blog-curious ever since I found Alex Guzey, but what finally pushed me over the edge was Ben Kuhn&#39;s, Why and how to write things on the Internet.</p>
<p>(Both amazing writers. You should check them both out.)<br>The main points that inspired me were making new, interesting friends that you otherwise would never have access to and creating new and interesting conversations with already existing friends. Getting better at writing was a big plus too.</p>
<p>Another feature of this blog is that it will only use vanilla CSS/HTML/JS (I can&#39;t wait to see the abomination I create). The blog will be simple, but I&#39;m excited to see what kind of features I can add all on my lonesome.</p>
<h3>Disclaimer!</h3><p>What lies ahead will be a slew of very average writing from a very averagely intelligent person. Please proceed at your own risk.</p>
]]></description>
<pubDate>Wed, 11 Oct 2023 00:00:00 GMT</pubDate>
</item>
</channel>
</rss>
