LINK.TL
LINK.TL is one of the best and highest URL shortener website.It pays up to $16 for every 1000 views.You just have to sign up for free.You can earn by shortening your long URL into short and you can paste that URL into your website, blogs or social media networking sites, like facebook, twitter, and google plus etc.
One of the best thing about this site is its referral system.They offer 10% referral commission.You can withdraw your amount when it reaches $5.- Payout for 1000 views-$16
- Minimum payout-$5
- Referral commission-10%
- Payout methods-Paypal, Payza, and Skrill
- Payment time-daily basis
Al.ly
Al.ly is another very popular URL Shortening Service for earning money on short links without investing any single $. Al.ly will pay from $1 to $10 per 1000 views depending upon the different regions. Minimum withdrawal is only $1, and it pays through PayPal, Payoneer, or Payza. So, you have to earn only $1.00 to become eligible to get paid using Al.ly URL Shortening Service.
Besides the short links, Al.ly also runs a referral program wherein you can earn 20% commission on referrals for a lifetime. The referral program is one of the best ways to earn even more money with your short links. Al.ly offers three different account subscriptions, including free option as well as premium options with advanced features.CPMlink
CPMlink is one of the most legit URL shortener sites.You can sign up for free.It works like other shortener sites.You just have to shorten your link and paste that link into the internet.When someone will click on your link.
You will get some amount of that click.It pays around $5 for every 1000 views.They offer 10% commission as the referral program.You can withdraw your amount when it reaches $5.The payment is then sent to your PayPal, Payza or Skrill account daily after requesting it.- The payout for 1000 views-$5
- Minimum payout-$5
- Referral commission-10%
- Payment methods-Paypal, Payza, and Skrill
- Payment time-daily
Shrinkearn.com
Shrinkearn.com is one of the best and most trusted sites from our 30 highest paying URL shortener list.It is also one of the old URL shortener sites.You just have to sign up in the shrinkearn.com website. Then you can shorten your URL and can put that URL to your website, blog or any other social networking sites.
Whenever any visitor will click your shortener URL link you will get some amount for that click.The payout rates from Shrinkearn.com is very high.You can earn $20 for 1000 views.Visitor has to stay only for 5 seconds on the publisher site and then can click on skip button to go to the requesting site.- The payout for 1000 views- up to $20
- Minimum payout-$1
- Referral commission-25%
- Payment methods-PayPal
- Payment date-10th day of every month
Bc.vc
Bc.vc is another great URL Shortener Site. It provides you an opportunity to earn $4 to $10 per 1000 visits on your Shortened URL. The minimum withdrawal is $10, and the payment method used PayPal or Payoneer.
Payments are made automatically on every seven days for earnings higher than $10.00. It also runs a referral system wherein the rate of referral earning is 10%.- The payout for 1000 views-$10
- Minimum payout -$10
- Referral commission-10%
- Payment method -Paypal
- Payment time-daily
Oke.io
Oke.io provides you an opportunity to earn money online by shortening URLs. Oke.io is a very friendly URL Shortener Service as it enables you to earn money by shortening and sharing URLs easily.
Oke.io can pay you anywhere from $5 to $10 for your US, UK, and Canada visitors, whereas for the rest of the world the CPM will not be less than $2. You can sign up by using your email. The minimum payout is $5, and the payment is made via PayPal.- The payout for 1000 views-$7
- Minimum payout-$5
- Referral commission-20%
- Payout options-PayPal, Payza, Bitcoin and Skrill
- Payment time-daily
Short.pe
Short.pe is one of the most trusted sites from our top 30 highest paying URL shorteners.It pays on time.intrusting thing is that same visitor can click on your shorten link multiple times.You can earn by sign up and shorten your long URL.You just have to paste that URL to somewhere.
You can paste it into your website, blog, or social media networking sites.They offer $5 for every 1000 views.You can also earn 20% referral commission from this site.Their minimum payout amount is only $1.You can withdraw from Paypal, Payza, and Payoneer.- The payout for 1000 views-$5
- Minimum payout-$1
- Referral commission-20% for lifetime
- Payment methods-Paypal, Payza, and Payoneer
- Payment time-on daily basis
BIT-URL
It is a new URL shortener website.Its CPM rate is good.You can sign up for free and shorten your URL and that shortener URL can be paste on your websites, blogs or social media networking sites.bit-url.com pays $8.10 for 1000 views.
You can withdraw your amount when it reaches $3.bit-url.com offers 20% commission for your referral link.Payment methods are PayPal, Payza, Payeer, and Flexy etc.- The payout for 1000 views-$8.10
- Minimum payout-$3
- Referral commission-20%
- Payment methods- Paypal, Payza, and Payeer
- Payment time-daily
Cut-win
Cut-win is a new URL shortener website.It is paying at the time and you can trust it.You just have to sign up for an account and then you can shorten your URL and put that URL anywhere.You can paste it into your site, blog or even social media networking sites.It pays high CPM rate.
You can earn $10 for 1000 views.You can earn 22% commission through the referral system.The most important thing is that you can withdraw your amount when it reaches $1.- The payout for 1000 views-$10
- Minimum payout-$1
- Referral commission-22%
- Payment methods-PayPal, Payza, Bitcoin, Skrill, Western Union and Moneygram etc.
- Payment time-daily
Ouo.io
Ouo.io is one of the fastest growing URL Shortener Service. Its pretty domain name is helpful in generating more clicks than other URL Shortener Services, and so you get a good opportunity for earning more money out of your shortened link. Ouo.io comes with several advanced features as well as customization options.
With Ouo.io you can earn up to $8 per 1000 views. It also counts multiple views from same IP or person. With Ouo.io is becomes easy to earn money using its URL Shortener Service. The minimum payout is $5. Your earnings are automatically credited to your PayPal or Payoneer account on 1st or 15th of the month.- Payout for every 1000 views-$5
- Minimum payout-$5
- Referral commission-20%
- Payout time-1st and 15th date of the month
- Payout options-PayPal and Payza
Linkbucks
Linkbucks is another best and one of the most popular sites for shortening URLs and earning money. It boasts of high Google Page Rank as well as very high Alexa rankings. Linkbucks is paying $0.5 to $7 per 1000 views, and it depends on country to country.
The minimum payout is $10, and payment method is PayPal. It also provides the opportunity of referral earnings wherein you can earn 20% commission for a lifetime. Linkbucks runs advertising programs as well.- The payout for 1000 views-$3-9
- Minimum payout-$10
- Referral commission-20%
- Payment options-PayPal,Payza,and Payoneer
- Payment-on the daily basis
Wi.cr
Wi.cr is also one of the 30 highest paying URL sites.You can earn through shortening links.When someone will click on your link.You will be paid.They offer $7 for 1000 views.Minimum payout is $5.
You can earn through its referral program.When someone will open the account through your link you will get 10% commission.Payment option is PayPal.- Payout for 1000 views-$7
- Minimum payout-$5
- Referral commission-10%
- Payout method-Paypal
- Payout time-daily
Clk.sh
Clk.sh is a newly launched trusted link shortener network, it is a sister site of shrinkearn.com. I like ClkSh because it accepts multiple views from same visitors. If any one searching for Top and best url shortener service then i recommend this url shortener to our users. Clk.sh accepts advertisers and publishers from all over the world. It offers an opportunity to all its publishers to earn money and advertisers will get their targeted audience for cheapest rate. While writing ClkSh was offering up to $8 per 1000 visits and its minimum cpm rate is $1.4. Like Shrinkearn, Shorte.st url shorteners Clk.sh also offers some best features to all its users, including Good customer support, multiple views counting, decent cpm rates, good referral rate, multiple tools, quick payments etc. ClkSh offers 30% referral commission to its publishers. It uses 6 payment methods to all its users.- Payout for 1000 Views: Upto $8
- Minimum Withdrawal: $5
- Referral Commission: 30%
- Payment Methods: PayPal, Payza, Skrill etc.
- Payment Time: Daily
Short.am
Short.am provides a big opportunity for earning money by shortening links. It is a rapidly growing URL Shortening Service. You simply need to sign up and start shrinking links. You can share the shortened links across the web, on your webpage, Twitter, Facebook, and more. Short.am provides detailed statistics and easy-to-use API.
It even provides add-ons and plugins so that you can monetize your WordPress site. The minimum payout is $5 before you will be paid. It pays users via PayPal or Payoneer. It has the best market payout rates, offering unparalleled revenue. Short.am also run a referral program wherein you can earn 20% extra commission for life.Dwindly
Dwindly is one of the best URL Shorten to earn money online. It offers the opportunity to earn money for every person that views links you have created.
Its working is simple. You need to create an account and then shorten any URLs with a click of a button. Go on to share your shortened URLs on the internet, including social media, YouTube, blogs, and websites. And finally, earn when any person clicks on your shortened URL.
They offer the best environment to you for earning money from home. They have even come up with a referral system where you can invite people to Dwindly and earn as much as 20% of their income.
It has built-in a unique system wherein you get the opportunity to increase your daily profits when you analyze your top traffic sources and detailed stats.
Best of all, you get the highest payout rates. The scripts and the APIs allow you to earn through your websites efficiently.
Last but not the least you get payments on time within four days.Fas.li
Although Fas.li is relatively new URL Shortener Service, it has made its name and is regarded as one of the most trusted URL Shortener Company. It provides a wonderful opportunity for earning money online without spending even a single $. You can expect to earn up to $15 per 1000 views through Fas.li.
You can start by registering a free account on Fas.li, shrink your important URLs, and share it with your fans and friends in blogs, forums, social media, etc. The minimum payout is $5, and the payment is made through PayPal or Payza on 1st or 15th of each month.
Fas.li also run a referral program wherein you can earn a flat commission of 20% by referring for a lifetime. Moreover, Fas.li is not banned in anywhere so you can earn from those places where other URL Shortening Services are banned.Adf.ly
Adf.ly is the oldest and one of the most trusted URL Shortener Service for making money by shrinking your links. Adf.ly provides you an opportunity to earn up to $5 per 1000 views. However, the earnings depend upon the demographics of users who go on to click the shortened link by Adf.ly.
It offers a very comprehensive reporting system for tracking the performance of your each shortened URL. The minimum payout is kept low, and it is $5. It pays on 10th of every month. You can receive your earnings via PayPal, Payza, or AlertPay. Adf.ly also runs a referral program wherein you can earn a flat 20% commission for each referral for a lifetime.Linkrex.net
Linkrex.net is one of the new URL shortener sites.You can trust it.It is paying and is a legit site.It offers high CPM rate.You can earn money by sing up to linkrex and shorten your URL link and paste it anywhere.You can paste it in your website or blog.You can paste it into social media networking sites like facebook, twitter or google plus etc.
You will be paid whenever anyone will click on that shorten a link.You can earn more than $15 for 1000 views.You can withdraw your amount when it reaches $5.Another way of earning from this site is to refer other people.You can earn 25% as a referral commission.- The payout for 1000 views-$14
- Minimum payout-$5
- Referral commission-25%
- Payment Options-Paypal,Bitcoin,Skrill and Paytm,etc
- Payment time-daily
Friday, March 29, 2019
18 Highest Paying URL Shortener to Earn Money Online
Dear Hearthstone Players: Please Learn Some Dang Manners!
By Julian
One of the greatest features of Hearthstone (an incredible online collectible card game you should check out if you haven't) is that it limits the online talk of its players to six straightforward emotes: Thanks, Well Played, Greetings, Sorry, Oops, and Threaten. It's simple but effective communication that makes it easy to display good game etiquette. Of course, you still have to have some idea of what good game etiquette actually IS. After playing this game for quite some time, it's clear that many of you missed the day (or the entire childhood) where they were teaching this stuff. Never fear, my friends. I am here to help you with a breakdown of each emote and how to PROPERLY use it. Pay attention, whipper-snapper! I'm about to teach you some manners!
This is the polite and proper response when someone says or does something nice for you. In Hearthstone, this should follow any time your opponent uses the "Good Game" emote to compliment you on your play. Also, appropriate (but not necessary) if an opponent plays a mutually beneficial card that does something fun or cool for you, too. Do NOT use this emote sarcastically to whine at your opponent when they destroy your favorite creature or wipe your board. That's petty.
Unless your opponent is a sociopathic monster, you must press this emote at least once per game. If your opponent does something clever or cool, "Well Played" is a fine compliment to pay them. However, regardless of how they played, regardless of whether you won or lost, at the end of every game you tell your opponent "Well Played." That's not a bot your playing. That's a person on the other side of the table. It's a person that just spent time doing something that helped you enjoy yourself. Yes, they did it because they were having fun, too. So what. At the end of ANY game, you thank your fellow players for taking the time to play with you. In Hearthstone, the emote to say this is "Well Played."
This emote is mostly pointless. You can say a generic greeting at your opponent at the start of the game to say hello, but after several games this starts to get old. It doesn't really show appreciation in any meaningful way. However, if your opponent is taking a long time on their turn and doesn't seem to be doing anything, you can give a single "Greetings" to check that they know it's still their turn. Also, pointless though it may be, if someone greets you at the start of the game, you GREET THEM BACK. That's just common decency.
It can be tempting to say sorry when you destroy your opponent's board or otherwise swing the game strongly in your favor. Don't. It's a competitive game. Everyone gets that. Apologizing for playing effectively is just condescending. That said, Hearthstone has a lot of cards with random effects that sometimes swing the game in unfair ways. When a random effect unbalances the game in your favor, a sympathetic "Sorry" is a good way to indicate that you know you're not about to win due to any particular skill or strategy on your part. Also, "Sorry" is a fine way to express sympathy if your opponent makes an obvious misplay and calls it out by pressing the "oops" emote.
This emote is a little self-serving. It's only exists for you to press when you screw up and only so you can prove to your opponent that you're not dumb because you know you screwed up. Then, you can imagine they're laughing along with you at your ridiculous mistake. Press it if you're really that worried about an anonymous stranger judging your intellect. Do NOT press it to point out an opponent's mistake. When an opponent misplays, emoting "Sorry" says "I sympathize. Obviously, that didn't work out how you'd hoped." Emoting "Oops" say "I'm a snarky jerk who thinks I'm sooooo superior to your incredibly feeble play skills."
What are you 12? Obviously you shouldn't threaten people you're playing a game with. True, the threat emote is too ridiculous to be threatening. However, it's not ridiculous ENOUGH to be ironic or funny. It's just juvenile and pointless. And when you press "Threaten" after losing a game, what is that about? Do you think you're the villain in my hero's story and that's your dramatic finish? Well it's not. It's dumb. Grow up.
Remember folks, even when communication is limited, its important to show respect to those we play against. Without those players, there would be no meaningful game to play. Let's all play well together and have fun! (And seriously, just press "Well Played" at the end of a game. It's right there on the left. Just. Press. It.)
Get Free Games!
Speaking of fun things to play, Growing Up Gamers is running a contest where you, yes YOU, can win free games! It's all to promote our Kickstarter for Riftwalker: A StormHollow Card Game going on through Sunday, March 20th. You can check out the contest here! The Kickstarter is also promoting the last few weeks of Storm Hollow pre-orders. This awesome storytelling adventure game represents four years of development by the Growing Up Gamers crew (and other amazing people who helped out). There are no immediate plans for a retail version so preordering may be the only way to ever get this fantastic game of which we are incredibly proud. It will only be available for purchase in its current format until March 20th. You can check out the pre-order here!
Across The Stars
SPOILER ALERT: Plot details for Super Dimension Fortress Macross are discussed.
Super Dimension Fortress Macross, released in America as Robotech, is composed of three basic elements: mechs, a love triangle, and pop music. The standard mechs, the Valkyries, are transforming planes, while their strongest mech, the Macross is the alien fortress wherein they reside. The pilot at the center of this love triangle is Hikaru Ichijo, whose affections fluctuate from the stern lieutenant Misa Hayase to the bubbly pop star Lynn Minmay. Minmay's songs, while providing hope and joy for those aboard, are also the key to intergalactic peace.
The story is set ten years after an alien ship is left stranded on Earth, and has now been repurposed for human use as the "Macross." The aliens, giants known as the Zentradi, have waged war with the humans to get their ship back. The Macross escapes with thousands of refugees from the war using a "Space Fold" that teleports them near the orbit of Pluto. Now the crew of the Macross must make an arduous odyssey back to Earth, fighting off the relentless Zentradi along the way.
Many of the standard mechs aren't as stylish as those in, say, Gundam or Evangelion, but the VF-1 Valkyrie jets are known for their smooth transformations into massive battle suits. Indeed, a great deal of the animation budget is spent on their transformations and epic space battles. While done without the aid of computers, the flashy, dizzying battles still hold up as impressive. The aesthetics of Top Gun and Star Wars are written all over this. The greatest mech of them all, however, is the Macross, whose transformation is so disruptive that it causes havok for those living aboard.
The romance in Macross can rise to the level of soap opera, especially with the indecisive back and forth between Hikaru, Minmay, and Hayase, who come in and out of states of love, hate, and uncertainty. It can be frustrating, at times, to watch these three trip over their feelings, and at others, humorous to the point of parody. It's best not to take the romance too seriously, but it remains the better of the others in the show. Claudia and Roy have a touching and tragic love that ends on a note of pineapple salad, but it remains a side story. Max and Milia's deadly rivalry is exciting, but their transition to a married couple feels very rushed. In the central love story, things are allowed to take their time. What makes this love triangle one of the more effective, is that you genuinely don't know who Hikaru will pick, as he has enough of a relationship with both to choose either. Minmay is the cute first crush who showers Hikaru with affection and warmth, a pleasant escape from military life. Yet Minmay's ascendance as a pop star keeps her farther and farther away from him. Her childish antics also have less emotional pull with his growing life as a soldier. Lieutenant Hayase is rather strict and cold with him at first. Theirs is a love that grows with mutual understanding. Hayase grows to better understand the visceral terrors exacted on those she commands in battle, while Hikaru grows more accepting of the military code that his superior follows. His eventual selection of Hayase represents his maturity away from the youthful pleasures childhood, to the meaningful fruit produced by a life of labor.
Macross is very much a musical. To distinguish itself from the other mech show, Mobile Suit Gundam, and other spaceship odyssey show, Space Battleship Yamato, it needed a new stand-out element. That element was J-Pop, to be sung by newcomer Mari Iijima as Lynn Minmay. Her music, initially, serves as a comfort for the many refugees lost in space. They are mainly bubblegum pop songs, "My Boyfriend Is A Pilot", "Zero-G Love", and the theme for her film "Xiao Pai Long." We soon learn, however, that this music has an adverse effect on the Zentradi, who were a race created only to wage war. Music or displays of romantic affection shock and weaken them. The apex of this achievement occurs when Minmay's songs are broadcast to all the pilots and Zentradi during an all-out space battle in episode twenty-seven. This battle is so exciting because you get a sense that humanity is on its last legs, with all of Earth's population annihilated, and the Zentradi forces greatly outnumbering the humans. It's all so terrible that even Hikaru's plane is taken down. Minmay's music is their only advantage, as she sings through her every song as ships explode around her. The last is a "Bolero" infused march of "Love Drifts Away", during which the Macross lunges its way into the interiors of the main Zentradi ship, firing all of their missiles and winning the war. At the same time, Hikaru rescues Hayase, the last woman on Earth, as they realize their love for each other and cruise away to see the Macross landing on the horizon. It really is a perfect ending, and much of what occurs afterwards is unnecessary filler that can be skipped.
Macross got its first film in Macross: Do You Remember Love? It is a compilation film that summarizes the best highlights of the show. The Adolescence of Utena remains the gold standard for this, as it remixed all of the strongest elements of the show into a standalone plot, while surpassing its source material in beatific artistry. While it is preferable to have seen Revolutionary Girl Utena before watching Adolescence, the movie stands enough on its own to make that unnecessary. The same can't be said for Do You Remember Love? This is regrettable because the animation in the film is a full realization of character designs that were limited by a television budget. It also adds the new song, "Do You Remember Love?" which is played during the spectacular final battle, and has become a flagship anthem of the series. All of the mechs are purely handrawn, and the film is stuffed with so many, that it is probably the most ambitious mecha film on that scale alone. The drawbacks are that the movie tries to stuff in too much with character development terribly stunted or skipped, though I'll give it points for the juggle. In any case, Do You Remember Love? is an aesthetic firework, a rare gem of animation never to be seen of in the mecha genre again
It's a shame that so many subsequent entries in the Macross series have yet to get a Western release. Macross 7, Macross Zero, Macross Frontier, and Macross Delta will remain within Japanese borders, due to arcane copyright issues between Harmony Gold and Studio Nue. The best of these entries remains the OVA Macross Plus, which thankfully has a Western release. It deals with a love triangle of three childhood friends, now split apart. Two of them pilots and one a manager for Sharon Apple, a pop star A.I., and one of the first virtual idols in fiction. Plus continues the Macross tradition of strong characterization and glamorous battle animations. The animation, it must be said, did for anime what The Prince of Egypt did for Western cartoons, in its innovative mixing of computer animation with traditional, now standard in anime today. Plus is also scored by Cowboy Bebop composer Yoko Kanno, whose grand reputation fits right in with this musical series. Macross 7 takes place not long after the original, with Max and Milia as side characters, and their daughter taking a major role. The main character, though, is the guitarist Basara, who wants to utilize rock music to end conflicts. While Macross 7 isn't as critically well-recieved, the soundtrack remains highly popular, and is worth a listen. Macross Zero is prequel to the original series that explains the origin of the transforming planes, while bringing back Roy as a supporting character. Macross Frontier is a tribute to all the prior Macross shows, with Ranka singing "My Boyfriend Is A Pilot" to Alto practicing the hand motions of Dyson from Plus. Frontier is the third best Macross show, with Kanno returning to score, and rivalry between the two very cute singers, Sheryl Nome and Ranka Lee. The only downside is that all the mechs are computer animated, which may look great in Rebuild of Evangelion, but not so much here. Macross Delta is the latest installment, and perhaps the most divisive, as it utilizes the modern moe idol aesthetic seen in Love Live and Idolmaster, while introducing magic. It may have its fans, but it's a far cry from the science-fiction space opera that started it all.
The influence of Macross on anime is also quite visible. We can assume that Hideaki Anno was a passionate fan. Captain Nemo from Nadia: Secret Of Blue Water has a striking resemblance to Captain Global. Shinji's dream in Neon Genesis Evangelion, where previous scenes in the anime are repurposed to explore his psyche, echoes a similar nightmare the Hikaru suffered after a battle left him in a coma. Macross Frontier seemed to acknowledge Evangelion, by making Alto's pilot suit look similar to Shinji's blue plugsuit. Music also plays a strong role in Evangelion's copycat. Rahxephon. They even brought Yoko Kanno for the soundtrack, and while Macross had a love triangle, Rahxephon had what felt like a love pentagon. Macross has also been an influence on the future funk genre of internet pop, that samples Japanese pop songs of the 80's and 90's and remixes them with modern funk. The artist Macross 82-99 takes his name from the series, naming one of his songs after Lynn Minmay, Night Tempo has remixed the Macross song "Silver Moon, Red Moon" and the YouTube channel "Artzie Music" routinely uses Macross clips in their future funk music videos.
Macross was created by Takamori Shoji, who is also responsible for isekai-mecha fusion, The Vision Of Escaflowne and the original designs for many of the Transformers, such as Optimus Prime. Kawamori was partially inspired into pursuing mechanical design by the Apollo 11 mission, but "When he saw the moon landing on television as a child, he was frustrated. he wanted to go to the moon" (Anime Jump). From that dream of spaceflight came another dream true to the spirit of what Apollo represented: the elevation of our species for a more common good. While the message that love and music will save the world comes off as hokey, it speaks to a deeper truth, that these things are part of what make life so enriching, and the world worth saving. It speaks to common humanity that may not end war, but can shrink our fears. I think now on the words of Dr. Yury Pelyoshonok, who having grown up in the Soviet Union, remarked on the impact of hearing the Beatles in that oppressive regime, "The kids lost their interest in all Soviet unshakable dogmas and ideals, and stopped thinking of an English-speaking person as an enemy" (BBC News).
Music Video
Art Of Anime
"When Did Mimi Get So Cute?"
http://sansuthecat.blogspot.com/2016/05/when-did-mimi-get-so-cute.html
"Evangelion, Or Something Like It."
http://sansuthecat.blogspot.com/2015/10/evangelion-or-something-like-it.html
"Yuri Vincit Omnia."
http://sansuthecat.blogspot.com/2015/03/puella-magi-madoka-magica-yuri-vincit.html
"FLCL: Insanity Defined."
http://sansuthecat.blogspot.com/2014/10/flcl-insanity-defined.html
"Barefoot In The Park."
https://sansuthecat.blogspot.com/2017/01/barefoot-in-park.html
"Sakura No Aware."
https://sansuthecat.blogspot.com/2017/06/sakura-no-aware.html
"The Celebrity And The Sybil."
https://sansuthecat.blogspot.com/2017/12/the-celebrity-and-sybil.html
Super Dimension Fortress Macross, released in America as Robotech, is composed of three basic elements: mechs, a love triangle, and pop music. The standard mechs, the Valkyries, are transforming planes, while their strongest mech, the Macross is the alien fortress wherein they reside. The pilot at the center of this love triangle is Hikaru Ichijo, whose affections fluctuate from the stern lieutenant Misa Hayase to the bubbly pop star Lynn Minmay. Minmay's songs, while providing hope and joy for those aboard, are also the key to intergalactic peace.
The story is set ten years after an alien ship is left stranded on Earth, and has now been repurposed for human use as the "Macross." The aliens, giants known as the Zentradi, have waged war with the humans to get their ship back. The Macross escapes with thousands of refugees from the war using a "Space Fold" that teleports them near the orbit of Pluto. Now the crew of the Macross must make an arduous odyssey back to Earth, fighting off the relentless Zentradi along the way.
Many of the standard mechs aren't as stylish as those in, say, Gundam or Evangelion, but the VF-1 Valkyrie jets are known for their smooth transformations into massive battle suits. Indeed, a great deal of the animation budget is spent on their transformations and epic space battles. While done without the aid of computers, the flashy, dizzying battles still hold up as impressive. The aesthetics of Top Gun and Star Wars are written all over this. The greatest mech of them all, however, is the Macross, whose transformation is so disruptive that it causes havok for those living aboard.
The romance in Macross can rise to the level of soap opera, especially with the indecisive back and forth between Hikaru, Minmay, and Hayase, who come in and out of states of love, hate, and uncertainty. It can be frustrating, at times, to watch these three trip over their feelings, and at others, humorous to the point of parody. It's best not to take the romance too seriously, but it remains the better of the others in the show. Claudia and Roy have a touching and tragic love that ends on a note of pineapple salad, but it remains a side story. Max and Milia's deadly rivalry is exciting, but their transition to a married couple feels very rushed. In the central love story, things are allowed to take their time. What makes this love triangle one of the more effective, is that you genuinely don't know who Hikaru will pick, as he has enough of a relationship with both to choose either. Minmay is the cute first crush who showers Hikaru with affection and warmth, a pleasant escape from military life. Yet Minmay's ascendance as a pop star keeps her farther and farther away from him. Her childish antics also have less emotional pull with his growing life as a soldier. Lieutenant Hayase is rather strict and cold with him at first. Theirs is a love that grows with mutual understanding. Hayase grows to better understand the visceral terrors exacted on those she commands in battle, while Hikaru grows more accepting of the military code that his superior follows. His eventual selection of Hayase represents his maturity away from the youthful pleasures childhood, to the meaningful fruit produced by a life of labor.
Macross is very much a musical. To distinguish itself from the other mech show, Mobile Suit Gundam, and other spaceship odyssey show, Space Battleship Yamato, it needed a new stand-out element. That element was J-Pop, to be sung by newcomer Mari Iijima as Lynn Minmay. Her music, initially, serves as a comfort for the many refugees lost in space. They are mainly bubblegum pop songs, "My Boyfriend Is A Pilot", "Zero-G Love", and the theme for her film "Xiao Pai Long." We soon learn, however, that this music has an adverse effect on the Zentradi, who were a race created only to wage war. Music or displays of romantic affection shock and weaken them. The apex of this achievement occurs when Minmay's songs are broadcast to all the pilots and Zentradi during an all-out space battle in episode twenty-seven. This battle is so exciting because you get a sense that humanity is on its last legs, with all of Earth's population annihilated, and the Zentradi forces greatly outnumbering the humans. It's all so terrible that even Hikaru's plane is taken down. Minmay's music is their only advantage, as she sings through her every song as ships explode around her. The last is a "Bolero" infused march of "Love Drifts Away", during which the Macross lunges its way into the interiors of the main Zentradi ship, firing all of their missiles and winning the war. At the same time, Hikaru rescues Hayase, the last woman on Earth, as they realize their love for each other and cruise away to see the Macross landing on the horizon. It really is a perfect ending, and much of what occurs afterwards is unnecessary filler that can be skipped.
Macross got its first film in Macross: Do You Remember Love? It is a compilation film that summarizes the best highlights of the show. The Adolescence of Utena remains the gold standard for this, as it remixed all of the strongest elements of the show into a standalone plot, while surpassing its source material in beatific artistry. While it is preferable to have seen Revolutionary Girl Utena before watching Adolescence, the movie stands enough on its own to make that unnecessary. The same can't be said for Do You Remember Love? This is regrettable because the animation in the film is a full realization of character designs that were limited by a television budget. It also adds the new song, "Do You Remember Love?" which is played during the spectacular final battle, and has become a flagship anthem of the series. All of the mechs are purely handrawn, and the film is stuffed with so many, that it is probably the most ambitious mecha film on that scale alone. The drawbacks are that the movie tries to stuff in too much with character development terribly stunted or skipped, though I'll give it points for the juggle. In any case, Do You Remember Love? is an aesthetic firework, a rare gem of animation never to be seen of in the mecha genre again
It's a shame that so many subsequent entries in the Macross series have yet to get a Western release. Macross 7, Macross Zero, Macross Frontier, and Macross Delta will remain within Japanese borders, due to arcane copyright issues between Harmony Gold and Studio Nue. The best of these entries remains the OVA Macross Plus, which thankfully has a Western release. It deals with a love triangle of three childhood friends, now split apart. Two of them pilots and one a manager for Sharon Apple, a pop star A.I., and one of the first virtual idols in fiction. Plus continues the Macross tradition of strong characterization and glamorous battle animations. The animation, it must be said, did for anime what The Prince of Egypt did for Western cartoons, in its innovative mixing of computer animation with traditional, now standard in anime today. Plus is also scored by Cowboy Bebop composer Yoko Kanno, whose grand reputation fits right in with this musical series. Macross 7 takes place not long after the original, with Max and Milia as side characters, and their daughter taking a major role. The main character, though, is the guitarist Basara, who wants to utilize rock music to end conflicts. While Macross 7 isn't as critically well-recieved, the soundtrack remains highly popular, and is worth a listen. Macross Zero is prequel to the original series that explains the origin of the transforming planes, while bringing back Roy as a supporting character. Macross Frontier is a tribute to all the prior Macross shows, with Ranka singing "My Boyfriend Is A Pilot" to Alto practicing the hand motions of Dyson from Plus. Frontier is the third best Macross show, with Kanno returning to score, and rivalry between the two very cute singers, Sheryl Nome and Ranka Lee. The only downside is that all the mechs are computer animated, which may look great in Rebuild of Evangelion, but not so much here. Macross Delta is the latest installment, and perhaps the most divisive, as it utilizes the modern moe idol aesthetic seen in Love Live and Idolmaster, while introducing magic. It may have its fans, but it's a far cry from the science-fiction space opera that started it all.
The influence of Macross on anime is also quite visible. We can assume that Hideaki Anno was a passionate fan. Captain Nemo from Nadia: Secret Of Blue Water has a striking resemblance to Captain Global. Shinji's dream in Neon Genesis Evangelion, where previous scenes in the anime are repurposed to explore his psyche, echoes a similar nightmare the Hikaru suffered after a battle left him in a coma. Macross Frontier seemed to acknowledge Evangelion, by making Alto's pilot suit look similar to Shinji's blue plugsuit. Music also plays a strong role in Evangelion's copycat. Rahxephon. They even brought Yoko Kanno for the soundtrack, and while Macross had a love triangle, Rahxephon had what felt like a love pentagon. Macross has also been an influence on the future funk genre of internet pop, that samples Japanese pop songs of the 80's and 90's and remixes them with modern funk. The artist Macross 82-99 takes his name from the series, naming one of his songs after Lynn Minmay, Night Tempo has remixed the Macross song "Silver Moon, Red Moon" and the YouTube channel "Artzie Music" routinely uses Macross clips in their future funk music videos.
Macross was created by Takamori Shoji, who is also responsible for isekai-mecha fusion, The Vision Of Escaflowne and the original designs for many of the Transformers, such as Optimus Prime. Kawamori was partially inspired into pursuing mechanical design by the Apollo 11 mission, but "When he saw the moon landing on television as a child, he was frustrated. he wanted to go to the moon" (Anime Jump). From that dream of spaceflight came another dream true to the spirit of what Apollo represented: the elevation of our species for a more common good. While the message that love and music will save the world comes off as hokey, it speaks to a deeper truth, that these things are part of what make life so enriching, and the world worth saving. It speaks to common humanity that may not end war, but can shrink our fears. I think now on the words of Dr. Yury Pelyoshonok, who having grown up in the Soviet Union, remarked on the impact of hearing the Beatles in that oppressive regime, "The kids lost their interest in all Soviet unshakable dogmas and ideals, and stopped thinking of an English-speaking person as an enemy" (BBC News).
Music Video
Art Of Anime
"When Did Mimi Get So Cute?"
http://sansuthecat.blogspot.com/2016/05/when-did-mimi-get-so-cute.html
"Evangelion, Or Something Like It."
http://sansuthecat.blogspot.com/2015/10/evangelion-or-something-like-it.html
"Yuri Vincit Omnia."
http://sansuthecat.blogspot.com/2015/03/puella-magi-madoka-magica-yuri-vincit.html
"FLCL: Insanity Defined."
http://sansuthecat.blogspot.com/2014/10/flcl-insanity-defined.html
"Barefoot In The Park."
https://sansuthecat.blogspot.com/2017/01/barefoot-in-park.html
"Sakura No Aware."
https://sansuthecat.blogspot.com/2017/06/sakura-no-aware.html
"The Celebrity And The Sybil."
https://sansuthecat.blogspot.com/2017/12/the-celebrity-and-sybil.html
Assault Android Cactus+ Blasts Off Today On Nintendo Switch
Assault Android Cactus+ debuts on Nintendo Switch with all-new features: Campaign+, new character costumes and aim assist options. Campaign+ reconstructs the original campaign with new enemy waves, more dynamic elements, and amped-up boss fights, all at 60 frames-per-second. Unlock a new costume for each of the nine androids while testing their unique loadouts to see what's most effective across 25 levels.
While Campaign+ and its new leaderboards are enticing additions for those familiar with the game, anyone can enjoy Cactus+'s frantic firefights with the addition of Aim Assist options. To let players get the most out of the local co-op experience, the game can be played with dual Joy-Con, Pro Controller and even single Joy-Con in any combination.
Recruit up to three friends and start shooting!
Lead Junior Constable Cactus and her Android friends as they respond to a distress call and finds a derelict space freighter under attack by its own robot workers. Keep the androids' batteries charged by embracing aggressive play and blasting hordes in frantic, 60 frames-per-second firefights.
Keep the entertainment going with Daily Drive, which offers one shot a day at setting a worldwide high score in a newly-generated level. Players craving further challenge will find it in Boss Rush and Infinity Drive. Earn credits to enable amusing EX options including first-person mode, visual filters, and the newly re-balanced MEGA Weapons. A new Movie Gallery joins unlockables like Developer Commentary, Jukebox, and Sound Test, making revisiting favorite moments easier than ever.
"Assault Android Cactus+ has something for everyone," says Tim Dawson, director, Witch Beam. "We hope the fans that have supported us over the years will enjoy Campaign+, and we look forward to first-timers feeling confident with aim assist."
Assault Android Cactus+ is available on Nintendo Switch for $19.99. The game supports English, French, Italian, German, Spanish and Japanese languages.
Thursday, March 28, 2019
Max Payne 3 Free Download For PC
Max Payne 3 Free Download
Max Payne 3 Free Download PC Game setup in single link for windows. Max Payne 3 is a third person shooter video game with interesting story.
Max Payne 3 Overview
This game is published by Rockstar Games. Max Payne 3 has stunning sound and graphic effects. Max Payne 3 is the third game in the Max Payne series. Max Payne is the main character of this game. He was detector at times. Somebody has killed his wife and daughter badly. Max Payne is in the mission to take revenge from that person. Enemies of Max Payne are very powerful so he has to play with a plan to take revenge from them.
Run and gun style of Max Payne 3 PC game is same as other previous Max Payne 1 game. In this game Last Stand mechanic is introduced. and with the help of this player can play even after loosing all his health. Player can shoot at 360 degrees that is an amazing thing in that game. Animation of this game is very high class. Killing and shooting in this game has got a sense of reality.
The locations of this game are very amazing. This game has also got an online multiplayer mode and with the help of this mode 16 players will be able to play that game.
Max Payne 3 Features
- A third person shooter video game.
- Published by Rockstar Games.
- Stunning sound and graphic effects.
- Third game in the Max Payne series.
- Max Payne is the main character of this game.
- Mission of taking revenge.
- Last Stand mechanic is introduced.
- Player can shoot at 360 degrees
- Animation of this game is very high class.
- Killing and shooting in this game has got a sense of reality.
- The locations of this game are very amazing.
- 16 players can play online in multiplayer mode.
Max Payne 3 System Requirements
Minimum system requirements for this game are given below.
- Operating System: Windows 7, Windows Vista, Windows 8 and 8.1
- CPU: Dual Core 2.4 GHz
- RAM: 2 GB
- Hard Disk: 35 GB
Max Payne 3 Free Download
Click below download to start Max Payne 3 Free Download. It is full and complete game. Just download and start playing it. We have provided direct link full setup of game.
Explore Simple Game Algorithms With Color Walk: Part 7
We're continuing to explore different game algorithms using the simple game Color Walk. In the last post we took a deep dive into other heuristics that could be used instead of the obvious maximize-the-number-of-blocks-removed approach and found that the obvious choice is actually hard to beat. After looking at various heuristics, it's time we fill in some gaps in our exploration of algorithms by looking at a couple of fundamental graph algorithms: breadth-first search (BFS) and depth-first search (DFS). These algorithms are the two basic ways to search for something in a graph of nodes (or vertices) connected by edges, and a graph is exactly what we have when we draw out all possible move choices with each node representing a move and edges connecting sequential moves. We'll focus on BFS for this post.
Before we start looking into BFS, we should make some small changes to the code to improve its performance. The implementation of the greedy look-ahead (GLA) algorithm that we've implemented a bug that is not affecting correctness, but it is slowing the search down considerably. Here is the code in its sub-optimal state:
Another improvement that can easily be made is to not search for blocks for a move that we already made on the preceding move, i.e. don't pick the same move twice in a row. The previously discussed if condition would end the search on the duplicate move when it's fixed, but only after searching for matches and finding no additional matches. We can skip the superfluous search by detecting when we're repeating the previous move. The fixes to the code involve passing the previous move and previous matches into greedyLookAheadN() so that they can be compared with the current move and matches, respectively:
BFS is one of two fundamental ways to search a graph. We could be searching for a specific node value, searching for a maximum or minimum, or searching for something else based on node values. In our case, we're searching for the end-of-game condition where the board is cleared of blocks. The BFS algorithm is conceptually very simple: search the current node, then search that node's child nodes, then search those children's child nodes, and so on until we find what we're looking for.
If we think of the graph as a tree with the current node at the root, then we're searching all nodes in the tree in order from those closest to the root to progressively deeper levels of the tree. To get a better visual picture of the process, let's assume we've arranged the move choices in Color Walk in the form of a tree, and we have three colors to pick from instead of five. Each move would consist of a choice between two colors, since we would never pick the same color twice in a row. A tree depicting three moves that were searched with BFS would look like this:
The move choices are blue, red, and yellow, and we just picked blue as our last move, so it is the root of the tree. Our choices for the next move are then red or yellow, and each level of the tree doubles in size compared to the level before it. The numbers in each node show the order that the nodes will be searched with BFS. The nice thing about this algorithm is that if we're searching for something specific, as we are for the end-of-game condition, then we know as soon as we find the first node with that condition that we can stop searching. That node resides at the level with the least number of moves to reach that state. We know this fact because we've searched each level of the tree in order from the level of the first move to the level of the first move found that completes the game. That means we've found an optimal solution.
Not everything is so nice, though. In reality this tree will be enormous. It grows exponentially, and we are dealing with a base of 4 instead of 2. If we assume the average game will have at least 30 moves, that means we'll have to search 430 = 260 nodes before finding the shortest sequence of moves to end the game. Even if we could represent each node with a single byte of data (which we most certainly can't), the tree would need over an exabyte of storage to hold it. If instead we generated the nodes we needed to search on the fly, and we assume it took a microsecond to generate and check each node (highly optimistic, especially for JavaScript), it would take 36,560 years to search the tree. Assuming the minimum number of moves is less doesn't help much. Reducing to 25 moves still results in almost 36 years of searching. None of this is feasible. The tree is just too big.
We need a way to cut this tree down to size, and to do it, we can use our old friend greedy. The idea is that the GLA algorithm works pretty well, and it's relatively fast. We can run with it for some number of moves at the beginning of the game to take some reasonably optimal path into the move tree. Then switch to the BFS algorithm to find the optimal sequence of moves from that point forward.
The issue that we need to resolve with this approach is when do we switch to the BFS algorithm? We don't want to switch too early, or it will still take a crazy long time to find the optimal path. We don't want to switch too late, or it will be practically useless to have switched algorithms at all. It's also difficult to tell when we're getting close to the end, at least with the information available at the time we're trying to decide. The best number of moves we've seen so far has varied from 25 to 40 over 100 random boards, so if we picked a fixed move number of, say, 20 to switch over to BFS, we could still be searching on the order of 420 nodes on some boards before finding the optimal path.
If instead we tried looking at how many blocks are left and created a threshold for when to switch, we would run into another problem. Sometimes one or more colors of blocks are not chosen for a long time, creating a large number of blocks of the same color that stay on the board until close to the end, when they are wiped out with a single move. At that point we would suddenly be too close to the end of the game for BFS to be useful. This behavior doesn't happen all of the time, either, compounding the problem of choosing an adequate threshold.
What we need is a way to try for BFS, but to bail on it if it's taking too long. We can start with GLA, and proceed to a safe number of moves, like 18. Then we can try using BFS for some reasonable number of nodes, and if we find the end-of-game condition, great. If we don't find it, then we'll run GLA for another move and try BFS again. The combined execution of both algorithms will be slower than running GLA by itself, but hopefully we'll find a more optimal sequence of moves. Now that we have a plan of action, we can start implementing the BFS algorithm. We'll start by adding it to the list of algorithms and adding its case to the switch statement of algorithms:
The if condition to use GLA is straightforward, and exactly like it was described: if there have been less than 18 moves or BFS fails, then run GLA for another move. The details of bfs() get more complex, so let's take a look at what a basic BFS algorithm looks like first and pick it apart:
The use of a queue keeps the nodes in order as BFS searches through the move tree. The possible moves after the current move are added to the queue first, and then each of those moves are taken off the queue in order and inspected. If the end condition isn't found, each of those moves' child moves are added to the queue, in order. This process ends up with each level of moves being added to the queue in succession until either the search runs into the end condition or the entire tree has been searched.
The BFS algorithm as it stands has some problems, though. First, it doesn't do anything to limit the length of the search, so if we switch to BFS on the 18th move, many boards will end up searching effectively forever. We need to limit the search somehow. Second, we can do better than simply returning true when we find the end condition. Since we know what moves produced the ending, we can simply do those moves right away and be done. Last, we need some way for each node to keep track of which moves led to that particular node. It's clear from the code that a node will have information about which control was used for its move and its depth in the tree, but not a full record of the moves taken to get to that node. We need that information attached to the nodes, and we can do it by maintaining an array of move numbers, called markers, that we'll discuss in a moment. First, here is what the augmented bfs() code looks like:
A threshold of 16384 allows for about 7 levels of moves to be searched. The nice thing about limiting the search in this way is that if we decide to trim out some move choices before adding them to the queue, the algorithm will automatically search deeper into the tree in the same amount of search time. Limiting the search by level would require a change to the threshold if we wanted to search deeper, and it would have to search the entire next level. Remember that level size grows exponentially. By limiting the queue size, we could decide to partially search the last search level if it was too big. Alternatively, we could limit the search by run time and get the added benefit that if we could improve the checkGameBoard() performance, the algorithm would automatically search deeper as well.
The second addition to the code, doMarkedMoves() is pretty self-explanatory at this level. We'll get into the details if it after describing the markers array for keeping track of moves for each node.
The markers array is basically the marked property from each Block object consolidated into one array for easy, compact copying to each node in the move tree. (See part 4 for how the marked property works.) We could copy the entire blocks array for each node, but the majority of the data in a block never changes during a search. Only the marked property would change, so we can pull it out and make it its own markers array that mirrors the blocks array. To make this change, we can add markers at the top level:
Now that we know how to add and remove nodes from the queue, let's look at how we can use the markers array to find the sequence of moves taken to clear the board when the end-of-game condition is found:
At this point the code works, but there's a problem. The first couple of iterations seem to run okay, about ten seconds each on my machine, but each iteration quickly starts taking longer. It isn't too many iterations in before each one is taking upwards of five minutes to complete. Not long after that, the program crashes with an out-of-memory error. We seem to have a memory leak, and it obviously has something to do with creating tens of thousands of node objects. Somehow the garbage collector is not reclaiming all of that memory.
After doing some research and much pondering, I think the problem stems from having a pointer to an object outside of a scope (the markers array) and more pointers to the same object at certain times in multiple levels of nested scope (in bfs() and Queue()). The GC can't tell when nodes have no more pointers to them, so their memory is not freed, creating the memory leak. The way to fix this leak is to explicitly set the pointers to null when they are no longer used:
The completed run of 100 iterations, using a GLA depth of 5, came up with these results:
The results look promising, but let's compare it to a selection of the other algorithms:
The BFS algorithm just barely squeaks out a victory over the GLA-5 algorithm on average and on the maximum. It's one move longer than GLA-5 on the minimum. This slight win came at a cost of significantly reduced speed, however, as the BFS algorithm runs considerably slower than GLA-5. It is, after all, running GLA-5 for most of each iteration, and only finishing off with BFS to find the end-of-game condition.
Even if we didn't make significant improvements with the BFS algorithm, we did learn a number of things. We learned how to implement a BFS algorithm using a queue, and that the basic idea is fairly simple. Theoretically, BFS will give an optimal solution to the problem of finding a minimum sequence of moves for Color Walk, but the exponential growth of the move tree presents an insurmountable problem for a pure BFS algorithm in practice. To make BFS tractable, we need to start with a good, fast algorithm like GLA to cut down the tree size before switching to BFS. Finally, using BFS to augment GLA can make incremental improvements to the performance, but it's not a slam dunk because of significant costs in run time. Next time we'll explore the other fundamental graph search algorithm, depth-first search, and see what problems we need to overcome there.
Article Index
Part 1: Introduction & Setup
Part 2: Tooling & Round-Robin
Part 3: Random & Skipping
Part 4: The Greedy Algorithm
Part 5: Greedy Look Ahead
Part 6: Heuristics & Hybrids
Part 7: Breadth-First Search
Part 8: Depth-First Search
Part 9: Dijkstra's Algorithm
Part 10: Dijkstra's Hybrids
Part 11: Priority Queues
Part 12: Summary
Before We Begin, A Bug Fix
Before we start looking into BFS, we should make some small changes to the code to improve its performance. The implementation of the greedy look-ahead (GLA) algorithm that we've implemented a bug that is not affecting correctness, but it is slowing the search down considerably. Here is the code in its sub-optimal state:
this.greedyLookAhead = function() {
var max_control = _.max(controls, function(control) {
if (control.checkGameBoard(1, that.metric) === 0) {
return 0;
}
return greedyLookAheadN(2);
});
this.index = max_control.index;
}
function greedyLookAheadN(move) {
return _.max(_.map(controls, function(control) {
var matches = control.checkGameBoard(move, that.metric);
if (matches === 0 || move >= max_moves) {
return matches;
}
return greedyLookAheadN(move + 1);
}));
}
The problem is hiding in the if conditional in greedyLookAheadN(). The idea with this if statement is that if we didn't find any matching blocks on this move or we've reached the desired search depth, then we should end the search of this branch of moves. However, matches is not the number of matches on the current move, but of all matched blocks on all moves up to this search depth. It will only potentially be zero on the first call to greedyLookAheadN(), but not any subsequent recursive calls! That behavior makes the look-ahead search perform slowly at the end of the game because it's trying to search through moves beyond when the board is already cleared. That's how I noticed the problem.Another improvement that can easily be made is to not search for blocks for a move that we already made on the preceding move, i.e. don't pick the same move twice in a row. The previously discussed if condition would end the search on the duplicate move when it's fixed, but only after searching for matches and finding no additional matches. We can skip the superfluous search by detecting when we're repeating the previous move. The fixes to the code involve passing the previous move and previous matches into greedyLookAheadN() so that they can be compared with the current move and matches, respectively:
this.greedyLookAhead = function() {
var max_control = _.max(controls, function(control) {
var matches = control.checkGameBoard(1, that.metric);
if (matches === 0) {
return 0;
}
return greedyLookAheadN(2, control, matches);
});
this.index = max_control.index;
}
function greedyLookAheadN(move, prev_control, prev_matches) {
return _.max(_.map(controls, function(control) {
if (control === prev_control) {
return 0;
}
var matches = control.checkGameBoard(move, that.metric);
if (matches === prev_matches || move >= max_moves) {
return matches;
}
return greedyLookAheadN(move + 1, control, matches);
}));
}
With these changes, the algorithm correctly cuts off the search of a particular move branch when no additional matches are found, or when the move is the same as the previous move. The speed-up is more than a factor of 3, so it was well worth the trouble. Even though we're moving on from the greedy algorithm, it was worth finding and correcting this bug because we'll be using similar logic to determine where to search in the next couple algorithms. We want to get it right so the searching will be as fast as possible. Now let's start digging into the details of BFS.Theoretical BFS
BFS is one of two fundamental ways to search a graph. We could be searching for a specific node value, searching for a maximum or minimum, or searching for something else based on node values. In our case, we're searching for the end-of-game condition where the board is cleared of blocks. The BFS algorithm is conceptually very simple: search the current node, then search that node's child nodes, then search those children's child nodes, and so on until we find what we're looking for.
If we think of the graph as a tree with the current node at the root, then we're searching all nodes in the tree in order from those closest to the root to progressively deeper levels of the tree. To get a better visual picture of the process, let's assume we've arranged the move choices in Color Walk in the form of a tree, and we have three colors to pick from instead of five. Each move would consist of a choice between two colors, since we would never pick the same color twice in a row. A tree depicting three moves that were searched with BFS would look like this:
The move choices are blue, red, and yellow, and we just picked blue as our last move, so it is the root of the tree. Our choices for the next move are then red or yellow, and each level of the tree doubles in size compared to the level before it. The numbers in each node show the order that the nodes will be searched with BFS. The nice thing about this algorithm is that if we're searching for something specific, as we are for the end-of-game condition, then we know as soon as we find the first node with that condition that we can stop searching. That node resides at the level with the least number of moves to reach that state. We know this fact because we've searched each level of the tree in order from the level of the first move to the level of the first move found that completes the game. That means we've found an optimal solution.
Not everything is so nice, though. In reality this tree will be enormous. It grows exponentially, and we are dealing with a base of 4 instead of 2. If we assume the average game will have at least 30 moves, that means we'll have to search 430 = 260 nodes before finding the shortest sequence of moves to end the game. Even if we could represent each node with a single byte of data (which we most certainly can't), the tree would need over an exabyte of storage to hold it. If instead we generated the nodes we needed to search on the fly, and we assume it took a microsecond to generate and check each node (highly optimistic, especially for JavaScript), it would take 36,560 years to search the tree. Assuming the minimum number of moves is less doesn't help much. Reducing to 25 moves still results in almost 36 years of searching. None of this is feasible. The tree is just too big.
We need a way to cut this tree down to size, and to do it, we can use our old friend greedy. The idea is that the GLA algorithm works pretty well, and it's relatively fast. We can run with it for some number of moves at the beginning of the game to take some reasonably optimal path into the move tree. Then switch to the BFS algorithm to find the optimal sequence of moves from that point forward.
The issue that we need to resolve with this approach is when do we switch to the BFS algorithm? We don't want to switch too early, or it will still take a crazy long time to find the optimal path. We don't want to switch too late, or it will be practically useless to have switched algorithms at all. It's also difficult to tell when we're getting close to the end, at least with the information available at the time we're trying to decide. The best number of moves we've seen so far has varied from 25 to 40 over 100 random boards, so if we picked a fixed move number of, say, 20 to switch over to BFS, we could still be searching on the order of 420 nodes on some boards before finding the optimal path.
If instead we tried looking at how many blocks are left and created a threshold for when to switch, we would run into another problem. Sometimes one or more colors of blocks are not chosen for a long time, creating a large number of blocks of the same color that stay on the board until close to the end, when they are wiped out with a single move. At that point we would suddenly be too close to the end of the game for BFS to be useful. This behavior doesn't happen all of the time, either, compounding the problem of choosing an adequate threshold.
What we need is a way to try for BFS, but to bail on it if it's taking too long. We can start with GLA, and proceed to a safe number of moves, like 18. Then we can try using BFS for some reasonable number of nodes, and if we find the end-of-game condition, great. If we don't find it, then we'll run GLA for another move and try BFS again. The combined execution of both algorithms will be slower than running GLA by itself, but hopefully we'll find a more optimal sequence of moves. Now that we have a plan of action, we can start implementing the BFS algorithm. We'll start by adding it to the list of algorithms and adding its case to the switch statement of algorithms:
function Solver() {
// ...
this.init = function() {
// ...
$('#solver_type').change(function () {
switch (this.value) { case 'bfs':
that.solverType = that.bfsWithGla;
that.metric = areaCount;
break;
default:
that.solverType = that.roundRobin;
break;
}
// ...
});
}
// ...
this.bfsWithGla = function() {
if (moves < 18 || bfs() === false) this.greedyLookAhead();
}
}
The metric that we'll use is the one for GLA, and it'll be the normal area-maximizing heuristic. We'll need a different one for BFS, and it will be the metric that checks if we've reached the end-of-game condition. We can pass it into the Control.checkGameBoard() function directly from within bfs(), which allows us to set the code up like it is above.The if condition to use GLA is straightforward, and exactly like it was described: if there have been less than 18 moves or BFS fails, then run GLA for another move. The details of bfs() get more complex, so let's take a look at what a basic BFS algorithm looks like first and pick it apart:
function bfs() {
var nodes = addNodes(new Queue(), 1, null);
while (nodes.getLength() > 0) {
var node = nodes.dequeue();
if (node.control.checkGameBoard(node.depth, endOfGame)) {
return true;
}
nodes = addNodes(nodes, node.depth + 1, node.control);
}
return false;
}
Here are the fundamental pieces of BFS, but this code is not all that we will need to get things working. It's the essence of the BFS algorithm, starting with creating a queue to hold the pending nodes that will be checked as we search through the move tree. (The queue library used here is the simple Queue.js.) The tail node of the queue will be taken off and checked, and more nodes will be added to the queue while checking the dequeued node for the search condition. The while loop does these steps as just described. It dequeues a node from the queue, checks if the move associated with that node causes an end-of-game condition, and adds the current node's children to the queue if the end isn't found. If the end condition is found, the search is cut off early by returning true from bfs(), notifying the calling function that the end was found. If the queue ever gets completely empty, we know we've searched the entire move tree, and we can return false to signal that fact.The use of a queue keeps the nodes in order as BFS searches through the move tree. The possible moves after the current move are added to the queue first, and then each of those moves are taken off the queue in order and inspected. If the end condition isn't found, each of those moves' child moves are added to the queue, in order. This process ends up with each level of moves being added to the queue in succession until either the search runs into the end condition or the entire tree has been searched.
Practical BFS
The BFS algorithm as it stands has some problems, though. First, it doesn't do anything to limit the length of the search, so if we switch to BFS on the 18th move, many boards will end up searching effectively forever. We need to limit the search somehow. Second, we can do better than simply returning true when we find the end condition. Since we know what moves produced the ending, we can simply do those moves right away and be done. Last, we need some way for each node to keep track of which moves led to that particular node. It's clear from the code that a node will have information about which control was used for its move and its depth in the tree, but not a full record of the moves taken to get to that node. We need that information attached to the nodes, and we can do it by maintaining an array of move numbers, called markers, that we'll discuss in a moment. First, here is what the augmented bfs() code looks like:
function bfs() {
var nodes = addNodes(new Queue(), 1, null);
var still_adding_nodes = true;
while (nodes.getLength() > 0) {
var node = nodes.dequeue();
markers = node.markers;
if (node.control.checkGameBoard(node.depth, endOfGame)) {
doMarkedMoves();
return true;
}
if (still_adding_nodes) {
nodes = addNodes(nodes, node.depth + 1, node.control);
still_adding_nodes = nodes.getLength() < 16384;
}
}
return false;
}
We'll tackle the additions in order. The search is easily limited by limiting the size of the queue. Every time a node is searched unsuccessfully, up to four more nodes will be added to the queue. If we stop adding nodes after the queue size hits a threshold, then the algorithm will naturally run down and stop as the rest of the nodes in the queue are searched with no new additions. This behavior is achieved through the still_adding_nodes flag and if condition. Once the queue reaches a size of 16384 or more, still_adding_nodes will be set to false and no more nodes will be added.A threshold of 16384 allows for about 7 levels of moves to be searched. The nice thing about limiting the search in this way is that if we decide to trim out some move choices before adding them to the queue, the algorithm will automatically search deeper into the tree in the same amount of search time. Limiting the search by level would require a change to the threshold if we wanted to search deeper, and it would have to search the entire next level. Remember that level size grows exponentially. By limiting the queue size, we could decide to partially search the last search level if it was too big. Alternatively, we could limit the search by run time and get the added benefit that if we could improve the checkGameBoard() performance, the algorithm would automatically search deeper as well.
The second addition to the code, doMarkedMoves() is pretty self-explanatory at this level. We'll get into the details if it after describing the markers array for keeping track of moves for each node.
The markers array is basically the marked property from each Block object consolidated into one array for easy, compact copying to each node in the move tree. (See part 4 for how the marked property works.) We could copy the entire blocks array for each node, but the majority of the data in a block never changes during a search. Only the marked property would change, so we can pull it out and make it its own markers array that mirrors the blocks array. To make this change, we can add markers at the top level:
function colorWalk() {
var blocks = [];
var clusters = [];
var markers = [];
// ...
Then we need to change every instance of <block_reference>.marked to markers[<block_reference>.position] throughout the code where <block_reference> is any reference to a Block object. With that change made, we can make a copy of the markers array when we add new nodes to the queue, preserving the move sequence to get to that node within the copy of the array. Then we can restore the markers array with the one in the node that gets dequeued each time through the while loop. The dequeue action is shown in the bfs() function above, and the enqueue action is shown in the addNodes() function: function addNodes(nodes, depth, prev_control) {
var markers_dup = markers.slice();
_.each(controls, function (control) {
if (control !== prev_control) {
nodes.enqueue({markers: markers_dup, depth: depth, control: control});
}
});
return nodes;
}
You'll notice that we don't make a copy for every node. One copy is enough for all child nodes as a group because the checkGameBoard() function will handle resetting the markers array for each child node, as long as they're siblings. It doesn't have enough information to do the same thing for child nodes that are cousins (where the child nodes' parents are siblings or related even further up the tree). We also pass in the control associated with the parent node so that we don't needlessly add a node for the same control that we just used to get here in the first place.Now that we know how to add and remove nodes from the queue, let's look at how we can use the markers array to find the sequence of moves taken to clear the board when the end-of-game condition is found:
function doMarkedMoves() {
var move_sequence = markers.slice();
var move = 1;
var i = _.indexOf(move_sequence, move);
while (i > 0) {
var control = _.findWhere(controls, {color: blocks[i].color});
control.updateGameBoard();
move += 1;
i = _.indexOf(move_sequence, move);
}
}
First, we need to make a copy of the markers array because each time updateGameBoard() is called, it's going to change the markers array. Next, we find the index of a block marked with the move number of 1. Any block will do. Then, we grab the control that matches the color of the block found and use that control to update the game board. Finally, we increment to the next move and find its block's index. This process repeats until we can't find the next move in the markers array, and by then the board should be cleared.Performant BFS
At this point the code works, but there's a problem. The first couple of iterations seem to run okay, about ten seconds each on my machine, but each iteration quickly starts taking longer. It isn't too many iterations in before each one is taking upwards of five minutes to complete. Not long after that, the program crashes with an out-of-memory error. We seem to have a memory leak, and it obviously has something to do with creating tens of thousands of node objects. Somehow the garbage collector is not reclaiming all of that memory.
After doing some research and much pondering, I think the problem stems from having a pointer to an object outside of a scope (the markers array) and more pointers to the same object at certain times in multiple levels of nested scope (in bfs() and Queue()). The GC can't tell when nodes have no more pointers to them, so their memory is not freed, creating the memory leak. The way to fix this leak is to explicitly set the pointers to null when they are no longer used:
function bfs() {
var nodes = addNodes(new Queue(), 1, null);
var still_adding_nodes = true;
while (nodes.getLength() > 0) {
var node = nodes.dequeue();
markers = null;
markers = node.markers;
if (node.control.checkGameBoard(node.depth, endOfGame)) {
doMarkedMoves();
return true;
}
if (still_adding_nodes) {
nodes = addNodes(nodes, node.depth + 1, node.control);
still_adding_nodes = nodes.getLength() < 16384;
}
node.markers = null;
}
return false;
}
Here both markers and node.markers are set to null explicitly, and this remedy seems to have fixed the leak at least enough to get through a batch run of 100 iterations of the algorithm. There still seems to be an issue with the GC because iterations regularly take 30 seconds or more, but it was good enough to complete a run. Maybe an implementation of Queue that was more specific to this problem—one that created the correctly sized array and only set the values of each node to reuse nodes instead of creating and deleting them—would be more memory efficient. It would be an interesting problem to explore more fully and learn from, but we need to move on and see how this BFS algorithm performs.The completed run of 100 iterations, using a GLA depth of 5, came up with these results:
The results look promising, but let's compare it to a selection of the other algorithms:
Algorithm | Min | Mean | Max | Stdev |
---|---|---|---|---|
RR with Skipping | 37 | 46.9 | 59 | 4.1 |
Random with Skipping | 43 | 53.1 | 64 | 4.5 |
Greedy | 31 | 39.8 | 48 | 3.5 |
Greedy Look-Ahead-2 | 28 | 37.0 | 45 | 3.1 |
Greedy Look-Ahead-5 | 25 | 33.1 | 41 | 2.8 |
Max Perimeter | 29 | 37.4 | 44 | 3.2 |
Max Perimeter Look-Ahead-2 | 27 | 35.0 | 44 | 2.8 |
Perimeter-Area Hybrid | 31 | 39.0 | 49 | 3.8 |
Deep-Path | 51 | 74.8 | 104 | 9.4 |
Path-Area Hybrid | 35 | 44.2 | 54 | 3.5 |
Path-Area Hybrid Look-Ahead-4 | 32 | 38.7 | 45 | 2.7 |
BFS with Greedy Look-Ahead-5 | 26 | 32.7 | 40 | 2.8 |
The BFS algorithm just barely squeaks out a victory over the GLA-5 algorithm on average and on the maximum. It's one move longer than GLA-5 on the minimum. This slight win came at a cost of significantly reduced speed, however, as the BFS algorithm runs considerably slower than GLA-5. It is, after all, running GLA-5 for most of each iteration, and only finishing off with BFS to find the end-of-game condition.
Even if we didn't make significant improvements with the BFS algorithm, we did learn a number of things. We learned how to implement a BFS algorithm using a queue, and that the basic idea is fairly simple. Theoretically, BFS will give an optimal solution to the problem of finding a minimum sequence of moves for Color Walk, but the exponential growth of the move tree presents an insurmountable problem for a pure BFS algorithm in practice. To make BFS tractable, we need to start with a good, fast algorithm like GLA to cut down the tree size before switching to BFS. Finally, using BFS to augment GLA can make incremental improvements to the performance, but it's not a slam dunk because of significant costs in run time. Next time we'll explore the other fundamental graph search algorithm, depth-first search, and see what problems we need to overcome there.
Article Index
Part 1: Introduction & Setup
Part 2: Tooling & Round-Robin
Part 3: Random & Skipping
Part 4: The Greedy Algorithm
Part 5: Greedy Look Ahead
Part 6: Heuristics & Hybrids
Part 7: Breadth-First Search
Part 8: Depth-First Search
Part 9: Dijkstra's Algorithm
Part 10: Dijkstra's Hybrids
Part 11: Priority Queues
Part 12: Summary
Subscribe to:
Posts (Atom)